📄 rs_undo.cpp
字号:
/****************************************************************************** $Id: rs_undo.cpp 1938 2004-12-09 23:09:53Z andrew $**** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.**** This file is part of the qcadlib Library project.**** This file may be distributed and/or modified under the terms of the** GNU General Public License version 2 as published by the Free Software** Foundation and appearing in the file LICENSE.GPL included in the** packaging of this file.**** Licensees holding valid qcadlib Professional Edition licenses may use ** this file in accordance with the qcadlib Commercial License** Agreement provided with the Software.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.**** See http://www.ribbonsoft.com for further details.**** Contact info@ribbonsoft.com if any conditions of this licensing are** not clear to you.************************************************************************/#include "rs_undo.h"/** * Default constructor. */RS_Undo::RS_Undo() { undoList.setAutoDelete(true); undoPointer = -1; currentCycle = NULL;}/** * @return Number of Cycles that can be undone. */int RS_Undo::countUndoCycles() { RS_DEBUG->print("RS_Undo::countUndoCycles"); return undoPointer+1;}/** * @return Number of Cycles that can be redone. */int RS_Undo::countRedoCycles() { RS_DEBUG->print("RS_Undo::countRedoCycles"); return (int)undoList.count()-1-undoPointer;}/** * Adds an Undo Cycle at the current position in the list. * All Cycles after the new one are removed and the Undoabels * on them deleted. */void RS_Undo::addUndoCycle(RS_UndoCycle* i) { RS_DEBUG->print("RS_Undo::addUndoCycle"); undoList.insert(++undoPointer, i); RS_DEBUG->print("RS_Undo::addUndoCycle: ok");}/** * Starts a new cycle for one undo step. Every undoable that is * added after calling this method goes into this cycle. */void RS_Undo::startUndoCycle() { RS_DEBUG->print("RS_Undo::startUndoCycle"); // definitely delete Undo Cycles and all Undoables in them // that cannot be redone now: while ((int)undoList.count()>undoPointer+1 && (int)undoList.count()>0) { RS_UndoCycle* l = undoList.last(); if (l!=NULL) { RS_Undoable* u=NULL; bool done = false; do { u = l->getFirstUndoable(); if (u!=NULL) { // Remove the pointer from _all_ cycles: for (RS_UndoCycle* l2=undoList.first(); l2!=NULL; l2=undoList.next()) { l2->removeUndoable(u); } // Delete the Undoable for good: if (u->isUndone()) { removeUndoable(u); } } else { done = true; } } while(!done); } // Remove obsolete undo cycles: undoList.removeLast(); } currentCycle = new RS_UndoCycle();}/** * Adds an undoable to the current undo cycle. */void RS_Undo::addUndoable(RS_Undoable* u) { RS_DEBUG->print("RS_Undo::addUndoable"); if (currentCycle!=NULL) { currentCycle->addUndoable(u); } else { RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Undo::addUndoable(): No undo cycle active."); }}/** * Ends the current undo cycle. */void RS_Undo::endUndoCycle() { addUndoCycle(currentCycle); currentCycle = NULL;}/** * Undoes the last undo cycle. */void RS_Undo::undo() { RS_DEBUG->print("RS_Undo::undo"); if (undoPointer>=0) { RS_UndoCycle* i = undoList.at(undoPointer); if (i!=NULL) { for (RS_Undoable* u=i->undoables.first(); u!=NULL; u=i->undoables.next()) { u->changeUndoState(); } undoPointer--; } }}/** * Redoes the undo cycle which was at last undone. */void RS_Undo::redo() { RS_DEBUG->print("RS_Undo::redo"); if (undoPointer+1<(int)undoList.count()) { undoPointer++; RS_UndoCycle* i = undoList.at(undoPointer); if (i!=NULL) { for (RS_Undoable* u=i->undoables.first(); u!=NULL; u=i->undoables.next()) { u->changeUndoState(); } } }}/** * @return The undo item that is next if we're about to undo * or NULL. */RS_UndoCycle* RS_Undo::getUndoCycle() { RS_UndoCycle* ret = NULL; RS_DEBUG->print("RS_Undo::getUndoCycle"); if (undoPointer>=0 && undoPointer<(int)undoList.count()) { ret = undoList.at(undoPointer); } RS_DEBUG->print("RS_Undo::getUndoCycle: OK"); return ret;}/** * @return The redo item that is next if we're about to redo * or NULL. */RS_UndoCycle* RS_Undo::getRedoCycle() { RS_DEBUG->print("RS_Undo::getRedoCycle"); if (undoPointer+1>=0 && undoPointer+1<(int)undoList.count()) { return undoList.at(undoPointer+1); } return NULL;}/** * Dumps the undo list to stdout. */std::ostream& operator << (std::ostream& os, RS_Undo& l) { os << "Undo List: " << "\n"; os << " Pointer is at: " << l.undoPointer << "\n"; for (RS_UndoCycle* i = l.undoList.first(); i!=NULL; i = l.undoList.next()) { if (l.undoList.at()==l.undoPointer) { os << " -->"; } else { os << " "; } os << *i << "\n"; } return os;}/** * Testing Undoables, Undo Cycles and the Undo container. */#ifdef RS_TESTbool RS_Undo::test() { int i, k; RS_UndoStub undo; //RS_UndoCycle* c1; RS_Undoable* u1; std::cout << "Testing RS_Undo\n"; std::cout << " Adding 500 cycles.."; // Add 500 Undo Cycles with i Undoables in every Cycle for (i=1; i<=500; ++i) { //c1 = new RS_UndoCycle(); undo.startUndoCycle(); for (k=1; k<=i; ++k) { u1 = new RS_Undoable(); //c1-> undo.addUndoable(u1); } //undo.addUndoCycle(c1); undo.endUndoCycle(); } std::cout << "OK\n"; assert(undo.countUndoCycles()==500); assert(undo.countRedoCycles()==0); std::cout << " Undo 500 cycles.."; // Undo all 500 cycles for (i=1; i<=500; ++i) { undo.undo(); } std::cout << "OK\n"; assert(undo.countUndoCycles()==0); assert(undo.countRedoCycles()==500); std::cout << " Redo 500 cycles.."; // Redo all 500 cycles for (i=1; i<=500; ++i) { undo.redo(); } std::cout << "OK\n"; assert(undo.countUndoCycles()==500); assert(undo.countRedoCycles()==0); std::cout << " Undo 250 cycles.."; // Undo all 500 cycles for (i=1; i<=250; ++i) { undo.undo(); } std::cout << "OK\n"; assert(undo.countUndoCycles()==250); assert(undo.countRedoCycles()==250); std::cout << " Adding 10 cycles.."; for (i=1; i<=10; ++i) { //c1 = new RS_UndoCycle(); undo.startUndoCycle(); for (k=1; k<=10; ++k) { u1 = new RS_Undoable(); //c1->addUndoable(u1); undo.addUndoable(u1); } //undo.addUndoCycle(c1); undo.endUndoCycle(); } std::cout << "OK\n"; assert(undo.countUndoCycles()==260); assert(undo.countRedoCycles()==0); std::cout << " Undo 5 cycles.."; for (i=1; i<=5; ++i) { undo.undo(); } std::cout << "OK\n"; assert(undo.countUndoCycles()==255); assert(undo.countRedoCycles()==5); std::cout << " Redo 5 cycles.."; for (i=1; i<=5; ++i) { undo.redo(); } std::cout << "OK\n"; assert(undo.countUndoCycles()==260); assert(undo.countRedoCycles()==0); std::cout << " Undo 15 cycles.."; for (i=1; i<=15; ++i) { undo.undo(); } std::cout << "OK\n"; assert(undo.countUndoCycles()==245); assert(undo.countRedoCycles()==15); std::cout << " Adding 1 cycle.."; for (i=1; i<=1; ++i) { //c1 = new RS_UndoCycle(); undo.startUndoCycle(); for (k=1; k<=10; ++k) { u1 = new RS_Undoable(); //c1->addUndoable(u1); undo.addUndoable(u1); } //undo.addUndoCycle(c1); undo.endUndoCycle(); } std::cout << "OK\n"; assert(undo.countUndoCycles()==246); assert(undo.countRedoCycles()==0); return true;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -