// Constructor. public TextTree(TextBuffer buffer, TextLayout layout) { // set the buffer for this text tree this.buffer = buffer; // set the layout for this text tree this.layout = layout; // set the root for this text tree root = new TextGroup(); // insert a new line into the buffer buffer.Insert(0, '\n'); // create the first line TextLine line = new TextLine (buffer.MarkPosition(0, true), buffer.MarkPosition(1, true)); // insert the first line into the tree root.InsertChild(null, line); // update the metrics information root.UpdateMetrics(layout, true); // create the caret position caret = buffer.MarkPosition(0, false); // create the selection position selection = buffer.MarkPosition(0, false); }
// Rebalance the tree at this node. public override void Rebalance(TextTree tree) { // get this node TextGroup node = this; // rebalance up the tree while(node != null) { // enforce upper bound on child count while(node.childCount > MAX_CHILD_COUNT) { // create a new root before splitting current root if(node.parent == null) { // create the new root node TextGroup root = new TextGroup(); // set the new root's level root.level = (node.level + 1); // insert the old root under the new root root.InsertChild(null, node); // set the root of the tree to the new root tree.root = root; } // create the new group for the excess children TextGroup group = new TextGroup(); // set the new group's level group.level = node.level; // get the first child of the node to be split TextNode child = node.first; // find the first excess child for(int i = 1; i < MIN_CHILD_COUNT; ++i) { child = child.next; } // insert first excess child under the new group group.InsertChildren(null, child.next); // insert group under the current node's parent node.parent.InsertChild(node, group); // set the current node to the new group node = group; } // enforce lower bound on child count while(node.childCount < MIN_CHILD_COUNT) { // handle the root node case if(node.parent == null) { // root needs at least two children or one line if((node.childCount == 1) && (node.level > 1)) { // set the root to its only child tree.root = (TextGroup)node.first; // remove new root from the old root node.RemoveChild(tree.root); } // we're done rebalancing return; } // rebalance the parent, if too few siblings if(node.parent.ChildCount < 2) { // rebalance the parent node.parent.Rebalance(tree); // try the current node again continue; } // get the next sibling of the current node TextGroup next = (TextGroup)node.next; // use previous and swap, if no next sibling if(next == null) { // set the next node to the current node next = node; // reset current node to previous sibling node = (TextGroup)node.prev; } // calculate the total child count for the nodes int fullCount = node.childCount + next.childCount; // merge the nodes or split up the children if(fullCount <= MAX_CHILD_COUNT) { // merge the children under a single node node.InsertChildren(node.last, next.first); // remove the empty node from the tree node.parent.RemoveChild(next); // continue rebalancing at this node, if needed if(fullCount < MIN_CHILD_COUNT) { continue; } } else { // calculate the first node's new child count int halfCount = (fullCount / 2); // move children around as needed if(node.childCount < halfCount) { // move the needed children to the first node node.InsertChildren (node.last, next.first, (halfCount - node.childCount)); } else if(node.childCount > halfCount) { // get the first child of the first node TextNode child = node.first; // get the first of the children to move for(int i = 1; i < halfCount; ++i) { child = child.next; } // move extra children to the second node next.InsertChildren(null, child); } } } // set the current node to its parent node = (TextGroup)node.parent; } }