public int IndexOf(object item) { SharpTreeNode node = item as SharpTreeNode; if (node != null && node.IsVisible && node.GetListRoot() == root) { if (includeRoot) { return(SharpTreeNode.GetVisibleIndexForNode(node)); } else { return(SharpTreeNode.GetVisibleIndexForNode(node) - 1); } } else { return(-1); } }
internal static int GetVisibleIndexForNode(SharpTreeNode node) { int index = node.left != null?node.left.GetTotalListLength() : 0; while (node.listParent != null) { if (node == node.listParent.right) { if (node.listParent.left != null) { index += node.listParent.left.GetTotalListLength(); } if (node.listParent.isVisible) { index++; } } node = node.listParent; } return(index); }
/// <summary> /// Balances the subtree rooted in <paramref name="node"/> and recomputes the 'height' field. /// This method assumes that the children of this node are already balanced and have an up-to-date 'height' value. /// </summary> /// <returns>The new root node</returns> static SharpTreeNode Rebalance(SharpTreeNode node) { Debug.Assert(node.left == null || Math.Abs(node.left.Balance) <= 1); Debug.Assert(node.right == null || Math.Abs(node.right.Balance) <= 1); // Keep looping until it's balanced. Not sure if this is stricly required; this is based on // the Rope code where node merging made this necessary. while (Math.Abs(node.Balance) > 1) { // AVL balancing // note: because we don't care about the identity of concat nodes, this works a little different than usual // tree rotations: in our implementation, the "this" node will stay at the top, only its children are rearranged if (node.Balance > 1) { if (node.right.Balance < 0) { node.right = node.right.RotateRight(); } node = node.RotateLeft(); // If 'node' was unbalanced by more than 2, we've shifted some of the inbalance to the left node; so rebalance that. node.left = Rebalance(node.left); } else if (node.Balance < -1) { if (node.left.Balance > 0) { node.left = node.left.RotateLeft(); } node = node.RotateRight(); // If 'node' was unbalanced by more than 2, we've shifted some of the inbalance to the right node; so rebalance that. node.right = Rebalance(node.right); } } Debug.Assert(Math.Abs(node.Balance) <= 1); node.height = (byte)(1 + Math.Max(Height(node.left), Height(node.right))); node.totalListLength = -1; // mark for recalculation // since balancing checks the whole tree up to the root, the whole path will get marked as invalid return(node); }
static void InsertNodeAfter(SharpTreeNode pos, SharpTreeNode newNode) { // newNode might be the model root of a whole subtree, so go to the list root of that subtree: newNode = newNode.GetListRoot(); if (pos.right == null) { pos.right = newNode; newNode.listParent = pos; } else { // insert before pos.right's leftmost: pos = pos.right; while (pos.left != null) { pos = pos.left; } Debug.Assert(pos.left == null); pos.left = newNode; newNode.listParent = pos; } RebalanceUntilRoot(pos); }
SharpTreeNode Successor() { if (right != null) { SharpTreeNode node = right; while (node.left != null) { node = node.left; } return(node); } else { SharpTreeNode node = this; SharpTreeNode oldNode; do { oldNode = node; node = node.listParent; // loop while we are on the way up from the right part } while (node != null && node.right == oldNode); return(node); } }
SharpTreeNode RotateRight() { /* Rotate tree to the right * * this left * / \ / \ * left C ===> A this * / \ / \ * A B B C */ SharpTreeNode b = left.right; SharpTreeNode newTop = left; if (b != null) { b.listParent = this; } this.left = b; newTop.right = this; newTop.listParent = this.listParent; this.listParent = newTop; newTop.right = Rebalance(this); return(newTop); }
static void DumpTree(SharpTreeNode node) { node.GetListRoot().DumpTree(); }
static int Height(SharpTreeNode node) { return(node != null ? node.height : 0); }
internal protected virtual void OnChildrenChanged(NotifyCollectionChangedEventArgs e) { if (e.OldItems != null) { foreach (SharpTreeNode node in e.OldItems) { Debug.Assert(node.modelParent == this); node.modelParent = null; Debug.WriteLine("Removing {0} from {1}", node, this); SharpTreeNode removeEnd = node; while (removeEnd.modelChildren != null && removeEnd.modelChildren.Count > 0) { removeEnd = removeEnd.modelChildren.Last(); } List <SharpTreeNode> removedNodes = null; int visibleIndexOfRemoval = 0; if (node.isVisible) { visibleIndexOfRemoval = GetVisibleIndexForNode(node); removedNodes = node.VisibleDescendantsAndSelf().ToList(); } RemoveNodes(node, removeEnd); if (removedNodes != null) { var flattener = GetListRoot().treeFlattener; if (flattener != null) { flattener.NodesRemoved(visibleIndexOfRemoval, removedNodes); } } } } if (e.NewItems != null) { SharpTreeNode insertionPos; if (e.NewStartingIndex == 0) { insertionPos = null; } else { insertionPos = modelChildren[e.NewStartingIndex - 1]; } foreach (SharpTreeNode node in e.NewItems) { Debug.Assert(node.modelParent == null); node.modelParent = this; node.UpdateIsVisible(isVisible && isExpanded, false); //Debug.WriteLine("Inserting {0} after {1}", node, insertionPos); while (insertionPos != null && insertionPos.modelChildren != null && insertionPos.modelChildren.Count > 0) { insertionPos = insertionPos.modelChildren.Last(); } InsertNodeAfter(insertionPos ?? this, node); insertionPos = node; if (node.isVisible) { var flattener = GetListRoot().treeFlattener; if (flattener != null) { flattener.NodesInserted(GetVisibleIndexForNode(node), node.VisibleDescendantsAndSelf()); } } } } RaisePropertyChanged("ShowExpander"); RaiseIsLastChangedIfNeeded(e); }