| 59 | | For methods, it should be possible to create a decorator (@reversable) 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): |
|---|
| | 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): |
|---|
| 76 | | We have three options: |
|---|
| 77 | | |
|---|
| 78 | | 1. Add a StateManager to gaphas. All changed are send to the statemanager. |
|---|
| 79 | | Gaphor should implement it's own state manager. |
|---|
| 80 | | + all state changes can easely be recorded |
|---|
| 81 | | + fix it in one place |
|---|
| 82 | | + reusable thoughout Gaphas and subtypes. |
|---|
| 83 | | ? does this solve undo-problems for other applications too? |
|---|
| 84 | | |
|---|
| 85 | | 2. Override all attrs and properties, decorate the method from a special |
|---|
| 86 | | update script at runtime. |
|---|
| 87 | | + keeps Gaphas' code clean, less complicated |
|---|
| 88 | | - it's not clear what happens |
|---|
| 89 | | - users require some sort of state recording/undo mechanism anyway |
|---|
| 90 | | |
|---|
| 91 | | 3. Why not use Tools? |
|---|
| 92 | | - Lot's of interaction can be achieved though menu items or other |
|---|
| 93 | | programmatic actions. |
|---|
| | 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. |
|---|
| 96 | | References: |
|---|
| | 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 | ========== |
|---|