Shadowrun: Awakened 29 September 2011 - Build 871
Command.cpp
Go to the documentation of this file.
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.

GNU Lesser General Public License 3 Sourceforge.net