![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 #include "Command.h" 00002 00003 // The maximum amount of undo history saved by the command invoker 00004 const int MAX_UNDO_COUNT = 100; 00005 00009 CompositeCommand::~CompositeCommand() 00010 { 00011 //we must delete all child commands when this is being deleted 00012 FOREACH(iter, std::list<ICommand*>, _commands) 00013 delete *iter; 00014 } 00015 00019 void CompositeCommand::addCommand(ICommand* command) 00020 { 00021 _commands.push_back(command); 00022 } 00023 00027 bool CompositeCommand::isCumulative(ICommand* command) 00028 { 00029 //the command must be a composite 00030 CompositeCommand* cmd = dynamic_cast<CompositeCommand*>(command); 00031 if(cmd == NULL) 00032 return false; 00033 00034 //it must contain the same number of commands 00035 if(cmd->_commands.size() != _commands.size()) 00036 return false; 00037 00038 //each command must be equivalent to its matching command 00039 std::list<ICommand*>::const_iterator myIter = _commands.begin(); 00040 std::list<ICommand*>::const_iterator theirIter = cmd->_commands.begin(); 00041 while(myIter != _commands.end()) 00042 { 00043 //if they do not match, reject 00044 if(!((*myIter)->isCumulative(*theirIter))) 00045 return false; 00046 //otherwise move on 00047 ++myIter; 00048 ++theirIter; 00049 } 00050 00051 //if all of the above is met, they must be cumulative 00052 return true; 00053 } 00054 00058 void CompositeCommand::executeCumulative(ICommand* command) 00059 { 00060 CompositeCommand* cmd = dynamic_cast<CompositeCommand*>(command); 00061 00062 //go through all the commands between each composite 00063 std::list<ICommand*>::const_iterator myIter = _commands.begin(); 00064 std::list<ICommand*>::const_iterator theirIter = cmd->_commands.begin(); 00065 while(myIter != _commands.end()) 00066 { 00067 //apply from this object to the given objects 00068 (*myIter)->executeCumulative(*theirIter); 00069 ++myIter; 00070 ++theirIter; 00071 } 00072 } 00073 00078 void CompositeCommand::execute() 00079 { 00080 FOREACH(iter, std::list<ICommand*>, _commands) 00081 (*iter)->execute(); 00082 } 00083 00087 void CompositeCommand::undo() 00088 { 00089 FOREACH(iter, std::list<ICommand*>, _commands) 00090 (*iter)->undo(); 00091 } 00092 00097 void CommandInvoker::clearUndo() 00098 { 00099 FOREACH(iter, std::list<ICommand*>, _undoCommands) 00100 delete *iter; 00101 00102 _undoCommands.clear(); 00103 } 00104 00109 void CommandInvoker::clearRedo() 00110 { 00111 FOREACH(iter, std::list<ICommand*>, _redoCommands) 00112 delete *iter; 00113 00114 _redoCommands.clear(); 00115 } 00116 00121 void CommandInvoker::addCommandToUndo(ICommand* command) 00122 { 00123 //if undo is not enabled, then we cannot add this 00124 if(!_undoEnabled) 00125 return; 00126 00127 //add command to list 00128 _undoCommands.push_back(command); 00129 //if list is too long now, trim it down 00130 if(_undoCommands.size() > MAX_UNDO_COUNT) 00131 _undoCommands.pop_front(); 00132 } 00133 00137 CommandInvoker::CommandInvoker(): 00138 _undoEnabled(true), 00139 _redoEnabled(true) 00140 { 00141 } 00142 00146 CommandInvoker::~CommandInvoker() 00147 { 00148 clearUndo(); 00149 clearRedo(); 00150 } 00151 00155 ICommand* CommandInvoker::getLastCommand() 00156 { 00157 if(_undoCommands.size() > 0) 00158 return _undoCommands.back(); 00159 else 00160 return NULL; 00161 } 00162 00168 void CommandInvoker::submitCommand(ICommand* command) 00169 { 00170 //check if the command is cumulative 00171 if(command->isCumulative(getLastCommand())) 00172 { 00173 //if command is cumulative, then execute as cumulative 00174 //then delete because necessary state is now in last command 00175 command->executeCumulative(getLastCommand()); 00176 delete command; 00177 } 00178 else 00179 { 00180 //if command is non-cumulative, then execute and add to undo 00181 command->execute(); 00182 addCommandToUndo(command); 00183 } 00184 00185 //submitting a new command always invalidates redo 00186 clearRedo(); 00187 } 00188 00192 void CommandInvoker::undo() 00193 { 00194 //ensure there is a command to undo 00195 if(_undoCommands.size() == 0 || !_undoEnabled) 00196 return; 00197 00198 //get the last command 00199 ICommand* lastCommand = getLastCommand(); 00200 _undoCommands.pop_back(); 00201 00202 //undo the command 00203 lastCommand->undo(); 00204 00205 //save to redo list 00206 if(_redoEnabled) 00207 _redoCommands.push_back(lastCommand); 00208 } 00209 00213 void CommandInvoker::redo() 00214 { 00215 //ensure there is a command to redo 00216 if(_redoCommands.size() == 0 || !_redoEnabled) 00217 return; 00218 00219 // Get the last command from the list 00220 ICommand* lastCommandUndone = _redoCommands.back(); 00221 _redoCommands.pop_back(); 00222 00223 //execute it 00224 lastCommandUndone->execute(); 00225 00226 //then put it back on the undo list 00227 addCommandToUndo(lastCommandUndone); 00228 } 00229 00233 bool CommandInvoker::isUndoAvailable() 00234 { 00235 return _undoCommands.size() != 0; 00236 } 00237 00241 bool CommandInvoker::isRedoAvailable() 00242 { 00243 return _redoCommands.size() != 0; 00244 } 00245 00250 void CommandInvoker::setUndoEnabled(bool enabled) 00251 { 00252 _undoEnabled = enabled; 00253 if(!_undoEnabled) 00254 clearUndo(); 00255 } 00256 00261 void CommandInvoker::setRedoEnabled(bool enabled) 00262 { 00263 _redoEnabled = enabled; 00264 if(!_redoEnabled) 00265 clearRedo(); 00266 }
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.