/* * Action.hpp * * Created on: Dec 8, 2009 * Author: crueger */ #ifndef ACTION_HPP_ #define ACTION_HPP_ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include #include #include /** Used in .def files in paramdefaults define to set that no default value exists. * We define NOPARAM_DEFAULT here, as it is used in .def files and needs to be present * before these are included. */ #define NOPARAM_DEFAULT BOOST_PP_NIL // forward declaration namespace MoleCuilder { class ActionState; class ActionSequence; } class Dialog; #include "Actions/ActionTrait.hpp" namespace MoleCuilder { /** Actions are Command patterns to allow for undoing and redoing. * * Each specific Action derives from this class to implement a certain functionality. * * Actions describe something that has to be done. * Actions can be passed around, stored, performed and undone (Command-Pattern: * http://en.wikipedia.org/wiki/Command_pattern). * * Unique to each Action is its ActionTrait, i.e. the options it requires * to perform a certain function. E.g. in order to execute a "add atom" Action * we need to know a position and an element. These options have certain * properties, see \ref OptionTrait and \ref ActionTrait wherein these are stored. * Essentially, each option is stored as an \ref OptionTrait instance and * contains the token, default value, a description, the type, ... * * ActionTrait itself is also an OptionTrait because the command token may actually * coincide with an option-token. E.g. this allows "...--add-atom 3" to mean * both execute the action under token "add-atom" and that the option "add-atom" * (the new atom's \ref element number) should contain 3. * * \ref ActionTrait contains a map of all associated options. With this in the cstor * we register not only the Action with the \ref ActionRegistry but also each of * its \link options OptionTrait \endlink with the \ref OptionRegistry. * * The token of the option is unique, but two Action's may share the same token if: * -# they have the same default value * -# they have the same type * * This requirement is easy because if you need to store some option of another * type, simply think of a new suitable name for it. * * The actual value, i.e. "3" in the "add-atom" example, is taken from the * ValueStorage, see \ref Dialog for how this is possible. * * \note There is a unit test that checks on the consistency of all registered * options, also in "--enable-debug"-mode assertions will check that an option * has not been registered before under another type. * */ class Action { friend class ActionSequence; friend class ActionHistory; public: enum QueryOptions {Interactive, NonInteractive}; /** * This type is used to store pointers to ActionStates while allowing multiple ownership */ typedef boost::shared_ptr state_ptr; /** * Standard constructor of Action Base class * * All Actions need to have a name. The second flag indicates, whether the action should * be registered with the ActionRegistry. If the Action is registered the name of the * Action needs to be unique for all Actions that are registered. * * \note NO reference for \a _Traits as we do have to copy it, otherwise _Traits would have * to be present throughout the program's run. * * \param Traits information class to this action * \param _doRegister whether to register with ActionRegistry */ Action(const ActionTrait &_Traits, bool _doRegister=true); virtual ~Action(); /** * This method is used to call an action. The basic operations for the Action * are carried out and if necessary/possible the Action is added to the History * to allow for undo of this action. * * If the call needs to undone you have to use the History, to avoid destroying * invariants used by the History. * * Note that this call can be Interactive (i.e. a dialog will ask the user for * necessary information) and NonInteractive (i.e. the information will have to * be present already within the ValueStorage class or else a MissingArgumentException * is thrown) */ void call(enum QueryOptions state = Interactive); /** * This method provides a flag that indicates if an undo mechanism is implemented * for this Action. If this is true, and this action was called last, you can * use the History to undo this action. */ virtual bool canUndo()=0; /** * This method provides a flag, that indicates if the Action changes the state of * the application in a way that needs to be undone for the History to work. * * If this is false the Action will not be added to the History upon calling. However * Actions called before this one will still be available for undo. */ virtual bool shouldUndo()=0; /** * Indicates whether the Action can do it's work at the moment. If this * is false calling the action will result in a no-op. */ virtual bool isActive(); /** * Returns the name of the Action. */ const std::string getName() const; /** * returns a detailed help message. */ const std::string help() const; /** * Traits resemble all necessary information that "surrounds" an action, such as * its name (for ActionRegistry and as ref from string to instance and vice versa), * which menu, which position, what parameters, their types, if it is itself a * parameter and so on ... * * Note that is important that we do not use a reference here. We want to copy the * information in the Action's constructor and have it contained herein. Hence, we * also have our own copy constructor for ActionTrait. Information should be * encapsulated in the Action, no more references to the outside than absolutely * necessary. */ const ActionTrait Traits; protected: /** Removes the static entities Action::success and Action::failure. * This is only to be called on the program's exit, i.e. in cleanUp(), * as these static entities are used throughout all Actions. */ static void removeStaticStateEntities(); /** Creates the static entities Action::success and Action::failure. * This is only to be called by ActionHistory. */ static void createStaticStateEntities(); /** * This method is called by the History, when an undo is performed. It is * provided with the corresponding state produced by the performCall or * performRedo method and needs to provide a state that can be used for redo. */ state_ptr undo(state_ptr); /** * This method is called by the History, when a redo is performed. It is * provided with the corresponding state produced by the undo method and * needs to produce a State that can then be used for another undo. */ state_ptr redo(state_ptr); /** * This special state can be used to indicate that the Action was successful * without providing a special state. Use this if your Action does not need * a specialized state. */ static state_ptr success; /** * This special state can be returned, to indicate that the action could not do it's * work, was aborted by the user etc. If you return this state make sure to transactionize * your Actions and unroll the complete transaction before this is returned. */ static state_ptr failure; /** * This creates the dialog requesting the information needed for this action from the user * via means of the user interface. */ Dialog * createDialog(); /** Virtual function that starts the timer. * */ virtual void startTimer() const {}; /** Virtual function that ends the timer. * */ virtual void endTimer() const {}; private: /** * This is called internally before the action is processed. This adds necessary queries * to a given dialog to obtain parameters for the user for processing the action accordingly. * The dialog will be given to the user before Action::performCall() is initiated, values * are transfered via ValueStorage. */ virtual Dialog * fillDialog(Dialog*)=0; /** * This is called internally when the call is being done. Implement this method to do the actual * work of the Action. Implement this in your Derived classes. Needs to return a state that can be * used to undo the action. */ virtual state_ptr performCall()=0; /** * This is called internally when the undo process is chosen. This Method should use the state * produced by the performCall method to return the state of the application to the state * it had before the Action. */ virtual state_ptr performUndo(state_ptr)=0; /** * This is called internally when the redo process is chosen. This method shoudl use the state * produced by the performUndo method to return the application to the state it should have after * the action. * * Often this method can be implement to re-use the performCall method. However if user interaction * or further parameters are needed, those should be taken from the state and not query the user * again. */ virtual state_ptr performRedo(state_ptr)=0; }; /** * This class can be used by actions to save the state. * * It is implementing a memento pattern. The base class is completely empty, * since no general state internals can be given. The Action performing * the Undo should downcast to the appropriate type. */ class ActionState{ public: ActionState(){} virtual ~ActionState(){} }; /** * This class can be used by actions to contain parameters. * * The base class is completely empty, since no general parameters can be given. The * Action performing the function should construct its own parameter class derived * from it. */ class ActionParameters{ public: ActionParameters(){} virtual ~ActionParameters(){} }; } #endif /* ACTION_HPP_ */