/// <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 static void GoToCodeElementHelper(DTE2 dte, CodeElementWrapper cew, bool useTryShow) { if (cew != null) { try { TextPoint start = cew.StartPoint; var 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="codeElementWrapper">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; var 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 (ArgumentException e) { SourceOutlineToolWindow.DisplayMessage(Resources.ErrorPrefix, "Adding duplicate to mapElementIDToTreeViewCodeElementWrapper: " + e.Message); } // Add to filtered (flat) tree. var codeElementWrapperFilterView = new CodeElementWrapper(codeElementWrapper.CodeElement); FilterView.Nodes.Add(codeElementWrapperFilterView); try { // Add the element to the filter view map. mapElementIDToFilterViewCodeElementWrapper.Add(codeElementWrapper.UniqueElementId, codeElementWrapperFilterView); } catch (ArgumentException e) { SourceOutlineToolWindow.DisplayMessage(Resources.ErrorPrefix, "Adding duplicate to mapElementIDToFilterViewCodeElementWrapper: " + e.Message); } // Add the node to the array. var codeElementWrapperClone = new CodeElementWrapper(codeElementWrapper.CodeElement); codeElementWrapperArray.AddCodeElementWrapper(codeElementWrapperClone); }
/// <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 static 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; }
/// <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. var 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 { var 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; } 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); 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) { // Remove the children before the node, deleting upwards from last to first. for (int i = codeElementWrapperToDelete.Nodes.Count - 1; i >= 0; i--) { var 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 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--) { var 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(CodeElement codeElement, TreeNodeCollection nodes, bool interruptible) { if (interruptible) { yieldCount0++; if (yieldCount0 >= 5) { yieldCount0 = 0; var pkg = sourceOutlineToolWindow.Package as NPLLanguageServicePackage; 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 != vsCMInfoLocation.vsCMInfoLocationProject) { return true; } CodeElementWrapper treenode; 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); treenode.Expand(); 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; var pkg = sourceOutlineToolWindow.Package as NPLLanguageServicePackage; if (pkg != null) { IOleComponentManager cm = pkg.ComponentManager; if (cm != null) { if (cm.FContinueIdle() == 0) { return false; } } } } } var members = CodeModelHelpers.GetMembersOf(codeElementWrapper.CodeElement); if (members != null) { foreach (CodeElement codeElementMember in members) { string uniqueID = CodeModelHelpers.GetUniqueElementId(codeElementMember); CodeElementWrapper node; 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)) { var 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; }