root/gaphor/tags/gaphor-0.12.3/doc/undo.txt

Revision 1202, 4.6 kB (checked in by arj..@yirdis.nl, 2 years ago)

New version tag: 0.10.2

Line 
1
2
3 UndoManager
4 ==========
5
6 Fine grained undo: undo specific properties.
7
8 Add undo-operation, e.g. Item.request_update() should be executed as
9 part of an undo action. Such actions are normally called after the properties
10 have been set right though. This is not a problem for idle tasks, but for
11 directly executed tasks it is.
12
13 Should only need to save the originals, values calculated, e.g. during an
14 update shouldn't have to be calculated -> use undo-operations to trigger
15 updates.
16
17 To update:
18
19   Handle:
20     x, y (solvable)
21     connectable (attr)
22     visible (attr)
23     movable (attr)
24     connection status (solver?)
25
26   Item:
27     matrix
28     canvas is managed from Canvas
29
30     Element:
31       handles
32       width, height
33       min_width, min_height (solvable?)
34
35     Line:
36       handles
37       line_width
38       fuzzyness (attr)
39       orthogonal (boolean)
40       horizontal (boolean)
41       split_segment()
42       merge_segment()
43
44   Canvas:
45     tree:
46       add()
47       remove()
48     request_update() (should be performed as part of undo action when called)
49
50   Solver (?):
51     add_constraint()
52     remove_constraint()
53     Variable state
54
55 In Gaphor, connecting two diagram items is considered an atomic task,
56 performed by a IConnect adapter. This operation results in a set of primitive
57 tasks (properties set and a constraint created).
58
59 For methods, it should be possible to create a decorator (@reversible) that
60 schedules a method with the same signature as the calling operation, but with
61 the inverse effect (e.g. the gaphas.tree module):
62
63   Tree(object):
64
65     @reversable(lambda s, n, p: s.remove(n))
66     def add(self, node, parent=None):
67         ... add
68
69     @reversable(add, self='self', node='node', parent='self.get_parent(node)')
70     def remove(self, node):
71         ... remove
72
73 Okay, so the second case is tougher...
74  
75  
76 So what we did:
77 Add a StateManager to gaphas. All changed are send to the statemanager.
78 Gaphor should implement it's own state manager.
79   + all state changes can easily be recorded
80   + fix it in one place
81   + reusable throughout Gaphas and subtypes.
82
83
84 Transactions
85 ============
86
87 Gaphor's Undo manager works transactional. Typically, methods can be
88 decorated with @transactional and undo data is stored in the current
89 transaction. A new tx is created when none exists.
90
91 Although undo functionality is at the core of Gaphor (diagram items and
92 model elements have been adapted to provide proper undo information), the
93 UndoManager itself is just a service.
94
95 Transaction support though is a real core functionality. By letting elements
96 and items emit event notifications on important changed other (yet to be
97 defined) services can take benefit of those events. The UML module already
98 works this way. Gaphas (the Gaphor canvas) also emits state changes.
99
100 When state changes happen in model elements and diagram items an event is
101 emitted. Those events are handled by special handlers that produce
102 "reverse-events". Reverse events are functions that perform exactly the
103 opposite operation. Those functions are stored in a list (which technically is
104 the Transaction). When an undo request is done the list is executed in LIFO
105 order.
106
107 To start a transaction:
108
109   1. A Transaction object has been created.
110   2. This results in the emission of a TransactionBegin event.
111   3. The TransactionBegin event is a trigger for the UndoManager to start
112      listening for IUndoEvent actions.
113
114 Now, that should be done when a model element or diagram item sends a state
115 change:
116
117   1. The event is handled by the "reverse-handler"
118   2. Reverse handler generates a IUndoEvent signal
119   3. The signal is received and stored as part of the undo-transaction.
120
121 (Maybe step 2 and 3 can be merged, since only one function is not of any
122 interest to the rest of the application - creates nasty dependencies)
123
124 If nested transaction are created a simple counter is incremented.
125
126 When the topmost Transaction is committed:
127
128   1. A TransactionCommit event is emitted
129   2. This triggers the UndoManager to close and store the transaction.
130
131 When a transaction is rolled back:
132  
133   1. The main transaction is marked for rollback
134   2. When the toplevel tx is rolled back or commited a
135      TransactionRollback event is emitted
136   2. This triggers the UndoManager to play back all recorded actions and
137      stop listening.
138
139
140 References
141 ==========
142
143 A Framework for Undoing Actions in Collaborative Systems
144   http://www.eecs.umich.edu/~aprakash/papers/undo-tochi94.pdf
145 Undoing Actions in Collaborative Work: Framework and Experience
146   https://www.eecs.umich.edu/techreports/cse/94/CSE-TR-196-94.pdf
147
148 Implementing a Selective Undo Framework in Python
149   http://www.python.org/workshops/1997-10/proceedings/zukowski.html
150
151
Note: See TracBrowser for help on using the browser.