3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // Portions copyright (C) 2001-2003 RibbonSoft
7 // Copyright (C) 2010 Underground Software
8 // See the README and GPLv2 files for licensing and warranty information
10 // JLH = James L. Hammons <jlhamm@acm.org>
13 // --- ---------- -----------------------------------------------------------
14 // JLH 06/02/2010 Added this text. :-)
23 * Default constructor.
27 #warning "!!! Need to deal with setAutoDelete() Qt3->Qt4 !!!"
28 // undoList.setAutoDelete(true);
33 /*virtual*/ Undo::~Undo()
35 while (!undoList.isEmpty())
36 delete undoList.takeFirst();
40 * @return Number of Cycles that can be undone.
42 int Undo::countUndoCycles()
44 DEBUG->print("Undo::countUndoCycles");
46 return undoPointer + 1;
50 * @return Number of Cycles that can be redone.
52 int Undo::countRedoCycles()
54 DEBUG->print("Undo::countRedoCycles");
56 return (int)undoList.count() - 1 - undoPointer;
60 * Adds an Undo Cycle at the current position in the list.
61 * All Cycles after the new one are removed and the Undoabels
64 void Undo::addUndoCycle(UndoCycle * i)
66 DEBUG->print("Undo::addUndoCycle");
68 undoList.insert(++undoPointer, i);
70 DEBUG->print("Undo::addUndoCycle: ok");
74 * Starts a new cycle for one undo step. Every undoable that is
75 * added after calling this method goes into this cycle.
77 void Undo::startUndoCycle()
79 DEBUG->print("Undo::startUndoCycle");
81 // definitely delete Undo Cycles and all Undoables in them
82 // that cannot be redone now:
83 while ((int)undoList.count() > undoPointer + 1 && (int)undoList.count() > 0)
85 UndoCycle * l = undoList.last();
94 u = l->getFirstUndoable();
98 // Remove the pointer from _all_ cycles:
99 // for(UndoCycle * l2=undoList.first(); l2!=NULL; l2=undoList.next())
100 // l2->removeUndoable(u);
101 for(int i=0; i<undoList.size(); i++)
102 undoList[i]->removeUndoable(u);
104 // Delete the Undoable for good:
118 // Remove obsolete undo cycles:
119 undoList.removeLast();
122 currentCycle = new UndoCycle();
126 * Adds an undoable to the current undo cycle.
128 void Undo::addUndoable(Undoable * u)
130 DEBUG->print("Undo::addUndoable");
132 if (currentCycle != NULL)
134 currentCycle->addUndoable(u);
138 DEBUG->print(Debug::D_WARNING, "Undo::addUndoable(): No undo cycle active.");
143 * Ends the current undo cycle.
145 void Undo::endUndoCycle()
147 addUndoCycle(currentCycle);
152 * Undoes the last undo cycle.
156 DEBUG->print("Undo::undo");
158 if (undoPointer >= 0)
160 UndoCycle * i = undoList.at(undoPointer);
164 // for(Undoable * u=i->undoables.first(); u!=NULL; u=i->undoables.next())
165 // u->changeUndoState();
166 for(int j=0; j<i->undoables.size(); j++)
167 i->undoables[j]->changeUndoState();
175 * Redoes the undo cycle which was at last undone.
179 DEBUG->print("Undo::redo");
181 if (undoPointer + 1 < (int)undoList.count())
184 UndoCycle * i = undoList.at(undoPointer);
188 // for(Undoable * u=i->undoables.first(); u!=NULL; u=i->undoables.next())
189 // u->changeUndoState();
190 for(int j=0; j<i->undoables.size(); j++)
191 i->undoables[j]->changeUndoState();
197 * @return The undo item that is next if we're about to undo
200 UndoCycle * Undo::getUndoCycle()
202 UndoCycle * ret = NULL;
204 DEBUG->print("Undo::getUndoCycle");
206 if (undoPointer >= 0 && undoPointer < (int)undoList.count())
207 ret = undoList.at(undoPointer);
209 DEBUG->print("Undo::getUndoCycle: OK");
215 * @return The redo item that is next if we're about to redo
218 UndoCycle * Undo::getRedoCycle()
220 DEBUG->print("Undo::getRedoCycle");
222 if (undoPointer + 1 >= 0 && undoPointer + 1 < (int)undoList.count())
223 return undoList.at(undoPointer + 1);
229 * Dumps the undo list to stdout.
231 std::ostream & operator<<(std::ostream & os, Undo & l)
233 os << "Undo List: " << "\n";
234 os << " Pointer is at: " << l.undoPointer << "\n";
236 // for(UndoCycle * i=l.undoList.first(); i!=NULL; i=l.undoList.next())
237 for(int j=0; j<l.undoList.size(); j++)
239 UndoCycle * i = l.undoList[j];
241 // if (l.undoList.at() == l.undoPointer)
242 if (j == l.undoPointer)
253 //huh? how is this getting defined???
257 * Testing Undoables, Undo Cycles and the Undo container.
259 /*static*/ bool Undo::test()
266 std::cout << "Testing Undo\n";
267 std::cout << " Adding 500 cycles..";
269 // Add 500 Undo Cycles with i Undoables in every Cycle
270 for(i=1; i<=500; ++i)
272 //c1 = new UndoCycle();
273 undo.startUndoCycle();
279 undo.addUndoable(u1);
282 //undo.addUndoCycle(c1);
288 assert(undo.countUndoCycles() == 500);
289 assert(undo.countRedoCycles() == 0);
291 std::cout << " Undo 500 cycles..";
292 // Undo all 500 cycles
294 for(i=1; i<=500; ++i)
299 assert(undo.countUndoCycles() == 0);
300 assert(undo.countRedoCycles() == 500);
302 std::cout << " Redo 500 cycles..";
303 // Redo all 500 cycles
305 for(i=1; i<=500; ++i)
310 assert(undo.countUndoCycles() == 500);
311 assert(undo.countRedoCycles() == 0);
313 std::cout << " Undo 250 cycles..";
314 // Undo all 500 cycles
316 for(i=1; i<=250; ++i)
321 assert(undo.countUndoCycles() == 250);
322 assert(undo.countRedoCycles() == 250);
324 std::cout << " Adding 10 cycles..";
328 //c1 = new UndoCycle();
329 undo.startUndoCycle();
334 //c1->addUndoable(u1);
335 undo.addUndoable(u1);
338 //undo.addUndoCycle(c1);
344 assert(undo.countUndoCycles() == 260);
345 assert(undo.countRedoCycles() == 0);
347 std::cout << " Undo 5 cycles..";
354 assert(undo.countUndoCycles() == 255);
355 assert(undo.countRedoCycles() == 5);
357 std::cout << " Redo 5 cycles..";
364 assert(undo.countUndoCycles() == 260);
365 assert(undo.countRedoCycles() == 0);
367 std::cout << " Undo 15 cycles..";
374 assert(undo.countUndoCycles() == 245);
375 assert(undo.countRedoCycles() == 15);
377 std::cout << " Adding 1 cycle..";
381 //c1 = new UndoCycle();
382 undo.startUndoCycle();
387 //c1->addUndoable(u1);
388 undo.addUndoable(u1);
391 //undo.addUndoCycle(c1);
397 assert(undo.countUndoCycles() == 246);
398 assert(undo.countRedoCycles() == 0);