For several years now, Vitalije has rightly complained that copied positions can become invalid when the outline changes.
Just now, after a bicycle ride, I saw what seemed at first to be an elegant solution, namely p.cloned_positions. This would be a list of copied positions that Leo will automatically update when the original position changes. This would be easy to do. All the Position methods that change a position p would update the positions in p.cloned_positions.
Hmm. Instead of copying and updating, why not just use the "original" position? Ah. I see the problem. The position p1 that Leo updates might be equal to another position, p2, but p1.cloned_positions will likely be empty, no matter what p2.cloned_positions is. This problem probably dooms p.cloned_positions.
Instead, it looks like we need a global list, say c.cloned_positions. This will be a list of copied positions that must be kept in sync with any change to positions that are equal to any position p_i in c.cloned_positions. This approach looking promising.
Suppose, we simply change p.copy so that it updates c.cloned_positions. Now, copied positions might "just work". That is, all copied positions will automagically remain in sync, no matter what happens to the outline!
What about deleted nodes and their corresponding positions?
Because of undo, no outline node ever is completed deleted. So what happens when a node (and its associated positions) gets re-inserted into the outline as the result of an undo/redo operation? The undo/redo code will likely have to handle this explicitly as follows: Whenever undo/redo deletes one or more nodes, it will have to remember the corresponding positions in the undo info (the undo "bead"), just before deleting the positions from c.cloned_position. When these nodes come back to life, the corresponding positions must be added again to c.cloned_positions.
Hmm. When undo/redo deletes a node(tree) the corresponding Position method might be able to do the housekeeping chores. Ditto for when undo/redo re-inserts a node (tree). But I have a bad feeling about this. Just putting deleted positions on, say, c.deleted_cloned_positions doesn't seem like it retains enough data. This scheme probably has the wrong granularity. In contrast, remembering deleted positions in undo beads looks bullet proof, if a bit clumsy.
Summary
This post has discussed a straightforward way to make all copied positions robust. p.cloned_positions won't work, but a global, c.cloned_positions probably will work.
undo/redo is likely the acid test. The code must be rock solid.
To be investigated:
- Performance issues, including the typical size of c.cloned_positions.
- The proper way to bring cloned positions back from the grave.
Edward