In the previous part I wrote about functions for loading LeoTreeModel from xml files as well as loading external files. Now, that we have loaded outline let’s add some functions for moving nodes around.

Selecting nodes

User will need to select node previous, next, left, right. LeoTreeModel has field selectedPosition which contains position currently selected (an implementation detail - position is currently an ordinary python float). This value (position) frequently need to be converted to index, so we’ll have selectedIndex property for that purpose.

Here is select_next_node method:

We can assume that selected node is already visible which means all of its ancestors are expanded. That means the node after tree of currently selected node must be also visible. If selected node has children and is expanded, then next node at the selectedIndex + 1. If it is collapsed, then the next node is node after tree.

For selecting previous node we have some more work to do.

First we need to traverse all visible nodes and find last one whose index is less then currently selected index. This may seem inefficient but it won’t be too hard to use some kind of caching if necessary.

Selecting node to the left means select parent, or collapse this node. If this node is top level node, select previous top level node.

Selecting node to the right means expanding currently selected node and selecting its first child if it has children. If this node is without children, select next node.

Selecting nodes is not very difficult. All that is required is some basic integer arithmetic. Modifying outline by moving nodes around is much more challenging, especially taking proper care about clones. But it still requires only basic integer arithmetic and some list manipulations.

Moving nodes

The first method I wrote in this category was promote. It turns all of its following siblings into children. After writing several other outline manipulation methods, I think this method can be improved, but let’s see what its first implementation looks like.

This is just a preparation of necessary data and also we check to see if this operation is legal. If node at position pos has clone among following siblings or their subtrees this operation would make node self descendant which must not happen.

In children of this method definition operation is divided in smaller phases like this:

  1. promote this part of outline
  2. update clones of this node throughout the outline
  3. update node sizes in outline

In this part of the outline we don’t need to insert nor to delete any element in lists. All that is necessary is to handle links between parent node and children and to set parPos elements to point to this node as parent position. Also we need to increase levels of all following sibling nodes and their subtrees.

When we have finished promoting node in this part of outline, we need to adjust any other clone in the outline. Here we have to consider possibility that this node is cloned somewhere else in the outline under different parent. If there are such clones we have to insert new nodes in the outline to make all clones look identically as this one instance.

Finally, in the third phase, sizes of all other parent nodes are updated.