1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.vectomatic.client.rep.command;
19
20 import java.util.ArrayList;
21 import java.util.List;
22
23 import org.vectomatic.client.rep.events.ICommandHistoryListener;
24
25
26
27
28
29
30
31
32 public class CommandHistory {
33
34
35
36 private ICommand[] _commands;
37
38
39
40
41
42 private int _first;
43
44
45
46
47
48 private int _last;
49
50
51
52
53
54
55
56
57 private int _current;
58
59
60
61
62 private List<ICommandHistoryListener> _listeners;
63
64
65
66
67 private ICommand _savePoint;
68
69
70
71
72
73
74 public CommandHistory(int capacity) {
75 if (capacity < 1) {
76 throw new IllegalArgumentException();
77 }
78 _commands = new ICommand[capacity];
79 _first = -1;
80 }
81
82
83
84
85
86
87
88 public boolean canUndo() {
89 return (_current > 0);
90 }
91
92
93
94
95
96
97
98 public boolean canRedo() {
99 if (_first == -1) {
100
101 return false;
102 }
103 int count = (_last >= _first) ? _last - _first + 1 : _commands.length - _first + _last + 1;
104 return (_current < count);
105 }
106
107
108
109
110 public void undo() {
111 if (!canUndo()) {
112 throw new IllegalStateException("Invalid undo");
113 }
114 getUndoCommand().unexecute();
115 _current--;
116 fireCommandHistoryChange();
117 }
118
119
120
121
122 public void redo() {
123 if (!canRedo()) {
124 throw new IllegalStateException("Invalid redo");
125 }
126 getRedoCommand().execute();
127 _current++;
128 fireCommandHistoryChange();
129 }
130
131
132
133
134
135 public void addCommand(ICommand command) {
136 if (_first == -1) {
137
138 _first = 0;
139 }
140
141
142 int count = (_last >= _first) ? _last - _first + 1 : _commands.length - _first + _last + 1;
143 for (int i = _current + 1; i < count; i++) {
144 int index = (_first + i) % _commands.length;
145 _commands[index] = null;
146 }
147
148
149 _last = (_current + _first) % _commands.length;
150 _commands[_last] = command;
151
152
153 if (_current == _commands.length) {
154 _first = (_first == _commands.length - 1) ? 0 : _first + 1;
155 } else {
156
157 _current++;
158 }
159 fireCommandHistoryChange();
160 }
161
162
163
164
165
166 public ICommand getUndoCommand() {
167 if (!canUndo()) {
168 return null;
169 }
170 int index = (_first + _current - 1) % _commands.length;
171 return _commands[index];
172 }
173
174
175
176
177
178 public ICommand getRedoCommand() {
179 if (!canRedo()) {
180 return null;
181 }
182 int index = (_first + _current) % _commands.length;
183 return _commands[index];
184 }
185
186
187
188
189
190 public ICommand[] getCommands() {
191 if (_first == -1) {
192
193 return new ICommand[0];
194 }
195 int count = (_last >= _first) ? _last - _first + 1 : _commands.length - _first + _last + 1;
196 ICommand[] commands = new ICommand[count];
197 for (int i = 0; i < count; i++) {
198 int index = (_first + i) % _commands.length;
199 commands[i] = _commands[index];
200 }
201 return commands;
202 }
203
204
205
206
207
208
209
210
211
212
213 public int getCurrentCommand() {
214 return _current;
215 }
216
217
218
219
220
221 public void purge() {
222 _current = _last = 0;
223 _first = -1;
224 for (int i = 0; i < _commands.length; i++) {
225 _commands[i] = null;
226 }
227 _savePoint = null;
228 fireCommandHistoryChange();
229 }
230
231
232
233
234
235
236
237
238 public void setCapacity(int capacity) {
239 if (_first == -1) {
240
241 _commands = new ICommand[capacity];
242 fireCommandHistoryChange();
243 return;
244 }
245 int count = (_last >= _first) ? _last - _first + 1 : _commands.length - _first + _last + 1;
246 if (capacity < count) {
247 int current = _current * capacity / count;
248 ICommand[] commands = new ICommand[capacity];
249 for (int i = 0; i < capacity; i++) {
250 int index = (_first + _current - current + i) % _commands.length;
251 commands[i] = _commands[index];
252 }
253 _commands = commands;
254 _first = 0;
255 _current = current;
256 _last = capacity - 1;
257 fireCommandHistoryChange();
258 } else if (capacity > count) {
259 ICommand[] commands = new ICommand[capacity];
260 for (int i = 0; i < count; i++) {
261 int index = (_first + i) % _commands.length;
262 commands[i] = _commands[index];
263 }
264 _commands = commands;
265 _first = 0;
266 _last = count - 1;
267 fireCommandHistoryChange();
268 }
269 }
270
271
272
273
274
275 public int getCapacity() {
276 return _commands.length;
277 }
278
279 public void addCommandHistoryListener(ICommandHistoryListener listener) {
280 if (_listeners == null) {
281 _listeners = new ArrayList<ICommandHistoryListener>();
282 }
283 _listeners.add(listener);
284 }
285
286 public void removeCommandHistoryListener(ICommandHistoryListener listener) {
287 if (_listeners != null) {
288 _listeners.remove(listener);
289 }
290 }
291
292 public void fireCommandHistoryChange() {
293 if (_listeners != null) {
294 for (int i = 0, size = _listeners.size(); i < size; i++) {
295 ICommandHistoryListener listener = _listeners.get(i);
296 listener.commandHistoryChange(this);
297 }
298 }
299 }
300
301 public void setSavePoint() {
302 _savePoint = (canUndo()) ? getUndoCommand() : null;
303
304 }
305
306 public boolean needsSaving() {
307 ICommand command = (canUndo()) ? getUndoCommand() : null;
308 return (command != _savePoint);
309 }
310
311 }
312