/// <summary> /// It is assumed that the node oldFlattenedTree[oldIndex] and newFlattenedTree[newIndex] coorespond /// to one another (have the same path to root) /// Copies the expandedness of the node 'oldFlattenedTree[oldIndex]' to the new node at /// newFlattenedTree[newIndex], as well as all the state for child node. /// </summary> internal static void CopyExpandedStateForNode(List <CallTreeViewNode> newFlattenedTree, int newIndex, ObservableCollectionEx <CallTreeViewNode> oldFlattenedTree, int oldIndex) { Debug.Assert(newIndex == newFlattenedTree.Count - 1); CallTreeViewNode oldNode = oldFlattenedTree[oldIndex]; if (oldNode.m_isExpanded) { CallTreeViewNode newNode = newFlattenedTree[newIndex]; Debug.Assert(newNode.Data.DisplayName == oldNode.Data.DisplayName); newNode.m_isExpanded = true; if (newNode.HasChildren) { var children = newNode.MakeChildren(); for (int i = 0; i < children.Count; i++) { var newChild = children[i]; newFlattenedTree.Add(newChild); // This is N squared so can take a long time if there are many children // We can simply give up in that case. if (i < 50) { int oldChildIndex = FindChild(oldFlattenedTree, oldNode, oldIndex, newChild.Data.DisplayName); if (oldChildIndex >= 0) { CopyExpandedStateForNode(newFlattenedTree, newFlattenedTree.Count - 1, oldFlattenedTree, oldChildIndex); } } } } } }
/// <summary> /// I did not make this a property because it is too profound an operation (heavy) /// This sets the root of the tree. This is how you change the display to a new tree. /// </summary> public void SetRoot(CallTreeNode root) { List <CallTreeViewNode> newFlattenedTree = new List <CallTreeViewNode>(); newFlattenedTree.Add(new CallTreeViewNode(this, root, 0)); // Copy over the nodes to the new flattened tree (as best we can) if (m_flattenedTree.Count > 0 && m_flattenedTree[0].Data.DisplayName == root.DisplayName) { CallTreeViewNode.CopyExpandedStateForNode(newFlattenedTree, 0, m_flattenedTree, 0); } // Destroy old nodes (to save memory because GUI keeps references to them) foreach (var node in m_flattenedTree) { node.Dispose(); } // Update the whole tree with the new tree. m_flattenedTree.ReplaceRange(0, m_flattenedTree.Count, newFlattenedTree); Validate(); m_root = root; m_curPosition = null; m_endPosition = null; // Expand the root element var rootView = InsureVisible(m_root); rootView.IsExpanded = true; }
/// <summary> /// An Unexpanded CallTreeViewNode does not have any children even if the Data (CallTreeNode) does /// This routine will make the necessary children (it is part of expanding the node). /// </summary> private List <CallTreeViewNode> MakeChildren() { var callees = m_treeView.DisplayCallees(Data); Debug.Assert(callees != null); var ret = new List <CallTreeViewNode>(); for (int i = 0; i < callees.Count; i++) { CallTreeNode elem = callees[i]; var newNode = new CallTreeViewNode(m_treeView, elem, m_depth + 1); if (IsSecondaryChild || elem.IsGraphNode) { newNode.IsSecondaryChild = true; } ret.Add(newNode); } return(ret); }
/// <summary> /// Given a CallTreeNode, find a CallTreeViewNode for it (ensure that it is displayed) /// </summary> private CallTreeViewNode InsureVisible(CallTreeNode treeNode) { if (treeNode.Caller == null) { return(m_flattenedTree[0]); } CallTreeViewNode caller = InsureVisible(treeNode.Caller); if (caller == null) // should never happen, but we can fall back to giving up. { return(null); } caller.IsExpanded = true; caller.ValidateTree(); int callerPos = caller.MyIndex + 1; while (callerPos < m_flattenedTree.Count) { var child = m_flattenedTree[callerPos]; if (child.m_depth <= caller.m_depth) { break; } if (child.Data == treeNode) { return(child); } callerPos++; } Debug.Assert(false, "Should have found call node"); return(null); }
/// <summary> /// Given a node == flattenedTree[sampleIndex] find the sampleIndex in flattenedTree of a child with Data.NameBase == 'nameBame' /// </summary> private static int FindChild(ObservableCollectionEx <CallTreeViewNode> flattenedTree, CallTreeViewNode node, int index, string nameBase) { Debug.Assert(flattenedTree[index] == node); int childDepth = node.m_depth + 1; int childIndex = index; for (; ;) { childIndex++; if (childIndex >= flattenedTree.Count) { break; } var child = flattenedTree[childIndex]; if (child.m_depth < childDepth) { break; } if (child.m_depth == childDepth && child.Data.DisplayName == nameBase) { return(childIndex); } } return(-1); }