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 // (C) 2010 Underground Software
8 // JLH = James L. Hammons <jlhamm@acm.org>
11 // --- ---------- -----------------------------------------------------------
12 // JLH 06/02/2010 Added this text. :-)
18 #include "rs_undoable.h"
21 * Default constructor.
25 #warning "!!! Need to deal with setAutoDelete() Qt3->Qt4 !!!"
26 // undoList.setAutoDelete(true);
31 /*virtual*/ RS_Undo::~RS_Undo()
33 while (!undoList.isEmpty())
34 delete undoList.takeFirst();
38 * @return Number of Cycles that can be undone.
40 int RS_Undo::countUndoCycles()
42 RS_DEBUG->print("RS_Undo::countUndoCycles");
44 return undoPointer + 1;
48 * @return Number of Cycles that can be redone.
50 int RS_Undo::countRedoCycles()
52 RS_DEBUG->print("RS_Undo::countRedoCycles");
54 return (int)undoList.count() - 1 - undoPointer;
58 * Adds an Undo Cycle at the current position in the list.
59 * All Cycles after the new one are removed and the Undoabels
62 void RS_Undo::addUndoCycle(RS_UndoCycle * i)
64 RS_DEBUG->print("RS_Undo::addUndoCycle");
66 undoList.insert(++undoPointer, i);
68 RS_DEBUG->print("RS_Undo::addUndoCycle: ok");
72 * Starts a new cycle for one undo step. Every undoable that is
73 * added after calling this method goes into this cycle.
75 void RS_Undo::startUndoCycle()
77 RS_DEBUG->print("RS_Undo::startUndoCycle");
79 // definitely delete Undo Cycles and all Undoables in them
80 // that cannot be redone now:
81 while ((int)undoList.count() > undoPointer + 1 && (int)undoList.count() > 0)
83 RS_UndoCycle * l = undoList.last();
87 RS_Undoable * u = NULL;
92 u = l->getFirstUndoable();
96 // Remove the pointer from _all_ cycles:
97 // for(RS_UndoCycle * l2=undoList.first(); l2!=NULL; l2=undoList.next())
98 // l2->removeUndoable(u);
99 for(int i=0; i<undoList.size(); i++)
100 undoList[i]->removeUndoable(u);
102 // Delete the Undoable for good:
116 // Remove obsolete undo cycles:
117 undoList.removeLast();
120 currentCycle = new RS_UndoCycle();
124 * Adds an undoable to the current undo cycle.
126 void RS_Undo::addUndoable(RS_Undoable * u)
128 RS_DEBUG->print("RS_Undo::addUndoable");
130 if (currentCycle != NULL)
132 currentCycle->addUndoable(u);
136 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Undo::addUndoable(): No undo cycle active.");
141 * Ends the current undo cycle.
143 void RS_Undo::endUndoCycle()
145 addUndoCycle(currentCycle);
150 * Undoes the last undo cycle.
154 RS_DEBUG->print("RS_Undo::undo");
156 if (undoPointer >= 0)
158 RS_UndoCycle * i = undoList.at(undoPointer);
162 // for(RS_Undoable * u=i->undoables.first(); u!=NULL; u=i->undoables.next())
163 // u->changeUndoState();
164 for(int j=0; j<i->undoables.size(); j++)
165 i->undoables[j]->changeUndoState();
173 * Redoes the undo cycle which was at last undone.
177 RS_DEBUG->print("RS_Undo::redo");
179 if (undoPointer + 1 < (int)undoList.count())
182 RS_UndoCycle * i = undoList.at(undoPointer);
186 // for(RS_Undoable * u=i->undoables.first(); u!=NULL; u=i->undoables.next())
187 // u->changeUndoState();
188 for(int j=0; j<i->undoables.size(); j++)
189 i->undoables[j]->changeUndoState();
195 * @return The undo item that is next if we're about to undo
198 RS_UndoCycle * RS_Undo::getUndoCycle()
200 RS_UndoCycle * ret = NULL;
202 RS_DEBUG->print("RS_Undo::getUndoCycle");
204 if (undoPointer >= 0 && undoPointer < (int)undoList.count())
205 ret = undoList.at(undoPointer);
207 RS_DEBUG->print("RS_Undo::getUndoCycle: OK");
213 * @return The redo item that is next if we're about to redo
216 RS_UndoCycle * RS_Undo::getRedoCycle()
218 RS_DEBUG->print("RS_Undo::getRedoCycle");
220 if (undoPointer + 1 >= 0 && undoPointer + 1 < (int)undoList.count())
221 return undoList.at(undoPointer + 1);
227 * Dumps the undo list to stdout.
229 std::ostream & operator<<(std::ostream & os, RS_Undo & l)
231 os << "Undo List: " << "\n";
232 os << " Pointer is at: " << l.undoPointer << "\n";
234 // for(RS_UndoCycle * i=l.undoList.first(); i!=NULL; i=l.undoList.next())
235 for(int j=0; j<l.undoList.size(); j++)
237 RS_UndoCycle * i = l.undoList[j];
239 // if (l.undoList.at() == l.undoPointer)
240 if (j == l.undoPointer)
251 //huh? how is this getting defined???
255 * Testing Undoables, Undo Cycles and the Undo container.
257 /*static*/ bool RS_Undo::test()
264 std::cout << "Testing RS_Undo\n";
265 std::cout << " Adding 500 cycles..";
267 // Add 500 Undo Cycles with i Undoables in every Cycle
268 for(i=1; i<=500; ++i)
270 //c1 = new RS_UndoCycle();
271 undo.startUndoCycle();
275 u1 = new RS_Undoable();
277 undo.addUndoable(u1);
280 //undo.addUndoCycle(c1);
286 assert(undo.countUndoCycles() == 500);
287 assert(undo.countRedoCycles() == 0);
289 std::cout << " Undo 500 cycles..";
290 // Undo all 500 cycles
292 for(i=1; i<=500; ++i)
297 assert(undo.countUndoCycles() == 0);
298 assert(undo.countRedoCycles() == 500);
300 std::cout << " Redo 500 cycles..";
301 // Redo all 500 cycles
303 for(i=1; i<=500; ++i)
308 assert(undo.countUndoCycles() == 500);
309 assert(undo.countRedoCycles() == 0);
311 std::cout << " Undo 250 cycles..";
312 // Undo all 500 cycles
314 for(i=1; i<=250; ++i)
319 assert(undo.countUndoCycles() == 250);
320 assert(undo.countRedoCycles() == 250);
322 std::cout << " Adding 10 cycles..";
326 //c1 = new RS_UndoCycle();
327 undo.startUndoCycle();
331 u1 = new RS_Undoable();
332 //c1->addUndoable(u1);
333 undo.addUndoable(u1);
336 //undo.addUndoCycle(c1);
342 assert(undo.countUndoCycles() == 260);
343 assert(undo.countRedoCycles() == 0);
345 std::cout << " Undo 5 cycles..";
352 assert(undo.countUndoCycles() == 255);
353 assert(undo.countRedoCycles() == 5);
355 std::cout << " Redo 5 cycles..";
362 assert(undo.countUndoCycles() == 260);
363 assert(undo.countRedoCycles() == 0);
365 std::cout << " Undo 15 cycles..";
372 assert(undo.countUndoCycles() == 245);
373 assert(undo.countRedoCycles() == 15);
375 std::cout << " Adding 1 cycle..";
379 //c1 = new RS_UndoCycle();
380 undo.startUndoCycle();
384 u1 = new RS_Undoable();
385 //c1->addUndoable(u1);
386 undo.addUndoable(u1);
389 //undo.addUndoCycle(c1);
395 assert(undo.countUndoCycles() == 246);
396 assert(undo.countRedoCycles() == 0);