Ejemplo n.º 1
0
        /// <summary>
        /// Selects text in the code editor.
        /// </summary>
        /// <param name="dte">A DTE2 object exposing the Visual Studio automation object model.</param>
        /// <param name="cew">The CodeElementWrapper object containing the selection.</param>
        /// <param name="useTryShow">true to use TryToShow to adjust the code editor window to show the selection, otherwise false.</param>
        private void GoToCodeElementHelper(DTE2 dte, CodeElementWrapper cew, bool useTryShow)
        {
            if (cew != null)
            {
                try
                {
                    TextPoint start = cew.StartPoint;
                    TextDocument tx = (TextDocument)dte.ActiveDocument.Object("TextDocument");
                    int line = start.Line;
                    int offset = start.LineCharOffset;

                    if (!useTryShow)
                    {
                        tx.Selection.MoveToLineAndOffset(line, offset, false);
                    }
                    else
                    {
                        start.TryToShow(vsPaneShowHow.vsPaneShowCentered, start);
                    }

                    if (!useTryShow)
                    {
                        tx.Selection.SelectLine();
                    }
                }
                catch (COMException)
                {
                    // Discard the exception that gets thrown when accessing
                    // a non-code TextDocument, for example a Windows form.
                }
            }
        }
        /// <summary>
        /// Locates a specific element in the flat view by ID.
        /// </summary>
        /// <param name="codeElement">The CodeElementWrapper object to locate.</param>
        /// <returns>The CodeElementWrapper object containing the element.</returns>
        private CodeElementWrapper FindElementInFilterView(CodeElementWrapper codeElementWrapper)
        {
            CodeElementWrapper codeElementWrapperOut = null;
            string strElementID = codeElementWrapper.UniqueElementId;

            // Use sequential search.
            foreach (CodeElementWrapper node in FilterView.Nodes)
            {
                if (strElementID == node.UniqueElementId)
                {
                    codeElementWrapperOut = node;
                    break;
                }
            }

            return codeElementWrapperOut;
        }
        /// <summary>
        /// Determines if a code element is within a specific tree node.
        /// </summary>
        /// <param name="treeNode">The source CodeElementWrapper object.</param>
        /// <param name="tp">The TextPoint cursor position in the source file.</param>
        /// <returns>The CodeElementWrapper object that contains the text point.</returns>
        private CodeElementWrapper FindBestMatch(CodeElementWrapper treeNode, TextPoint tp)
        {
            CodeElementWrapper cewBestMatch = null;

            // Is the tp between the start and end point of this CodeElement.
            if ((treeNode.StartPoint.EqualTo(tp))
                || (treeNode.StartPoint.LessThan(tp) && treeNode.EndPoint.GreaterThan(tp)))
            {
                cewBestMatch = treeNode;
                CodeElementWrapper closestCEWInChildren = FindBestMatchInCollection(treeNode.Nodes, tp);
                if (closestCEWInChildren != null)
                {
                    cewBestMatch = closestCEWInChildren;
                }
            }

            return cewBestMatch;
        }
        /// <summary>
        /// Adds a new element to the tree views.
        /// </summary>
        /// <param name="codeElementWrapper">The new element as a CodeElementWrapper object.</param>
        private void AddNodeToInternalStructures(CodeElementWrapper codeElementWrapper)
        {
            try
            {
                // Add the element to the tree view map.
                _mapElementIDToTreeViewCodeElementWrapper.Add(codeElementWrapper.UniqueElementId, codeElementWrapper);
            }
            catch (System.ArgumentException e)
            {
                SourceOutliner.DisplayMessage(Resources.ErrorPrefix, "Adding duplicate to _mapElementIDToTreeViewCodeElementWrapper: " + e.Message);
            }

            // Add to filtered (flat) tree.
            CodeElementWrapper codeElementWrapperFilterView = new CodeElementWrapper(codeElementWrapper.CodeElement);
            FilterView.Nodes.Add(codeElementWrapperFilterView);

            try
            {
                // Add the element to the filter view map.
                _mapElementIDToFilterViewCodeElementWrapper.Add(codeElementWrapper.UniqueElementId, codeElementWrapperFilterView);
            }
            catch (System.ArgumentException e)
            {
                SourceOutliner.DisplayMessage(Resources.ErrorPrefix, "Adding duplicate to _mapElementIDToFilterViewCodeElementWrapper: " + e.Message);
            }

            // Add the node to the array.
            CodeElementWrapper codeElementWrapperClone = new CodeElementWrapper(codeElementWrapper.CodeElement);
            _codeElementWrapperArray.AddCodeElementWrapper(codeElementWrapperClone);
        }
        /// <summary>
        /// Locates an element by name within a set of nodes.
        /// </summary>
        /// <param name="codeElementWrapperParent">The CodeElementWrapper object to search.</param>
        /// <param name="codeElement">The CodeElement object to locate.</param>
        /// <param name="listCodeElementWrapperOut">The List of elements found.</param>
        private static void FindChildrenByName(CodeElementWrapper codeElementWrapperParent, 
            CodeElement codeElement,
            out System.Collections.Generic.List<CodeElementWrapper> listCodeElementWrapperOut)
        {
            listCodeElementWrapperOut = new System.Collections.Generic.List<CodeElementWrapper>();
            string strElementName = codeElement.Name;

            int matches = 0;
            foreach (CodeElementWrapper node in codeElementWrapperParent.Nodes)
            {
                if (node.ElementName == strElementName)
                {
                    listCodeElementWrapperOut.Add(node);
                    matches++;
                }
            }
        }
        /// <summary>
        /// Occurs when a new code element is added to the text window,
        /// and adds the new element to the appropriate place in the outline.
        /// </summary>
        /// <param name="newElement">The new code element.</param>
        public void OnCodeModelElementAdd(CodeElement newElement)
        {
            if ((newElement == null) || !CodeModelHelpers.IsInterestingKind(newElement.Kind))
            {
                return;
            }

            try
            {
                int line = newElement.StartPoint.Line;
            }
            catch
            {
                // An exception can be thrown here when an element is being edited, so ignore it.
                return;
            }

            // Update the tree.
            if (newElement.Kind == vsCMElement.vsCMElementParameter)
            {
                FindBestMatchCodeElementToRefreshFrom(newElement);
                return;
            }

            // Get the start point from the wrapper object and not from the CodeElement directly.
            CodeElementWrapper temp = new CodeElementWrapper(newElement);
            TextPoint tp = temp.StartPoint;
            CodeElementWrapper cew = GetClosestCodeElementInTreeView(TreeView, tp);

            if (cew == null)
            {
                // Nothing found, this must be the first element drawn.
                ReadCodeModelElementsRecursive(newElement, TreeView.Nodes, false);
            }
            else
            {
                CodeElementWrapper newNode = new CodeElementWrapper(newElement);

                // Note that the add could result from a paste, and the editor only informs
                // regarding the outer element that was added if the language is C# or VB;
                // the C++ language raises an event for each element.
                AddNodeToInternalStructures(newNode);
                ReadCodeModelChildrenElementsRecursive(newNode, false);

                newNode.ExpandAll();

                int index = 0;

                // Insert this element in the correct place.
                foreach (CodeElementWrapper n in cew.Nodes)
                {
                    if (n.Location > newNode.Location)
                    {
                        // Insert prior to n.
                        cew.Nodes.Insert(index, newNode);
                        newNode = null;
                        break;
                    }
                    else
                    {
                        index++;
                    }
                }

                // If it was not inserted, append it.

                if (newNode != null)
                {
                    cew.Nodes.Add(newNode);
                }
            }

            // Update the filter view.
            _codeElementWrapperIndexTable = new CodeElementWrapperIndexTable(_codeElementWrapperArray);
            _currentResults = _codeElementWrapperIndexTable.GenerateResultsTable(_searchCriteria);
            this.FilterText = _currentFilterText;
        }
        /// <summary>
        /// Removes a node and all of its children.
        /// </summary>
        /// <param name="codeElementWrapperToDelete">The CodeElementWrapper to delete.</param>
        /// <param name="codeElementWrapperParent">The CodeElementWrapper parent of the object to delete.</param>
        private void RemoveElementRecursive(CodeElementWrapper codeElementWrapperToDelete,
            CodeElementWrapper codeElementWrapperParent)
        {
            CodeElementWrapper codeElementWrapper;

            // Remove the children before the node, deleting upwards from last to first.
            for (int i = codeElementWrapperToDelete.Nodes.Count - 1; i >= 0; i--)
            {
                CodeElementWrapper node = codeElementWrapperToDelete.Nodes[i] as CodeElementWrapper;
                RemoveElementRecursive(node, codeElementWrapperToDelete);
            }

            // Remove the element from the outline view.
            RemoveElementFromTree(codeElementWrapperToDelete, codeElementWrapperParent);

            // Remove the element from the filter view.
            codeElementWrapper = FindElementInFilterView(codeElementWrapperToDelete);
            if (codeElementWrapper != null)
            {
                RemoveElementFromFilterView(codeElementWrapper);
            }

            // Remove the element from the array.
            codeElementWrapper = FindElementInWrapperArray(codeElementWrapperToDelete);
            if (codeElementWrapper != null)
            {
                RemoveElementFromWrapperArray(codeElementWrapper);
            }
        }
 /// <summary>
 /// Removes an element from the wrapper array.
 /// </summary>
 /// <param name="codeElementWrapperToDelete">The CodeElementWrapper to remove.</param>
 private void RemoveElementFromWrapperArray(CodeElementWrapper codeElementWrapperToDelete)
 {
     // Remove the element from the array.
     _codeElementWrapperArray.Remove(codeElementWrapperToDelete);
 }
        /// <summary>
        /// Removes an element from the outline tree view by ID.
        /// </summary>
        /// <param name="codeElementWrapperToDelete">The CodeElementWrapper to delete.</param>
        /// <param name="codeElementWrapperParent">The CodeElementWrapper parent of the object to delete.</param>
        private void RemoveElementFromTree(CodeElementWrapper codeElementWrapperToDelete,
            CodeElementWrapper codeElementWrapperParent)
        {
            // Remove the element from the tree view.
            codeElementWrapperParent.Nodes.Remove(codeElementWrapperToDelete);

            // Remove the element from the map.
            _mapElementIDToTreeViewCodeElementWrapper.Remove(codeElementWrapperToDelete.UniqueElementId);
        }
        /// <summary>
        /// Removes an element from the flat view by ID.
        /// </summary>
        /// <param name="codeElementWrapperToDelete">The CodeElementWrapper to delete.</param>
        private void RemoveElementFromFilterView(CodeElementWrapper codeElementWrapperToDelete)
        {
            // Remove the element from the filter view.
            FilterView.Nodes.Remove(codeElementWrapperToDelete);

            // Remove the element from the map.
            _mapElementIDToFilterViewCodeElementWrapper.Remove(codeElementWrapperToDelete.UniqueElementId);
        }
        /// <summary>
        /// Refreshes a specific tree node with a specific element.
        /// </summary>
        /// <param name="codeElementWrapper">The CodeElementWrapper to refresh.</param>
        /// <param name="codeElement">The CodeElement to refresh with.</param>
        private void RefreshCodeModelForElement(ref CodeElementWrapper codeElementWrapper,
            CodeElement codeElement)
        {
            TreeNode treeNodeFilterView = null;
            TreeNode treeNodeTreeView = null;

            try
            {
                treeNodeFilterView = FilterView.SelectedNode;
                treeNodeTreeView = TreeView.SelectedNode;

                TreeView.BeginUpdate();
                FilterView.BeginUpdate();

                BeginTransaction();

                // Update the element itself.
                codeElementWrapper.CodeElement = codeElement;

                // Remove elements from the parent in reverse order.
                for (int i = codeElementWrapper.Nodes.Count - 1; i >= 0; i--)
                {
                    CodeElementWrapper node = codeElementWrapper.Nodes[i] as CodeElementWrapper;
                    RemoveElementRecursive(node, codeElementWrapper);
                }

                codeElementWrapper.Nodes.Clear();

                ReadCodeModelChildrenElementsRecursive(codeElementWrapper, false);

                // Update the copy of the codeElementWrapper in the wrapper array.
                CodeElementWrapper codeElementWrapperClone = FindElementInWrapperArray(codeElementWrapper);
                if (codeElementWrapperClone != null)
                {
                    RemoveElementFromWrapperArray(codeElementWrapperClone);
                }
                codeElementWrapperClone = new CodeElementWrapper(codeElementWrapper.CodeElement);
                _codeElementWrapperArray.AddCodeElementWrapper(codeElementWrapperClone);

            }
            finally
            {
                EndTransaction();

                TreeView.ExpandAll();

                FilterView.EndUpdate();
                TreeView.EndUpdate();

                FilterView.SelectedNode = treeNodeFilterView;
                TreeView.SelectedNode = treeNodeTreeView;
            }
        }
        /// <summary>
        /// Iterates through the code model starting at a specified element
        /// and adds the discovered elements to a tree.
        /// </summary>
        /// <param name="codeElement">The starting CodeElement.</param>
        /// <param name="nodes">The TreeNodeCollection to add the element to.</param>
        /// <param name="interruptible">true if this method can be interrupted (is background), otherwise false.</param>
        /// <returns>true if the method completed, otherwise false.</returns>
        private bool ReadCodeModelElementsRecursive(EnvDTE.CodeElement codeElement, TreeNodeCollection nodes, bool interruptible)
        {
            if (interruptible)
            {
                yieldCount0++;
                if (yieldCount0 >= 5)
                {
                    yieldCount0 = 0;
                    SourceOutliner pkg = _sourceOutlineToolWindow.Package as SourceOutliner;
                    if (pkg != null)
                    {
                        IOleComponentManager cm = pkg.ComponentManager;
                        if (cm != null)
                        {
                            if (cm.FContinueIdle() == 0)
                            {
                                return false;
                            }
                        }
                    }
                }
            }

            if (codeElement == null)
            {
                return true;
            }

            // Test whether this is a code element of interest.
            if (!CodeModelHelpers.IsInterestingKind(codeElement.Kind))
            {
                return true;
            }

            if (codeElement.InfoLocation != EnvDTE.vsCMInfoLocation.vsCMInfoLocationProject)
            {
                return true;
            }

            CodeElementWrapper treenode = null;
            string uniqueID = CodeModelHelpers.GetUniqueElementId(codeElement);

            // See if this node has finished processing.
            _mapElementIDToTreeViewCodeElementWrapper.TryGetValue(uniqueID, out treenode);
            if (treenode != null)
            {
                if (treenode.FinishedLoading)
                    return true;
            }
            else
            {
                treenode = new CodeElementWrapper(codeElement);
                nodes.Add(treenode);
                AddNodeToInternalStructures(treenode);
            }

            treenode.FinishedLoading = ReadCodeModelChildrenElementsRecursive(treenode, interruptible);

            return treenode.FinishedLoading;
        }
        /// <summary>
        /// Iterates through the children of a code model element.
        /// </summary>
        /// <param name="codeElementWrapper">The CodeElementWrapper to process.</param>
        /// <param name="interruptible">true if this method can be interrupted (is background), otherwise false.</param>
        /// <returns>true if the method completed, otherwise false.</returns>
        private bool ReadCodeModelChildrenElementsRecursive(CodeElementWrapper codeElementWrapper, bool interruptible)
        {
            if (interruptible)
            {
                yieldCount1++;
                if (yieldCount1 >= 5)
                {
                    yieldCount1 = 0;
                    SourceOutliner pkg = _sourceOutlineToolWindow.Package as SourceOutliner;
                    if (pkg != null)
                    {
                        IOleComponentManager cm = pkg.ComponentManager;
                        if (cm != null)
                        {
                            if (cm.FContinueIdle() == 0)
                            {
                                return false;
                            }
                        }
                    }
                }
            }

            bool childrenRead;

            CodeElements members = CodeModelHelpers.GetMembersOf(codeElementWrapper.CodeElement);
            if (members != null)
            {
                foreach (CodeElement codeElementMember in members)
                {
                    string uniqueID = CodeModelHelpers.GetUniqueElementId(codeElementMember);
                    CodeElementWrapper node = null;
                    _mapElementIDToTreeViewCodeElementWrapper.TryGetValue(uniqueID, out node);
                    if (node != null)
                    {
                        if (node.FinishedLoading)
                            continue;
                    }

                    // Prevent a recursive call if the code element is not of interest.
                    if (CodeModelHelpers.IsInterestingKind(codeElementMember.Kind))
                    {
                        childrenRead = ReadCodeModelElementsRecursive(codeElementMember, codeElementWrapper.Nodes, interruptible);
                        if (!childrenRead)
                        {
                            // Children failed to be read, so leave.
                            return false;
                        }
                    }
                }
            }
            return true;
        }
        /// <summary>
        /// Locates an element in the wrapper array.
        /// </summary>
        /// <param name="codeElementWrapper">The CodeElementWrapper object to locate.</param>
        /// <returns>The CodeElementWrapper node that was located in the array.</returns>
        private CodeElementWrapper FindElementInWrapperArray(CodeElementWrapper codeElementWrapper)
        {
            CodeElementWrapper codeElementWrapperOut = null;

            try
            {
                codeElementWrapperOut = _codeElementWrapperArray.FindCodeElementWrapper(codeElementWrapper);
            }
            catch (Exception)
            {
                // If not found in the map, use a sequential search.
                string strElementID = codeElementWrapper.UniqueElementId;
                foreach (CodeElementWrapper node in _codeElementWrapperArray)
                {
                    if (strElementID == node.UniqueElementId)
                    {
                        codeElementWrapperOut = node;
                        break;
                    }
                }
            }

            return codeElementWrapperOut;
        }
        /// <summary>
        /// Locates a specific element in a tree node by ID, recursively.
        /// </summary>
        /// <param name="codeElement">The CodeElement object to locate.</param>
        /// <param name="codeElementWrapperNode">The CodeElementWrapper node to search.</param>
        /// <returns>The CodeElementWrapper object containing the element.</returns>
        private CodeElementWrapper FindElementInTreeRecursive(CodeElement codeElement, CodeElementWrapper codeElementWrapperNode)
        {
            string strCodeElementID = CodeModelHelpers.GetUniqueElementId(codeElement);

            if (strCodeElementID == codeElementWrapperNode.UniqueElementId)
            {
                return codeElementWrapperNode;
            }

            // If this is not it, check the children.
            CodeElementWrapper codeElementWrapper = null;
            foreach (CodeElementWrapper node in codeElementWrapperNode.Nodes)
            {
                codeElementWrapper = FindElementInTreeRecursive(codeElement, node);
                if (codeElementWrapper != null)
                {
                    break;
                }
            }

            return codeElementWrapper;
        }