File indexing completed on 2024-05-12 16:23:27
0001 /*************************************************************************** 0002 * Copyright (C) 2013 by Linuxstopmotion contributors; * 0003 * see the AUTHORS file for details. * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the * 0017 * Free Software Foundation, Inc., * 0018 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 0019 ***************************************************************************/ 0020 0021 #include "command.h" 0022 #include "../filenamevisitor.h" 0023 #include "undoredoobserver.h" 0024 0025 #include <list> 0026 #include <stdint.h> 0027 0028 // help out Eclipse's C++ parsing 0029 #ifndef INT32_MAX 0030 #define INT32_MAX 0x7FFFFFFF 0031 #endif 0032 0033 /** 0034 * Command list, for example the Undo or Redo stack. 0035 */ 0036 class CommandList { 0037 typedef std::list<Command*> clist; 0038 clist cs; 0039 public: 0040 /** 0041 * Construct a NullAdder on the stack to be able to use FillNull() to add 0042 * a command to the command list without the risk of an exception being 0043 * thrown. 0044 */ 0045 class NullAdder { 0046 CommandList& cl; 0047 NullAdder(const NullAdder&); 0048 NullAdder& operator=(const NullAdder&); 0049 public: 0050 NullAdder(CommandList& c) : cl(c) { 0051 cl.cs.push_front(0); 0052 } 0053 ~NullAdder() { 0054 if (!cl.cs.front()) 0055 cl.cs.pop_front(); 0056 } 0057 }; 0058 friend class NullAdder; 0059 CommandList() { 0060 } 0061 ~CommandList() { 0062 clear(); 0063 } 0064 /** 0065 * Removes all commands from the list 0066 */ 0067 void clear() { 0068 for (clist::iterator i = cs.begin(); i != cs.end(); ++i) { 0069 delete *i; 0070 } 0071 cs.clear(); 0072 } 0073 /** 0074 * Returns true if and only if the command list is empty. 0075 */ 0076 bool empty() const { 0077 return cs.empty(); 0078 } 0079 /** 0080 * Returns the command at the front of the list 0081 */ 0082 Command& front() const { 0083 return *cs.front(); 0084 } 0085 /** 0086 * Adds a command to the front of the list. 0087 */ 0088 void push(Command& c) { 0089 cs.push_front(&c); 0090 } 0091 /** 0092 * Adds a command to the back of the list. 0093 */ 0094 void add(Command& c) { 0095 cs.push_back(&c); 0096 } 0097 /** 0098 * Fills a previously-added null with c. There must be no calls to 0099 * Push, Pop, Splice or Clear in between the construction of NullAdder and 0100 * FillNull. Will not throw an exception. 0101 */ 0102 void fillNull(Command& c) { 0103 cs.front() = &c; 0104 } 0105 /** 0106 * Splices in the commands from the list newCommands into the front of 0107 * the list. This function will not throw an exception. newCommands 0108 * will be empty after this call. 0109 */ 0110 void splice(CommandList& newCommands) { 0111 cs.splice(cs.begin(), newCommands.cs); 0112 } 0113 /** 0114 * Calls v.Add(f) for each filename f referenced by the commands in the 0115 * list. 0116 */ 0117 void accept(FileNameVisitor& v) const { 0118 for (clist::const_iterator i = cs.begin(); i != cs.end(); ++i) { 0119 (*i)->accept(v); 0120 } 0121 } 0122 /** 0123 * Returns true if there is exactly one command in the list, false 0124 * otherwise 0125 */ 0126 bool singleton() const { 0127 return cs.size() == 1; 0128 } 0129 /** 0130 * Executes the command at the front (if it exists) and puts its inverse 0131 * onto the front of 'to'. 0132 * @param to The list to receive the inverse command. 0133 */ 0134 void executeFront(CommandList& to); 0135 }; 0136 0137 void CommandList::executeFront(CommandList& to) { 0138 if (empty()) 0139 return; 0140 NullAdder na(to); 0141 Command* c = cs.front(); 0142 Command* inv = c->execute(); 0143 to.fillNull(*inv); 0144 // remove command c, which should have been deleted or recycled by 0145 // execute() 0146 cs.pop_front(); 0147 } 0148 0149 FileNameVisitor::~FileNameVisitor() { 0150 } 0151 0152 void FileNameVisitor::reportNewScene() { 0153 } 0154 0155 Command::Command() { 0156 } 0157 0158 Command::~Command() { 0159 } 0160 0161 void Command::accept(FileNameVisitor&) const { 0162 } 0163 0164 class CommandNull : public Command { 0165 public: 0166 Command* execute() { 0167 // a null command is its own inverse 0168 return this; 0169 } 0170 }; 0171 0172 Command* createNullCommand() { 0173 return new CommandNull; 0174 } 0175 0176 CommandFactory::~CommandFactory() { 0177 } 0178 0179 Parameters::~Parameters() { 0180 } 0181 0182 int32_t Parameters::getHowMany() { 0183 return getInteger(1, INT32_MAX); 0184 } 0185 0186 CommandHistory::CommandHistory() : past(0), future(0), observer(0), 0187 previousCanUndo(false), previousCanRedo(false) { 0188 past = new CommandList(); 0189 future = new CommandList(); 0190 } 0191 0192 CommandHistory::~CommandHistory() { 0193 delete past; 0194 delete future; 0195 } 0196 0197 bool CommandHistory::canUndo() const { 0198 return !past->empty(); 0199 } 0200 0201 bool CommandHistory::canRedo() const { 0202 return !future->empty(); 0203 } 0204 0205 void CommandHistory::undo() { 0206 past->executeFront(*future); 0207 notifyObserver(); 0208 } 0209 0210 void CommandHistory::redo() { 0211 future->executeFront(*past); 0212 notifyObserver(); 0213 } 0214 0215 void CommandHistory::execute(Command& c) { 0216 future->clear(); 0217 future->push(c); 0218 redo(); 0219 notifyObserver(); 0220 } 0221 0222 void CommandHistory::clear() { 0223 future->clear(); 0224 past->clear(); 0225 notifyObserver(); 0226 } 0227 0228 void CommandHistory::accept(FileNameVisitor& v) const { 0229 future->accept(v); 0230 past->accept(v); 0231 } 0232 0233 void CommandHistory::setUndoRedoObserver(UndoRedoObserver* ob) { 0234 observer = ob; 0235 } 0236 0237 void CommandHistory::notifyObserver() { 0238 bool cu = canUndo(); 0239 if (cu != previousCanUndo) { 0240 previousCanUndo = cu; 0241 if (observer) 0242 observer->updateCanUndo(cu); 0243 } 0244 bool cr = canRedo(); 0245 if (cr != previousCanRedo) { 0246 previousCanRedo = cr; 0247 if (observer) 0248 observer->updateCanRedo(cr); 0249 } 0250 }