>
>
> Great help in quickly traversing tree to the given top position is to now 
>> how many nodes are in its subtree. In my model it is the size of a node. 
>>
>
> True, but the big payoff will come from just drawing/allocating 
> approximately N nodes, where there are N visible nodes in the outline.  
> This will eliminate the performance bug when expanding all nodes.  No 
> matter how many nodes the outline contains, the performance of the 
> algorithm should be roughly O(1).
>
> What I meant is that it can help to calculate the top_position. Let's say 
we want to start drawing at the 100th node. We need to skip 99 nodes 
before. It helps if you know that the first top level node has 98 nodes in 
its subtree and you can be sure that none of them should be drawn. If you 
don't know you have to traverse its subtree to find out.

An advantage of using QGraphicsScene and its items is that you can draw 
tree starting at any given node. It doesn't require items to have parents 
all the way to the top. Each position knows its level so you can move the 
corresponding graphics item at the correct indentation without drawing any 
parent items. Look at the miniTkLeo how items are drawn in Tk.Canvas. I am 
sure QGraphicsScene items will be very similar. 

Anyway you decide for yourself. I have bad memories about QTreeWidget 
(though they are fading). 
 

> p.moveToVisNext is pretty slow, but not slow enough to be dangerous.  
> Trying to optimize it might require a lot of code when expanding and 
> contracting a node.
>

They are fast enough to draw once the drawing starts, but they take their 
time while skipping invisible nodes (nodes that would be visible in large 
enough screen).
 

I have been wondering whether "stable" positions might be added to Leo's 
> existing data model. Can you point to some documentation?
>
 
The fragile position parts are integer index of vnode and int indexes in 
their stacks. If you add a dictionary to each node that maps child 
addresses (for example letters) to child nodes then position can put that 
address (letter) into its stack and its childIndex field. Accessing child 
nodes then would be two step process instead of just one. First you convert 
index into address (a letter) and then that address into a child node. That 
is little more work, but positions would become more immune to the tree 
modifications. At some point I was thinking about this idea to use letters 
or short strings to point to the child nodes. It is like UNL with indexes, 
but much shorter and faster to calculate. This approach would require some 
more work to keep those addresses in sync with the actual content of the 
"children" field. Every time this field is adjusted it needs to update this 
lookup dictionary.

class Vnode:
    def __init__(self, ...):
        ...
        self.a2v = {}
        self.address_list = []
        self._addrcounter = 0

    def new_free_address(self):
        self._addrcounter += 1
        return '%x'%self._addrcounter

    def _addLink(self, childIndex, parent_v):
        v = self
        ...
        # at the end
        myaddr = parent_v.new_free_address()
        parent_v.children.insert(childIndex, v)
        parent_v.address_list.insert(childIndex, v)
        parent_v.a2v[myaddr] = v

    def _cutLink(self, childIndex, parent_v):
        v = self
        ...
        # at the end
        myaddr = parent_v.address_list[childIndex]
        del parent_v.address_list[childIndex]
        del parent_v.a2v[myaddr]
To access child node by index one needs to get the address of this child (addr 
= v.address_list[i]) and then to reach the node  (child = v.a2v[addr]) 
That is more work to get to the child node, but positions can be fully 
defined by the string that is concatenation of all the addresses along the 
path to the vnode.
That string can become an immutable id of the position.

parent position id is just p.full_address.rpartition(sep)[0]

id of the position of child at the address a is just p.full_address + sep + 
a

And the real index of the position is just 
p._parentVnode().address_list.index(p.full_address.rpartition(sep)[2])
But I guess most of the time it won't be necessary to calculate this index 
at all. Just operate with the addresses.

HTH

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 leo-editor+unsubscr...@googlegroups.com.
To post to this group, send email to leo-editor@googlegroups.com.
Visit this group at https://groups.google.com/group/leo-editor.
For more options, visit https://groups.google.com/d/optout.

Reply via email to