//=====================================================================

        /// <summary>
        /// Search for members that match the search conditions
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void btnFind_Click(object sender, EventArgs e)
        {
            ApiEntryType entryType;
            ApiVisibility visibility;
            ListViewItem lvi;
            string id, nodeText, subgroup;
            int pos, ignoreCase = Convert.ToInt32(!chkCaseSensitive.Checked),
                fullyQualified = Convert.ToInt32(chkFullyQualified.Checked);
            List<NodeInfo> nodeList;
            NodeInfo newNode;
            XPathNavigator subsubgroup;

            epErrors.Clear();

            if(txtSearchText.Text.Trim().Length == 0)
            {
                epErrors.SetError(txtSearchText,
                    "A search expression is required");
                return;

            }

            try
            {
                Regex reSearch = new Regex(txtSearchText.Text);
            }
            catch(ArgumentException ex)
            {
                epErrors.SetError(txtSearchText, "The search regular " +
                    "expression is not valid: " + ex.Message);
                return;
            }

            try
            {
                this.Cursor = Cursors.WaitCursor;
                btnGoto.Enabled = btnInclude.Enabled = btnExclude.Enabled = false;

                // Use the custom XPath function matches-regex to perform
                // a regular expression search for matching nodes.  The
                // custom XPath function resolve-name is used to convert the
                // API names to their display format for the search.
                XPathFunctionContext context = new XPathFunctionContext();
                XPathExpression expr = navigator.Compile(String.Format(
                    CultureInfo.InvariantCulture, "api[matches-regex(" +
                    "resolve-name(node(), boolean({0})), '{1}', boolean({2}))]",
                    fullyQualified, txtSearchText.Text, ignoreCase));

                // The first search uses the documented APIs
                expr.SetContext(context);
                lvSearchResults.Items.Clear();
                nodeList = new List<NodeInfo>();

                // The results are stored in the list view with each list
                // item's Tag property referencing the matching node.
                foreach(XPathNavigator nav in navigator.Select(expr))
                {
                    id = nav.GetAttribute("id", String.Empty);

                    if(id[0] == 'N')
                    {
                        entryType = ApiEntryType.Namespace;
                        visibility = ApiVisibility.Public;
                        nodeText = id.Substring(2);
                    }
                    else
                    {
                        subsubgroup = nav.SelectSingleNode("apidata/@subsubgroup");

                        if(subsubgroup != null)
                            subgroup = subsubgroup.Value;
                        else
                            subgroup = nav.SelectSingleNode("apidata/@subgroup").Value;

                        entryType = NodeInfo.EntryTypeFromId(id[0], subgroup);
                        visibility = NodeInfo.DetermineVisibility(id[0],
                            ((IHasXmlNode)nav).GetNode());

                        pos = id.IndexOf('(');

                        if(pos != -1)
                            id = id.Substring(0, pos);

                        pos = id.LastIndexOf('.');

                        if(pos != -1)
                            nodeText = id.Substring(pos + 1);
                        else
                            nodeText = id.Substring(2);
                    }

                    // Only include the wanted items
                    if(((CheckBox)pnlOptions.Controls[
                      (int)entryType + 1]).Checked &&
                      ((CheckBox)pnlOptions.Controls[
                      (int)visibility + 14]).Checked)
                    {
                        newNode = new NodeInfo(nodeText, id.Substring(2));
                        newNode.ApiNode = ((IHasXmlNode)nav).GetNode();
                        nodeList.Add(newNode);
                    }
                }

                // Search inherited APIs as well.  Namespaces first...
                expr = navigator.Compile(String.Format(
                    CultureInfo.InvariantCulture,
                    "api/elements/element/containers/namespace[matches-regex(" +
                    "string(@api), '{0}', boolean({1}))]",
                    txtSearchText.Text, ignoreCase));

                expr.SetContext(context);

                foreach(XPathNavigator nav in navigator.Select(expr))
                {
                    id = nav.GetAttribute("api", String.Empty).Substring(2);

                    // Only include the wanted items
                    if(((CheckBox)pnlOptions.Controls[
                      (int)ApiEntryType.Namespace + 1]).Checked)
                    {
                        newNode = new NodeInfo(id, id);
                        newNode.ApiNode = ((IHasXmlNode)nav).GetNode();
                        nodeList.Add(newNode);
                    }
                }

                // ... then types ...
                expr = navigator.Compile(String.Format(
                    CultureInfo.InvariantCulture,
                    "api/elements/element/containers/type[matches-regex(" +
                    "resolve-name(node(), boolean({0})), '{1}', boolean({2}))]",
                    fullyQualified, txtSearchText.Text, ignoreCase));

                expr.SetContext(context);

                foreach(XPathNavigator nav in navigator.Select(expr))
                {
                    id = nav.GetAttribute("api", String.Empty).Substring(2);
                    pos = id.LastIndexOf('.');

                    if(pos != -1)
                        nodeText = id.Substring(pos + 1);
                    else
                        nodeText = id;

                    // Only include the wanted items.  Since we can't tell the
                    // actual API type, we'll assume Class for these.
                    if(((CheckBox)pnlOptions.Controls[
                        (int)ApiEntryType.Class + 1]).Checked)
                    {
                        newNode = new NodeInfo(nodeText, id);
                        newNode.ApiNode = ((IHasXmlNode)nav).GetNode();
                        nodeList.Add(newNode);
                    }
                }

                // ... and then members.
                expr = navigator.Compile(String.Format(
                    CultureInfo.InvariantCulture,
                    "api/elements/element[matches-regex(resolve-name(" +
                    "node(), boolean({0})), '{1}', boolean({2})) and containers]",
                    fullyQualified, txtSearchText.Text, ignoreCase));

                expr.SetContext(context);

                foreach(XPathNavigator nav in navigator.Select(expr))
                    if(nav.HasChildren)
                    {
                        id = nav.GetAttribute("api", String.Empty);

                        if(id[0] == 'N')
                        {
                            entryType = ApiEntryType.Namespace;
                            visibility = ApiVisibility.Public;
                            nodeText = id;
                        }
                        else
                        {
                            subsubgroup = nav.SelectSingleNode("apidata/@subsubgroup");

                            if(subsubgroup != null)
                                subgroup = subsubgroup.Value;
                            else
                                subgroup = nav.SelectSingleNode("apidata/@subgroup").Value;

                            entryType = NodeInfo.EntryTypeFromId(id[0], subgroup);
                            visibility = NodeInfo.DetermineVisibility(id[0],
                                ((IHasXmlNode)nav).GetNode());

                            pos = id.IndexOf('(');

                            if(pos != -1)
                                id = id.Substring(0, pos);

                            pos = id.LastIndexOf('.');

                            if(pos != -1)
                                nodeText = id.Substring(pos + 1);
                            else
                                nodeText = id;
                        }

                        // Only include the wanted items
                        if(((CheckBox)pnlOptions.Controls[
                          (int)entryType + 1]).Checked &&
                          ((CheckBox)pnlOptions.Controls[
                          (int)visibility + 14]).Checked)
                        {
                            newNode = new NodeInfo(nodeText, id.Substring(2));
                            newNode.ApiNode = ((IHasXmlNode)nav).GetNode();
                            nodeList.Add(newNode);
                        }
                    }

                if(nodeList.Count == 0)
                    lvSearchResults.Items.Add(new ListViewItem(
                        "Nothing found", 0));
                else
                {
                    nodeList.Sort(
                    delegate(NodeInfo x, NodeInfo y)
                    {
                        int result = (int)x.EntryType - (int)y.EntryType;

                        if(result == 0)
                            result = String.Compare(x.Id, y.Id,
                                StringComparison.CurrentCulture);

                        return result;
                    });

                    foreach(NodeInfo ni in nodeList)
                        if(!lvSearchResults.Items.ContainsKey(ni.Id))
                        {
                            lvi = new ListViewItem(ni.NodeText,
                                (int)ni.EntryType + ((int)ni.Visibility * 11));
                            lvi.Name = ni.Id;
                            lvi.Tag = ni;

                            nodeText = ni.Id;

                            // Use the display name for the member
                            if(ni.EntryType >= ApiEntryType.Class &&
                              ni.EntryType <= ApiEntryType.Operator)
                            {
                                pos = nodeText.LastIndexOf('.');

                                if(pos != -1)
                                    nodeText = nodeText.Substring(0, pos + 1) +
                                        ni.NodeText;
                                else
                                    nodeText = ni.NodeText;

                                // Resolve templates in the type name
                                if((ni.EntryType == ApiEntryType.Constructor ||
                                  ni.EntryType == ApiEntryType.Method) &&
                                  nodeText.IndexOf('`') != -1)
                                    nodeText = ResolveNameFunction.ReplaceTypeTemplateMarker(
                                        ni.ApiNode, nodeText);
                            }
                            else
                                if(nodeText.IndexOf('`') != -1)
                                    nodeText = ResolveNameFunction.ReplaceTypeTemplateMarker(
                                        ni.ApiNode, nodeText);

                            lvi.SubItems.Add(new ListViewItem.ListViewSubItem(
                                lvi, nodeText));

                            lvSearchResults.Items.Add(lvi);
                        }
                }
            }
            catch(Exception ex)
            {
                MessageBox.Show("Unexpected error occurred while performing " +
                    "the search: " + ex.Message, Constants.AppName,
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                this.Cursor = Cursors.Default;

                btnGoto.Enabled = btnInclude.Enabled = btnExclude.Enabled =
                    (lvSearchResults.Items.Count != 0);
            }
        }
Example #2
0
        /// <summary>
        /// This is called to invoke the <b>resolve-name</b> method
        /// </summary>
        /// <param name="xsltContext">The XSLT context for the function call</param>
        /// <param name="args">The arguments for the function call</param>
        /// <param name="docContext">The context node for the function call</param>
        /// <returns>An object representing the return value of the function (the name string)</returns>
        /// <exception cref="ArgumentException">This is thrown if the number of arguments for the function is
        /// not two.</exception>
        public object Invoke(XsltContext xsltContext, object[] args, XPathNavigator docContext)
        {
            XPathNavigator nav;
            XmlNode        apiNode;
            XmlNodeList    templates;
            StringBuilder  sb = new StringBuilder(100);
            string         nodeText;
            bool           fullyQualified;
            int            pos, idx = 1;
            char           nodeType;

            if (args.Length != 2)
            {
                throw new ArgumentException("There must be two parameters passed to the 'resolve-name' function",
                                            nameof(args));
            }

            nav            = ((XPathNodeIterator)args[0]).Current;
            apiNode        = ((IHasXmlNode)nav).GetNode();
            fullyQualified = Convert.ToBoolean(args[1], CultureInfo.InvariantCulture);

            if (apiNode.Name == "api")
            {
                templates = apiNode.SelectNodes("templates/template");
                nodeText  = apiNode.Attributes["id"].Value;
            }
            else
            {
                nodeText = apiNode.Attributes["api"].Value;

                templates = apiNode.SelectNodes("specialization/template");

                if (templates.Count == 0)
                {
                    templates = apiNode.SelectNodes("specialization/type");
                }
            }

            nodeType = nodeText[0];
            nodeText = nodeText.Substring(2);

            if (nodeType == 'N')
            {
                if (nodeText.Length == 0 && !fullyQualified)
                {
                    nodeText = "(global)";
                }
            }
            else
            {
                // Strip parameters
                pos = nodeText.IndexOf('(');

                if (pos != -1)
                {
                    nodeText = nodeText.Substring(0, pos);
                }

                // Remove the namespace and type if not fully qualified.  Note the last period's position though
                // as we'll need it to skip generic markers in the name type name.
                pos = nodeText.LastIndexOf('.');

                if (!fullyQualified && pos != -1)
                {
                    nodeText = nodeText.Substring(pos + 1);
                    pos      = 0;
                }

                if (nodeType != 'T')
                {
                    // Replace certain values to make it more readable
                    if (nodeText.IndexOf("#cctor", StringComparison.Ordinal) != -1)
                    {
                        nodeText = nodeText.Replace("#cctor", "Static Constructor");
                    }
                    else
                    if (nodeText.IndexOf("#ctor", StringComparison.Ordinal) != -1)
                    {
                        nodeText = nodeText.Replace("#ctor", "Constructor");
                    }
                    else
                    {
                        if (nodeText.IndexOf('#') != -1)
                        {
                            nodeText = nodeText.Replace('#', '.');
                        }

                        if (pos == 0)
                        {
                            if (nodeText.StartsWith("op_", StringComparison.Ordinal))
                            {
                                nodeText = nodeText.Substring(3) + " Operator";
                            }
                        }
                        else
                        if (nodeText.IndexOf("op_", pos, StringComparison.Ordinal) != -1)
                        {
                            nodeText = nodeText.Substring(0, pos + 1) + nodeText.Substring(pos + 4) + " Operator";
                        }
                    }
                }

                // Replace generic template markers with the names
                if (pos != -1)
                {
                    pos = nodeText.IndexOf('`', pos);
                }

                if (pos != -1)
                {
                    nodeText = nodeText.Substring(0, pos);

                    foreach (XmlNode template in templates)
                    {
                        if (sb.Length != 0)
                        {
                            sb.Append(',');
                        }

                        if (template.Name != "type")
                        {
                            sb.Append(template.Attributes["name"].Value);
                        }
                        else
                        {
                            // For specializations of types, we don't want to show the type but a generic placeholder
                            sb.Append('T');

                            if (idx > 1)
                            {
                                sb.Append(idx);
                            }

                            idx++;
                        }
                    }

                    if (sb.Length != 0)
                    {
                        sb.Insert(0, "<");
                        sb.Append('>');
                        nodeText += sb.ToString();
                    }
                }

                // Replace generic template markers in the type name if fully qualified
                if (fullyQualified && nodeText.IndexOf('`') != -1)
                {
                    nodeText = XPathFunctionContext.ReplaceTypeTemplateMarker(apiNode, nodeText);
                }
            }

            return(nodeText);
        }