annotate undo_manager.d @ 25:8f58a8f88735

Checkpoint
author "David Bryant <bagnose@gmail.com>"
date Wed, 15 Jul 2009 23:49:02 +0930
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
25
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
1 module undo_manager;
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
2
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
3 class UndoManager : IUndoManager {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
4 this() {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
5 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
6
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
7 void addObserver(IUndoObserver observer) {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
8 _observers.add(observer);
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
9 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
10
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
11 void removeObserver(IUndoObserver observer) {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
12 _observers.remove(observer);
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
13 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
14
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
15 void reset() {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
16 assert(!inTransaction());
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
17 _past.clear();
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
18 _future.clear();
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
19 foreach(IUndoObserver obs; _observers) {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
20 obs.canUndo(false, "");
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
21 obs.canRedo(false, "");
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
22 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
23 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
24
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
25 void undo() {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
26 assert(canUndo());
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
27 Transaction t = _past.pop();
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
28 t.undo();
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
29 _future.push(t);
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
30 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
31
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
32 void redo() {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
33 assert(canRedo());
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
34 Transaction t = _future.pop();
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
35 t.redo();
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
36 _past.push(t);
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
37 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
38
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
39 bool canUndo() {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
40 assert(!inTransaction());
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
41 return !_past.empty();
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
42 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
43
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
44 bool canRedo() {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
45 assert(!inTransaction()) {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
46 return !_future.empty();
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
47 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
48 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
49
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
50 void beginTransaction(char[] description) {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
51 assert(!inTransaction());
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
52 _current_transaction = new Transaction(description);
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
53 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
54
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
55 void cancelTransaction() {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
56 assert(inTransaction());
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
57 _current_transaction.cancel();
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
58 _current_transaction = null;
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
59 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
60
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
61 void endTransaction() {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
62 assert(inTransaction());
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
63 _current_transaction.finalise();
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
64
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
65 if (!_future.empty()) {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
66 _future.clear();
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
67 foreach(IUndoObserver obs; _observers) {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
68 obs.canRedo(false, "");
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
69 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
70 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
71
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
72 _past.push(_current_transaction);
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
73
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
74 foreach(IUndoObserver obs; _observers) {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
75 bs.canUndo(true, _current_transaction.name());
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
76 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
77
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
78 _current_transaction = null;
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
79 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
80
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
81 // IUndoManager implementations:
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
82
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
83 void addAction(Action action) {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
84 assert(inTransaction());
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
85 _current_transaction.add(action);
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
86 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
87
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
88 private {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
89 bool inTransaction() {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
90 return _current_transaction !is null;
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
91 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
92
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
93 class Transaction {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
94 enum State {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
95 Accumulating,
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
96 Finalised,
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
97 Canceled
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
98 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
99
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
100 this(char[] description) {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
101 _description = description;
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
102 _state = Accumulating;
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
103 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
104
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
105 char[] description() {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
106 return _description;
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
107 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
108
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
109 void add(Action action) {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
110 assert(_state == State.Accumulating);
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
111 _actions.addTail(action);
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
112 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
113
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
114 void finalise() {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
115 assert(_state == State.Accumulating);
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
116 assert(!_actions.empty());
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
117 _finalised = true;
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
118 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
119
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
120 void cancel() {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
121 assert(_state == State.Accumulating);
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
122 foreachreverse(UndoAction ua; _actions) {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
123 ua.undo();
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
124 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
125 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
126
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
127 void redo() {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
128 assert(_finalised);
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
129 foreach (UndoAction ua; _actions) {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
130 ua.redo();
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
131 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
132 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
133
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
134 void undo() {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
135 assert(_finalised);
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
136 foreachreverse(UndoAction ua; _actions) {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
137 ua.undo();
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
138 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
139 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
140
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
141 private {
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
142 char[] _description;
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
143 List<Action> _actions;
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
144 State _state;
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
145 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
146 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
147
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
148 Transaction _current_transaction;
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
149 Stack!(Transaction) _past;
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
150 Stack!(Transaction) _future;
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
151 Set!(IUndoObserver) _observers;
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
152 }
8f58a8f88735 Checkpoint
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
153 }