]> Shamusworld >> Repos - architektonas/blob - src/base/rs_undo.cpp
7ccad0871b5bbb1e21e0844d7a827876991157fc
[architektonas] / src / base / rs_undo.cpp
1
2 #include "rs_undo.h"
3
4 #include "rs_debug.h"
5 #include "rs_undoable.h"
6
7 /**
8  * Default constructor.
9  */
10 RS_Undo::RS_Undo()
11 {
12 #warning "!!! Need to deal with setAutoDelete() Qt3->Qt4 !!!"
13 //      undoList.setAutoDelete(true);
14         undoPointer = -1;
15         currentCycle = NULL;
16 }
17
18 /*virtual*/ RS_Undo::~RS_Undo()
19 {
20         while (!undoList.isEmpty())
21                 delete undoList.takeFirst();
22 }
23
24 /**
25  * @return Number of Cycles that can be undone.
26  */
27 int RS_Undo::countUndoCycles()
28 {
29         RS_DEBUG->print("RS_Undo::countUndoCycles");
30
31         return undoPointer + 1;
32 }
33
34 /**
35  * @return Number of Cycles that can be redone.
36  */
37 int RS_Undo::countRedoCycles()
38 {
39         RS_DEBUG->print("RS_Undo::countRedoCycles");
40
41         return (int)undoList.count() - 1 - undoPointer;
42 }
43
44 /**
45  * Adds an Undo Cycle at the current position in the list.
46  * All Cycles after the new one are removed and the Undoabels
47  * on them deleted.
48  */
49 void RS_Undo::addUndoCycle(RS_UndoCycle * i)
50 {
51         RS_DEBUG->print("RS_Undo::addUndoCycle");
52
53         undoList.insert(++undoPointer, i);
54
55         RS_DEBUG->print("RS_Undo::addUndoCycle: ok");
56 }
57
58 /**
59  * Starts a new cycle for one undo step. Every undoable that is
60  * added after calling this method goes into this cycle.
61  */
62 void RS_Undo::startUndoCycle()
63 {
64         RS_DEBUG->print("RS_Undo::startUndoCycle");
65
66         // definitely delete Undo Cycles and all Undoables in them
67         //   that cannot be redone now:
68         while ((int)undoList.count() > undoPointer + 1 && (int)undoList.count() > 0)
69         {
70                 RS_UndoCycle * l = undoList.last();
71
72                 if (l != NULL)
73                 {
74                         RS_Undoable * u = NULL;
75                         bool done = false;
76
77                         do
78                         {
79                                 u = l->getFirstUndoable();
80
81                                 if (u != NULL)
82                                 {
83                                         // Remove the pointer from _all_ cycles:
84 //                                      for(RS_UndoCycle * l2=undoList.first(); l2!=NULL; l2=undoList.next())
85 //                                              l2->removeUndoable(u);
86                                         for(int i=0; i<undoList.size(); i++)
87                                                 undoList[i]->removeUndoable(u);
88
89                                         // Delete the Undoable for good:
90                                         if (u->isUndone())
91                                         {
92                                                 removeUndoable(u);
93                                         }
94                                 }
95                                 else
96                                 {
97                                         done = true;
98                                 }
99                         }
100                         while(!done);
101                 }
102
103                 // Remove obsolete undo cycles:
104                 undoList.removeLast();
105         }
106
107         currentCycle = new RS_UndoCycle();
108 }
109
110 /**
111  * Adds an undoable to the current undo cycle.
112  */
113 void RS_Undo::addUndoable(RS_Undoable * u)
114 {
115         RS_DEBUG->print("RS_Undo::addUndoable");
116
117         if (currentCycle != NULL)
118         {
119                 currentCycle->addUndoable(u);
120         }
121         else
122         {
123                 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Undo::addUndoable(): No undo cycle active.");
124         }
125 }
126
127 /**
128  * Ends the current undo cycle.
129  */
130 void RS_Undo::endUndoCycle()
131 {
132         addUndoCycle(currentCycle);
133         currentCycle = NULL;
134 }
135
136 /**
137  * Undoes the last undo cycle.
138  */
139 void RS_Undo::undo()
140 {
141         RS_DEBUG->print("RS_Undo::undo");
142
143         if (undoPointer >= 0)
144         {
145                 RS_UndoCycle * i = undoList.at(undoPointer);
146
147                 if (i != NULL)
148                 {
149 //                      for(RS_Undoable * u=i->undoables.first(); u!=NULL; u=i->undoables.next())
150 //                              u->changeUndoState();
151                         for(int j=0; j<i->undoables.size(); j++)
152                                 i->undoables[j]->changeUndoState();
153
154                         undoPointer--;
155                 }
156         }
157 }
158
159 /**
160  * Redoes the undo cycle which was at last undone.
161  */
162 void RS_Undo::redo()
163 {
164         RS_DEBUG->print("RS_Undo::redo");
165
166         if (undoPointer + 1 < (int)undoList.count())
167         {
168                 undoPointer++;
169                 RS_UndoCycle * i = undoList.at(undoPointer);
170
171                 if (i != NULL)
172                 {
173 //            for(RS_Undoable * u=i->undoables.first(); u!=NULL; u=i->undoables.next())
174 //                u->changeUndoState();
175                         for(int j=0; j<i->undoables.size(); j++)
176                                 i->undoables[j]->changeUndoState();
177                 }
178         }
179 }
180
181 /**
182  * @return The undo item that is next if we're about to undo
183  * or NULL.
184  */
185 RS_UndoCycle * RS_Undo::getUndoCycle()
186 {
187         RS_UndoCycle * ret = NULL;
188
189         RS_DEBUG->print("RS_Undo::getUndoCycle");
190
191         if (undoPointer >= 0 && undoPointer < (int)undoList.count())
192                 ret = undoList.at(undoPointer);
193
194         RS_DEBUG->print("RS_Undo::getUndoCycle: OK");
195
196         return ret;
197 }
198
199 /**
200  * @return The redo item that is next if we're about to redo
201  * or NULL.
202  */
203 RS_UndoCycle * RS_Undo::getRedoCycle()
204 {
205         RS_DEBUG->print("RS_Undo::getRedoCycle");
206
207         if (undoPointer + 1 >= 0 && undoPointer + 1 < (int)undoList.count())
208                 return undoList.at(undoPointer + 1);
209
210         return NULL;
211 }
212
213 /**
214  * Dumps the undo list to stdout.
215  */
216 std::ostream & operator<<(std::ostream & os, RS_Undo & l)
217 {
218         os << "Undo List: " <<  "\n";
219         os << " Pointer is at: " << l.undoPointer << "\n";
220
221 //      for(RS_UndoCycle * i=l.undoList.first(); i!=NULL; i=l.undoList.next())
222         for(int j=0; j<l.undoList.size(); j++)
223         {
224                 RS_UndoCycle * i = l.undoList[j];
225
226 //              if (l.undoList.at() == l.undoPointer)
227                 if (j == l.undoPointer)
228                         os << " -->";
229                 else
230                         os << "    ";
231
232                 os << *i << "\n";
233         }
234
235         return os;
236 }
237
238 //huh? how is this getting defined???
239 #undef RS_TEST
240 #ifdef RS_TEST
241 /**
242  * Testing Undoables, Undo Cycles and the Undo container.
243  */
244 /*static*/ bool RS_Undo::test()
245 {
246         int i, k;
247         RS_UndoStub undo;
248         //RS_UndoCycle * c1;
249         RS_Undoable * u1;
250
251         std::cout << "Testing RS_Undo\n";
252         std::cout << "  Adding 500 cycles..";
253
254         // Add 500 Undo Cycles with i Undoables in every Cycle
255         for(i=1; i<=500; ++i)
256         {
257                 //c1 = new RS_UndoCycle();
258                 undo.startUndoCycle();
259
260                 for(k=1; k<=i; ++k)
261                 {
262                         u1 = new RS_Undoable();
263                         //c1->
264                         undo.addUndoable(u1);
265                 }
266
267                 //undo.addUndoCycle(c1);
268                 undo.endUndoCycle();
269         }
270
271         std::cout << "OK\n";
272
273         assert(undo.countUndoCycles() == 500);
274         assert(undo.countRedoCycles() == 0);
275
276         std::cout << "  Undo 500 cycles..";
277         // Undo all 500 cycles
278
279         for(i=1; i<=500; ++i)
280                 undo.undo();
281
282         std::cout << "OK\n";
283
284         assert(undo.countUndoCycles() == 0);
285         assert(undo.countRedoCycles() == 500);
286
287         std::cout << "  Redo 500 cycles..";
288         // Redo all 500 cycles
289
290         for(i=1; i<=500; ++i)
291                 undo.redo();
292
293         std::cout << "OK\n";
294
295         assert(undo.countUndoCycles() == 500);
296         assert(undo.countRedoCycles() == 0);
297
298         std::cout << "  Undo 250 cycles..";
299         // Undo all 500 cycles
300
301         for(i=1; i<=250; ++i)
302                 undo.undo();
303
304         std::cout << "OK\n";
305
306         assert(undo.countUndoCycles() == 250);
307         assert(undo.countRedoCycles() == 250);
308
309         std::cout << "  Adding 10 cycles..";
310
311         for(i=1; i<=10; ++i)
312         {
313                 //c1 = new RS_UndoCycle();
314                 undo.startUndoCycle();
315
316                 for(k=1; k<=10; ++k)
317                 {
318                         u1 = new RS_Undoable();
319                         //c1->addUndoable(u1);
320                         undo.addUndoable(u1);
321                 }
322
323                 //undo.addUndoCycle(c1);
324                 undo.endUndoCycle();
325         }
326
327         std::cout << "OK\n";
328
329         assert(undo.countUndoCycles() == 260);
330         assert(undo.countRedoCycles() == 0);
331
332         std::cout << "  Undo 5 cycles..";
333
334         for(i=1; i<=5; ++i)
335                 undo.undo();
336
337         std::cout << "OK\n";
338
339         assert(undo.countUndoCycles() == 255);
340         assert(undo.countRedoCycles() == 5);
341
342         std::cout << "  Redo 5 cycles..";
343
344         for(i=1; i<=5; ++i)
345                 undo.redo();
346
347         std::cout << "OK\n";
348
349         assert(undo.countUndoCycles() == 260);
350         assert(undo.countRedoCycles() == 0);
351
352         std::cout << "  Undo 15 cycles..";
353
354         for(i=1; i<=15; ++i)
355                 undo.undo();
356
357         std::cout << "OK\n";
358
359         assert(undo.countUndoCycles() == 245);
360         assert(undo.countRedoCycles() == 15);
361
362         std::cout << "  Adding 1 cycle..";
363
364         for(i=1; i<=1; ++i)
365         {
366                 //c1 = new RS_UndoCycle();
367                 undo.startUndoCycle();
368
369                 for(k=1; k<=10; ++k)
370                 {
371                         u1 = new RS_Undoable();
372                         //c1->addUndoable(u1);
373                         undo.addUndoable(u1);
374                 }
375
376                 //undo.addUndoCycle(c1);
377                 undo.endUndoCycle();
378         }
379
380         std::cout << "OK\n";
381
382         assert(undo.countUndoCycles() == 246);
383         assert(undo.countRedoCycles() == 0);
384
385         return true;
386 }
387 #endif