Changeset fdd840
- Timestamp:
- Apr 8, 2010, 2:28:59 PM (15 years ago)
- Branches:
- Action_Thermostats, Add_AtomRandomPerturbation, Add_FitFragmentPartialChargesAction, Add_RotateAroundBondAction, Add_SelectAtomByNameAction, Added_ParseSaveFragmentResults, AddingActions_SaveParseParticleParameters, Adding_Graph_to_ChangeBondActions, Adding_MD_integration_tests, Adding_ParticleName_to_Atom, Adding_StructOpt_integration_tests, AtomFragments, Automaking_mpqc_open, AutomationFragmentation_failures, Candidate_v1.5.4, Candidate_v1.6.0, Candidate_v1.6.1, ChangeBugEmailaddress, ChangingTestPorts, ChemicalSpaceEvaluator, CombiningParticlePotentialParsing, Combining_Subpackages, Debian_Package_split, Debian_package_split_molecuildergui_only, Disabling_MemDebug, Docu_Python_wait, EmpiricalPotential_contain_HomologyGraph, EmpiricalPotential_contain_HomologyGraph_documentation, Enable_parallel_make_install, Enhance_userguide, Enhanced_StructuralOptimization, Enhanced_StructuralOptimization_continued, Example_ManyWaysToTranslateAtom, Exclude_Hydrogens_annealWithBondGraph, FitPartialCharges_GlobalError, Fix_BoundInBox_CenterInBox_MoleculeActions, Fix_ChargeSampling_PBC, Fix_ChronosMutex, Fix_FitPartialCharges, Fix_FitPotential_needs_atomicnumbers, Fix_ForceAnnealing, Fix_IndependentFragmentGrids, Fix_ParseParticles, Fix_ParseParticles_split_forward_backward_Actions, Fix_PopActions, Fix_QtFragmentList_sorted_selection, Fix_Restrictedkeyset_FragmentMolecule, Fix_StatusMsg, Fix_StepWorldTime_single_argument, Fix_Verbose_Codepatterns, Fix_fitting_potentials, Fixes, ForceAnnealing_goodresults, ForceAnnealing_oldresults, ForceAnnealing_tocheck, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_continued, ForceAnnealing_with_BondGraph_continued_betteresults, ForceAnnealing_with_BondGraph_contraction-expansion, FragmentAction_writes_AtomFragments, FragmentMolecule_checks_bonddegrees, GeometryObjects, Gui_Fixes, Gui_displays_atomic_force_velocity, ImplicitCharges, IndependentFragmentGrids, IndependentFragmentGrids_IndividualZeroInstances, IndependentFragmentGrids_IntegrationTest, IndependentFragmentGrids_Sole_NN_Calculation, JobMarket_RobustOnKillsSegFaults, JobMarket_StableWorkerPool, JobMarket_unresolvable_hostname_fix, MoreRobust_FragmentAutomation, ODR_violation_mpqc_open, PartialCharges_OrthogonalSummation, PdbParser_setsAtomName, PythonUI_with_named_parameters, QtGui_reactivate_TimeChanged_changes, Recreated_GuiChecks, Rewrite_FitPartialCharges, RotateToPrincipalAxisSystem_UndoRedo, SaturateAtoms_findBestMatching, SaturateAtoms_singleDegree, StoppableMakroAction, Subpackage_CodePatterns, Subpackage_JobMarket, Subpackage_LinearAlgebra, Subpackage_levmar, Subpackage_mpqc_open, Subpackage_vmg, Switchable_LogView, ThirdParty_MPQC_rebuilt_buildsystem, TrajectoryDependenant_MaxOrder, TremoloParser_IncreasedPrecision, TremoloParser_MultipleTimesteps, TremoloParser_setsAtomName, Ubuntu_1604_changes, stable
- Children:
- 82b71a
- Parents:
- 68d781 (diff), a295d1 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Location:
- src
- Files:
-
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Actions/Action.cpp
r68d781 rfdd840 34 34 35 35 void Action::call(){ 36 if(!isActive()){ 37 return; 38 } 36 39 // forward to private virtual 37 40 state_ptr state = performCall(); … … 53 56 return performRedo(_state); 54 57 } 58 59 60 bool Action::isActive(){ 61 return true; 62 } -
src/Actions/Action.hpp
r68d781 rfdd840 18 18 19 19 /** 20 * @file 21 * <H1> Action Howto </H1> 22 * 23 * <H2> Introduction </H2> 24 * 25 * Actions are used in object oriented design as a replacement for callback functions. 26 * In most ways Actions can be used in the same way that callbacks were used in non 27 * OO-Systems, but can contain support for several extra mechanism such as undo/redo 28 * or progress indicators. 29 * 30 * The main purpose of an action class is to contain small procedures, that can be repeatedly 31 * called. These procedures can also be stored, passed around, so that the execution of an 32 * action can happen quite far away from the place of creation. For a detailed description of 33 * the Action pattern see GOF:1996. 34 * 35 * <H3> How to use an action </H3> 36 * 37 * The process of using an action is as easy as calling the call() method of the action. The 38 * action will then do whatever it is supposed to do. If it is an action that can be undone, it 39 * will also register itself in the history to make itself available for undo. To undo the last 40 * action, you can either use the undoLast() method inside the ActionHistory class or call the 41 * UndoAction also provided by the ActionHistory. If an action was undone it will be available for 42 * redo, using the redoLast() method of the ActionHistory or the RedoAction also provided by this 43 * class. To check whether undo/redo is available at any moment you can use the hasUndo() or 44 * hasRedo() method respectively. 45 * 46 * Actions can be set to be active or inactive. If an action is set to inactive it is signaling, that 47 * some condition necessary for this action to be executed is not currently met. For example the 48 * UndoAction will set itself to inactive, when there is no action at that time that can be undone. 49 * Using call() on an inactive Action results in a no-op. You can query the state of an action using 50 * the isActive() method. 51 * 52 * The undo capabilities of actions come in three types as signaled by two boolean flags (one 53 * combination of these flags is left empty as can be seen later). 54 * <ul> 55 * <li/> The first flag indicates if the undo mechanism for this action should be considered at all, i.e. 56 * if the state of the application changes in a way that needs to be reverted. Actions that should 57 * consider the undo mechanism are for example adding a molecule, moving atoms, changing 58 * the name of a molecule etc. Changing the View-Area on the other hand should be an action that 59 * does not consider the undo mechanism. This flag can be queried using the shouldUndo() method. 60 * 61 * <li/> The second flag indicates whether the changes can be undo for this action. If this flag is true 62 * the action will be made available for undo using the ActionHistory class and the actions of this 63 * class. If this flag is false while the shoudlUndo() flag is true this means that this action 64 * changes the state of the application changes in a way that cannot be undone, but might cause 65 * the undo of previous actions to fail. In this case the whole History is cleared, as to keep 66 * the state of the application intact by avoiding dangerous undos. This flag can be queried 67 * using the canUndo() method. 68 *</ul> 69 * 70 * Each action has a name, that can be used to identify it throughout the run of the application. 71 * This name can be retrieved using the getName() method. Most actions also register themselves with 72 * a global structure, called the ActionRegistry. Actions that register themselves need to have a 73 * unique name for the whole application. If the name is known these actions can be retrieved from 74 * the registry by their name and then be used as normal. 75 * 76 * <H2> Building your own actions </H2> 77 * 78 * Building actions is fairly easy. Simply derive from the abstract Action base class and implement 79 * the virtual methods. The main code that needs to be executed upon call() should be implemented in 80 * the performCall() method. You should also indicate whether the action supports undo by implementing 81 * the shouldUndo() and canUndo() methods to return the appropriate flags. 82 * 83 * The constructor of your derived class also needs to call the Base constructor, passing it the 84 * name of the Action and a flag indicating whether this action should be made available in the 85 * registry. WARNING: Do not use the virtual getName() method of the derived action to provide the 86 * constructor with the name, even if you overloaded this method to return a constant. Doing this 87 * will most likely not do what you think it does (see: http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.5 88 * if you want to know why this wont work) 89 * 90 * <H3> Interfacing your Action with the Undo mechanism </H3> 91 * 92 * The performX() methods need to comply to a simple standard to allow for undo and redo. The first 93 * convention in this standard concerns the return type. All methods that handle calling, undoing 94 * or redoing return an object of Action::state_ptr. This is a smart pointer to a State object, that 95 * can be used to store state information that is needed by your action for later redo. A rename 96 * Action for example would need to store which object has been renamed and what the old name was. 97 * A move Action on the other hand would need to store the object that has been moved as well as the 98 * old position. If your Action does not need to store any kind of information for redo you can 99 * simply return Action::success and skip the rest of this paragraph. If your action has been 100 * abborted you can return Action::failure, which indicates to the history mechanism that this 101 * action should not be stored. 102 * 103 * If your Action needs any kind of information to undo its execution, you need to store this 104 * information in the state that is returned by the performCall() method. Since no assumptions 105 * can be made on the type or amount of information the ActionState base class is left empty. 106 * To use this class you need to derive a YourActionState class from the ActionState base class 107 * adding your data fields and accessor functions. Upon undo the ActionState object produced 108 * by the corresponding performCall() is then passed to the performUndo() method which should 109 * typecast the ActionState to the appropriate sub class, undo all the changes and produce 110 * a State object that can be used to redo the action if neccessary. This new state object is 111 * then used if the redo mechanism is invoked and passed to the performRedo() function, which 112 * again produces a State that can be used for performUndo(). 113 * 114 * <H3> Outline of the implementation of Actions </H3> 115 * 116 * To sum up the actions necessary to build actions here is a brief outline of things methioned 117 * in the last paragraphs: 118 * 119 * <H4> Basics </H4> 120 * 121 * <ul> 122 * <li/> derive YourAction from Action 123 * <li/> pass name and flag for registry to the base constructor 124 * <li/> implement performCall(), performUndo(), performRedo() 125 * <li/> implement the functions that return the flags for the undo mechanism 126 * <li/> Derive YourActionState from ActionState as necessary 127 * </ul> 128 * 129 * <H4> Implementing performX() methods </H4> 130 * 131 * <ul> 132 * <li/> performCall(): 133 * <ul> 134 * <li/> do whatever is needed to make the action work 135 * <li/> if the action was abborted return Action::failure 136 * <li/> if the action needs to save a state return a custom state object 137 * <li/> otherwise return Action::success 138 * </ul> 139 * <li/> performUndo(): 140 * <ul> 141 * <li/> typecast the ActionState pointer to a Pointer to YourActionState if necessary 142 * <li/> undo the action using the information from the state 143 * <li/> produce a new state that can be used for redoing and return it 144 * </ul> 145 * <li/> performRedo(): 146 * <ul> 147 * <li/> take the ActionState produced by performUndo and typecast it to a pointer to YourActionState if necessary 148 * <li/> redo the undone action using the information from the state 149 * <li/> produce a new state that can be used by performUndo() and return it 150 * </ul> 151 * </ul> 152 * 153 * <H2> Advanced techniques </H2> 154 * 155 * <H3> Predefined Actions </H3> 156 * 157 * To make construction of actions easy there are some predefined actions. Namely these are 158 * the MethodAction and the ErrorAction. 159 * 160 * The method action can be used to turn any function with empty arguments and return type void 161 * into an action (also works for functors with those types). Simply pass the constructor for the 162 * MethodAction a name to use for this action, the function to call inside the performCall() 163 * method and a flag indicating if this action should be made retrievable inside the registry 164 * (default is true). MethodActions always report themselves as changing the state of the 165 * application but cannot be undone. i.e. calling MethodActions will always cause the ActionHistory 166 * to be cleared. 167 * 168 * ErrorActions can be used to produce a short message using the Log() << Verbose() mechanism of 169 * the molecuilder. Simply pass the constructor a name for the action, the message to show upon 170 * calling this action and the flag for the registry (default is again true). Error action 171 * report that they do not change the state of the application and are therefore not considered 172 * for undo. 173 * 174 * <H3> Sequences of Actions and MakroActions </H3> 175 * 176 * <H4> Building sequences of Actions </H4> 177 * 178 * Actions can be chained to sequences using the ActionSequence class. Once an ActionSequence is 179 * constructed it will be initially empty. Any Actions can then be added to the sequence using the 180 * addAction() method of the ActionSequence class. The last added action can be removed using the 181 * removeLastAction() method. If the construction of the sequence is done, you can use the 182 * callAll() method. Each action called this way will register itself with the History to allow 183 * separate undo of all actions in the sequence. 184 * 185 * <H4> Building larger Actions from simple ones </H4> 186 * 187 * Using the pre-defined class MakroAction it is possible to construct bigger actions from a sequence 188 * of smaller ones. For this you first have to build a sequence of the actions using the ActionSequence 189 * as described above. Then you can construct a MakroAction passing it a name, the sequence to use 190 * and as usual a flag for the registry. You can then simply call the complete action-sequence through 191 * this makro action using the normal interface. Other than with the direct use of the action sequence 192 * only the complete MakroAction is registered inside the history, i.e. the complete sequence can be 193 * undone at once. Also there are a few caveats you have to take care of when using the MakroAction: 194 * <ul> 195 * <li/> All Actions as well as the sequence should exclusively belong to the MakroAction. This 196 * especially means, that the destruction of these objects should be handled by the MakroAction. 197 * <li/> none of the Actions inside the MakroAction should be registered with the registry, since the 198 * registry also assumes sole ownership of the actions. 199 * <li/> Do not remove or add actions from the sequence once the MakroAction has been constructed, since this 200 * might brake important assumptions for the undo/redo mechanism 201 * </ul> 202 * 203 * <H3> Special kinds of Actions </H3> 204 * 205 * To make the usage of Actions more versatile there are two special kinds of actions defined, 206 * that contain special mechanisms. These are defined inside the class Process, for actions that 207 * take some time and indicate their own progress, and in the class Calculations for actions that 208 * have a retrievable result. 209 * 210 * <H4> Processes </H4> 211 * 212 * Processes are Actions that might take some time and therefore contain special mechanisms 213 * to indicate their progress to the user. If you want to implement a process you can follow the 214 * guidelines for implementing actions. In addition to the normal Action constructor parameters, 215 * you also need to define the number of steps the process takes to finish (use 0 if that number is 216 * not known upon construction). At the beginning of your process you then simply call start() to 217 * indicate that the process is taking up its work. You might also want to set the number of steps it 218 * needs to finish, if it has changed since the last invocation/construction. You can use the 219 * setMaxSteps() method for this. Then after each finished step of calulation simply call step(), 220 * to let the indicators know that it should update itself. If the number of steps is not known 221 * at the time of calculation, you should make sure the maxSteps field is set to 0, either through 222 * the constructor or by using setMaxSteps(0). Indicators are required to handle both processes that 223 * know the number of steps needed as well as processes that cannot predict when they will be finished. 224 * Once your calculation is done call stop() to let every indicator know that the process is done with 225 * the work and to let the user know. 226 * 227 * Indicators that want to know about processes need to implement the Observer class with all the 228 * methods defined there. They can then globally sign on to all processes using the static 229 * Process::AddObserver() method and remove themselves using the Process::RemoveObserver() 230 * methods. When a process starts it will take care that the notification for this process 231 * is invoked at the right time. Indicators should not try to observe a single process, but rather 232 * be ready to observe the status of any kind of process using the methods described here. 233 * 234 * <H4> Calculations </H4> 235 * 236 * Calculations are special Actions that also return a result when called. Calculations are 237 * always derived from Process, so that the progress of a calculation can be shown. Also 238 * Calculations should not contain side-effects and not consider the undo mechanism. 239 * When a Calculation is called using the Action mechanism this will cause it to calculate 240 * the result and make it available using the getResult() method. Another way to have a Calculation 241 * produce a result is by using the function-call operator. When this operator is used, the Calculation 242 * will try to return a previously calculated and cached result and only do any actuall calculations 243 * when no such result is available. You can delete the cached result using the reset() method. 244 */ 245 246 /** 20 247 * Base class for all actions. 21 248 * 22 249 * Actions describe something that has to be done. 23 250 * Actions can be passed around, stored, performed and undone (Command-Pattern). 24 *25 * TODO: Add queues of actions that have been performed to allow easy implementation of multiple-step undo26 251 */ 27 252 class Action 28 253 { 29 254 friend class ActionSequence; 255 friend class ActionHistory; 30 256 public: 31 257 … … 38 264 // actuall action is passed on to a private virtual 39 265 void call(); 266 267 virtual bool canUndo()=0; 268 virtual bool shouldUndo()=0; 269 270 virtual bool isActive(); 271 272 virtual const std::string getName(); 273 274 protected: 40 275 state_ptr undo(state_ptr); 41 276 state_ptr redo(state_ptr); 42 277 43 virtual bool canUndo()=0;44 virtual bool shouldUndo()=0;45 46 virtual const std::string getName();47 48 protected:49 278 static state_ptr success; 50 279 static state_ptr failure; -
src/Actions/ActionHistory.cpp
r68d781 rfdd840 36 36 } 37 37 38 bool ActionHistory::hasUndo(){ 39 return history.size()>0; 40 } 41 42 bool ActionHistory::hasRedo(){ 43 return yrotsih.size()>0; 44 } 45 38 46 void ActionHistory::addElement(Action* action,Action::state_ptr state){ 39 cout << "Adding action to end of history" << endl;40 47 yrotsih.clear(); 41 48 history.push_back(HistoryElement(action,state)); … … 43 50 44 51 void ActionHistory::clear(){ 45 cout << "History cleared" << endl;46 52 history.clear(); 47 53 yrotsih.clear(); … … 71 77 bool ActionHistory::UndoAction::shouldUndo(){ 72 78 return false; 79 } 80 81 bool ActionHistory::UndoAction::isActive(){ 82 return hist->hasUndo(); 73 83 } 74 84 … … 103 113 } 104 114 115 bool ActionHistory::RedoAction::isActive(){ 116 return hist->hasRedo(); 117 } 118 105 119 Action::state_ptr ActionHistory::RedoAction::performCall(){ 106 120 hist->redoLast(); -
src/Actions/ActionHistory.hpp
r68d781 rfdd840 37 37 virtual bool shouldUndo(); 38 38 39 virtual bool isActive(); 40 39 41 private: 40 42 virtual Action::state_ptr performCall(); … … 53 55 virtual bool shouldUndo(); 54 56 57 virtual bool isActive(); 58 55 59 private: 56 60 virtual Action::state_ptr performCall(); … … 65 69 void undoLast(); 66 70 void redoLast(); 71 72 bool hasUndo(); 73 bool hasRedo(); 67 74 68 75 void addElement(Action*,Action::state_ptr); -
src/Actions/ActionSequence.cpp
r68d781 rfdd840 36 36 } 37 37 38 ActionSequence::stateSet ActionSequence::callAll(){ 38 // this method is used outside the ActionModule 39 // Each action registers itself with the history 40 void ActionSequence::callAll(){ 41 for(actionSet::iterator it=actions.begin(); it!=actions.end(); it++){ 42 // we want to have a global bookkeeping for all actions in the sequence, so 43 // we bypass the normal call 44 (*it)->call(); 45 } 46 } 47 48 // This method is used internally when MakroActions are constructed. 49 // In this case only the makro Action should be registered and 50 // handle the states 51 ActionSequence::stateSet ActionSequence::callAll(bool){ 39 52 stateSet states; 40 53 for(actionSet::iterator it=actions.begin(); it!=actions.end(); it++){ -
src/Actions/ActionSequence.hpp
r68d781 rfdd840 18 18 class ActionSequence 19 19 { 20 friend class MakroAction; 20 21 public: 21 22 typedef std::deque<Action*> actionSet; … … 28 29 Action* removeLastAction(); 29 30 30 stateSet callAll(); 31 stateSet undoAll(stateSet); 32 stateSet redoAll(stateSet); 31 void callAll(); 33 32 34 33 bool canUndo(); 35 34 bool shouldUndo(); 36 35 36 protected: 37 stateSet callAll(bool); // Dummy parameter to allow overloading 38 stateSet undoAll(stateSet); 39 stateSet redoAll(stateSet); 37 40 private: 38 41 actionSet actions; -
src/Actions/MakroAction.cpp
r68d781 rfdd840 44 44 45 45 Action::state_ptr MakroAction::performCall(){ 46 ActionSequence::stateSet states = actions->callAll( );46 ActionSequence::stateSet states = actions->callAll(true); 47 47 return Action::state_ptr(new MakroActionState(states)); 48 48 } -
src/Actions/Process.cpp
r68d781 rfdd840 25 25 26 26 27 bool Process::is Active(){27 bool Process::isRunning(){ 28 28 return active; 29 29 } -
src/Actions/Process.hpp
r68d781 rfdd840 43 43 virtual ~Process(); 44 44 45 bool is Active();45 bool isRunning(); 46 46 bool doesStart(); 47 47 bool doesStop(); -
src/Menu/ActionMenuItem.cpp
r68d781 rfdd840 20 20 21 21 ActionMenuItem::~ActionMenuItem() 22 { 23 // TODO Auto-generated destructor stub 24 } 22 {} 25 23 26 24 void ActionMenuItem::doTrigger() { 27 25 action->call(); 28 26 } 27 28 bool ActionMenuItem::isActive() { 29 return action->isActive(); 30 } -
src/Menu/ActionMenuItem.hpp
r68d781 rfdd840 26 26 virtual void doTrigger(); 27 27 28 virtual bool isActive(); 29 28 30 private: 29 31 Action* action; //!< this action will be called when the trigger matches -
src/Menu/MenuItem.cpp
r68d781 rfdd840 78 78 return added; 79 79 } 80 81 bool MenuItem::isActive(){ 82 return true; 83 } -
src/Menu/MenuItem.hpp
r68d781 rfdd840 21 21 */ 22 22 class MenuItem { 23 private:24 char trigger;25 string *description;26 bool added;27 28 23 public: 29 24 MenuItem(char,const char*,Menu*); … … 41 36 bool wasAdded(); 42 37 38 virtual bool isActive(); 39 43 40 protected: 44 41 void setDescription(string); 42 43 private: 44 char trigger; 45 string *description; 46 bool added; 45 47 }; 46 48 -
src/Menu/TextMenu.cpp
r68d781 rfdd840 52 52 53 53 void TextMenu::showEntry(MenuItem* entry){ 54 outputter << entry->formatEntry() << "\n"; 54 if(entry->isActive()==false){ 55 outputter << "("; 56 } 57 outputter << entry->formatEntry(); 58 if(entry->isActive()==false){ 59 outputter << ")"; 60 } 61 outputter << "\n"; 55 62 } 56 63 … … 75 82 list<MenuItem*>::iterator iter; 76 83 for(iter = items.begin(); iter!=items.end();iter++){ 77 somethingChosen |= (*iter)->checkTrigger(choice); 84 if((*iter)->isActive()){ 85 somethingChosen |= (*iter)->checkTrigger(choice); 86 } 78 87 } 79 88 // see if something was chosen and call default Item if not -
src/unittests/ActionSequenceTest.cpp
r68d781 rfdd840 13 13 #include "Actions/Action.hpp" 14 14 #include "Actions/ActionSequence.hpp" 15 #include "Actions/MakroAction.hpp" 16 #include "Actions/ActionHistory.hpp" 17 #include "Actions/ActionRegistry.hpp" 15 18 16 19 #ifdef HAVE_TESTRUNNER … … 22 25 // Registers the fixture into the 'registry' 23 26 CPPUNIT_TEST_SUITE_REGISTRATION( ActionSequenceTest ); 24 25 void setUp();26 void tearDown();27 28 void canUndoTest();29 27 30 28 /* some neccessary stubs for tests */ … … 110 108 111 109 void ActionSequenceTest::setUp(){ 110 ActionHistory::init(); 112 111 // create some necessary stubs used in this test 113 112 positive1 = new canUndoActionStub(); … … 134 133 delete shouldNotCall2; 135 134 135 ActionHistory::purgeInstance(); 136 ActionRegistry::purgeInstance(); 136 137 } 137 138 … … 209 210 void ActionSequenceTest::doesUndoTest(){ 210 211 ActionSequence *sequence = new ActionSequence(); 211 sequence->addAction(shouldNotCall1); 212 sequence->addAction(shouldNotCall2); 213 sequence->addAction(shouldCall1); 214 sequence->addAction(shouldCall2); 215 216 ActionSequence::stateSet states = sequence->callAll(); 217 218 sequence->removeLastAction(); 219 sequence->removeLastAction(); 220 221 sequence->undoAll(states); 222 223 CPPUNIT_ASSERT_EQUAL(true,shouldCall1->wasCalled()); 224 CPPUNIT_ASSERT_EQUAL(true,shouldCall2->wasCalled()); 225 CPPUNIT_ASSERT_EQUAL(false,shouldNotCall1->wasCalled()); 226 CPPUNIT_ASSERT_EQUAL(false,shouldNotCall2->wasCalled()); 227 228 delete sequence; 229 } 230 231 212 wasCalledActionStub *wasCalled1 = new wasCalledActionStub(); 213 wasCalledActionStub *wasCalled2 = new wasCalledActionStub(); 214 sequence->addAction(wasCalled1); 215 sequence->addAction(wasCalled2); 216 217 MakroAction act("Test MakroAction",sequence,false); 218 219 act.call(); 220 221 CPPUNIT_ASSERT_EQUAL(true,wasCalled1->wasCalled()); 222 CPPUNIT_ASSERT_EQUAL(true,wasCalled1->wasCalled()); 223 224 ActionHistory::getInstance().undoLast(); 225 226 CPPUNIT_ASSERT_EQUAL(false,wasCalled1->wasCalled()); 227 CPPUNIT_ASSERT_EQUAL(false,wasCalled1->wasCalled()); 228 229 } 230 231
Note:
See TracChangeset
for help on using the changeset viewer.