The latest version of prototype is 84b54fc3af.

Currently it is almost 1000 lines including comments and includes the 
following features:

    browsing outline
    editing headlines
    editing bodies
    shows basic Leo icons on nodes
    inserting new nodes
    deleting nodes
    moving nodes up, down, left or right
    promote / demote
    hoist / de-hoist
    cloning nodes
    undo/redo for outline editing commands

I don't plan to work more on this prototype. Its purpose is to prove my 
claims from the beginning of this post. I believe this covers about 5000 
lines of code in Leo:
    - LeoQTreeWidget ~ 500,
    - LeoTree ~ 350,
    - leoChapters.py ~ 480,
    - qt_tree.py ~ 1430,
    - leoUndo.py ~ 1730
    - ... total 4490 LOC + about 500 lines for implementing all these 
commands.

This means that the bugs have about 4000 lines more space to hide than is 
necessary.
It is also 4000 lines more for CPU to execute and a lot of those lines are 
inside
loops. By applying all these refactorings Leo's code will be much smaller 
and hopefully
it will run much faster.

The prototype is not fully documented. There are a few not very obvious 
methods that
I had to rewrite several times to eliminate bugs that I haven't spotted at 
first.
Those methods require more detailed explanation.

First is make_undoable_move. Here it is:
def make_undoable_move(self, oldparent, srcindex, newparent, dstindex):
    t = self.tree
    root = t.invisibleRootItem()
    trash = []

    newitems = [(x, oldparent.child(srcindex).clone())
                    for x in all_other_items(root, newparent)]
    def domove():
        for item in all_other_items(root, oldparent):
            trash.append(item.takeChild(srcindex))

        for item, child in newitems:
            item.insertChild(dstindex, child)

        curr = move_treeitem(oldparent, srcindex, newparent, dstindex)

        self.tree.setCurrentItem(curr)

    def undomove():
        for item, child in newitems:
            item.takeChild(dstindex)

        for item in all_other_items(root, oldparent):
            item.insertChild(srcindex, trash.pop())

        curr = move_treeitem(newparent, dstindex, oldparent, srcindex)

        self.tree.setCurrentItem(curr)

    domove()

    self.c.addUndo(undomove, domove)


oldparent and newparent are tree widget items, and srcindex/dstindex are 
ints. At first I was creating and deleting child items inside functions 
domove and undomove. However, this caused exceptions when performing undo 
and redo later, because redo would create new items and maybe next undo 
block relies on the items that used to be created before. To solve this 
issue, all necessary items must be created outside domove/undomove and all 
items that will be deleted by this command must be kept in local variable 
trash. This pattern I had to repeat in other commands as well.

Generator all_other_items yields tree widget items that point to the same v 
node, skipping the given one. This generator uses links between v-nodes so 
the order of the execution is important. In this method this order of the 
execution doesn't matter but in some other methods it does.

When moving item from one parent to another one, if the oldparent is cloned 
or belongs to the cloned subtree it means we have to remove child not only 
from the oldparent, but from all other items that point to the same v node 
as oldparent. It means we will have to delete some items. The deleted items 
will go to trash from where we will be able to collect them again during 
the undo command.

OTOH if the newparent is part of cloned subtree, that means we will need 
extra items to insert in every other clone. The command moves single item 
from oldparent to the newparent and all other clones both on the source 
side and on the destination side are processed using all_other_items 
generator. Sometimes like in this method the results of this generator are 
kept in local variable and iterated again using that variable (like 
newitems variable above).

Vitalije

-- 
You received this message because you are subscribed to the Google Groups 
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/leo-editor/f22b17c0-aace-45bc-a8b9-a6f6931134b4%40googlegroups.com.

Reply via email to