/* * Action_impl.hpp * * Created on: Aug 25, 2010 * Author: heber */ /** These macros define the following functions, necessary but repetitive for * every Action: * -# Dialog* fillDialog() * -# action command (e.g. AnalysisMolecularVolume() ) * -# void getParametersfromValuStorage() * -# struct Action...Parameters * * For this, the user has the define the following values, each with * parenthesis, for the values/parameters the action needs * -# paramtypes, e.g. (int)(double) * -# paramtokens, e.g. ("Z")("length") * -# paramreferences, e.g. (Z)(length) * and for additional values/parameters to save in the state * -# statetypes, e.g. (int)(double) * -# statereferences, e.g. (Z)(length) * and the name and category of the action * -# CATEGORY, e.g. Analysis * -# ACTIONNAME, e.g. MolecularVolume */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "CodePatterns/Chronos.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Actions/ActionQueue.hpp" #include "Actions/toCLIString.hpp" #include "Actions/toPythonString.hpp" #include "Parameters/Parameter.hpp" // some derived names: if CATEGORY is not given, we don't prefix with it #ifdef CATEGORY #define ACTION BOOST_PP_CAT(CATEGORY, BOOST_PP_CAT(ACTIONNAME, Action)) #define COMMAND BOOST_PP_CAT(CATEGORY, ACTIONNAME) #define STATE BOOST_PP_CAT(CATEGORY, BOOST_PP_CAT(ACTIONNAME, State)) #define PARAMS BOOST_PP_CAT(CATEGORY, BOOST_PP_CAT(ACTIONNAME, Parameters)) #else #define ACTION BOOST_PP_CAT(ACTIONNAME, Action) #define COMMAND ACTIONNAME #define STATE BOOST_PP_CAT(ACTIONNAME, State) #define PARAMS BOOST_PP_CAT(ACTIONNAME, Parameters) #endif #define INSTANCE BOOST_PP_CAT(this_, BOOST_PP_CAT(ACTIONNAME, _instance)) // check if no lists given #ifndef paramtypes #define MAXPARAMTYPES 0 #else #define MAXPARAMTYPES BOOST_PP_SEQ_SIZE(paramtypes) #endif #ifndef statetypes #define MAXSTATETYPES 0 #else #define MAXSTATETYPES BOOST_PP_SEQ_SIZE(statetypes) #endif #ifndef paramdefaults #define MAXPARAMDEFAULTS 0 // this is required for valid_print "else part" #define sequencer(z,n,data) \ BOOST_PP_SEQ_PUSH_BACK( data, NOPARAM_DEFAULT) #define paramdefaults BOOST_PP_REPEAT( MAXPARAMTYPES, sequencer, BOOST_PP_SEQ_NIL ) #else #define MAXPARAMDEFAULTS BOOST_PP_SEQ_SIZE(paramdefaults) #endif #define PARAM_DEFAULT(x) \ (x, BOOST_PP_NIL) // check user has given name and category #ifndef ACTIONNAME ERROR: No "ACTIONNAME" defined in: __FILE__ #endif // calculate numbers and check whether all have same size #ifdef paramtokens BOOST_PP_ASSERT_MSG(BOOST_PP_EQUAL(MAXPARAMTYPES, BOOST_PP_SEQ_SIZE(paramtokens)),\ ERROR: There are not the same number of "paramtokens" and "paramtypes" in: __FILE__ \ ) #endif #ifdef paramreferences BOOST_PP_ASSERT_MSG(BOOST_PP_EQUAL(MAXPARAMTYPES, BOOST_PP_SEQ_SIZE(paramreferences)),\ ERROR: There are not the same number of "paramtokens" and "paramreferences" in: __FILE__ \ ) #endif #ifdef statetypes BOOST_PP_ASSERT_MSG(BOOST_PP_EQUAL(MAXSTATETYPES, BOOST_PP_SEQ_SIZE(statereferences)),\ ERROR: There are not the same number of "statetypes" and "statereferences" in: __FILE__ \ ) #endif // print a list of type ref followed by a separator, i.e. "int i;" #define initialiser_print(z,n,initialiserlist) \ BOOST_PP_SEQ_ELEM(n, initialiserlist) \ (BOOST_PP_CAT(_, BOOST_PP_SEQ_ELEM(n, initialiserlist))), // print a list of ref(_ref) followed by a separator, i.e. "id(_id)," #define type_print(z,n,TYPELIST, VARLIST, separator) \ BOOST_PP_SEQ_ELEM(n, TYPELIST) \ BOOST_PP_SEQ_ELEM(n, VARLIST)\ separator // print a list of type ref followed, i.e. "int i, double position" #define type_list(z,n,TYPELIST,VARLIST) \ BOOST_PP_COMMA_IF(n)\ BOOST_PP_SEQ_ELEM(n, TYPELIST) \ BOOST_PP_SEQ_ELEM(n, VARLIST) // prints dialog->query calls for paramtypes with tokens #define dialog_print(z,n,unused) \ dialog->query<\ BOOST_PP_SEQ_ELEM(n, paramtypes)\ >( params. \ BOOST_PP_SEQ_ELEM(n, paramreferences)\ ,\ BOOST_PP_SEQ_ELEM(n, paramtokens)\ , Traits.getDescription()\ ); // prints command line call for this Action for paramtypes with tokens #define outputAsCLI_print(z,n,output) \ output << \ BOOST_PP_IF(n, " --", "--") \ << \ BOOST_PP_SEQ_ELEM(n, paramtokens) \ << " " << toCLIString(params. \ BOOST_PP_SEQ_ELEM(n, paramreferences) \ .get()); // prints if statement to check two strings (paramtokens[n] vs. TOKEN) #define checkpresenttoken_print(z, n, TOKEN, booltoken) \ if ( std::string(\ BOOST_PP_SEQ_ELEM(n, paramtokens) )\ == getName()) \ booltoken = false; // prints command line call for this Action for paramtypes with tokens #define outputAsPython_print(z,n,output) \ output << \ BOOST_PP_IF(n, ", ", "") \ << "\"" << toPythonString(params. \ BOOST_PP_SEQ_ELEM(n, paramreferences) \ .get()) \ << "\""; // print an initialiser list, i.e. "var( token, valid (,default) )(,)" #define valid_print(z,n,TOKENLIST, VARLIST, VALIDLIST, DEFAULTLIST) \ BOOST_PP_COMMA_IF(n) \ BOOST_PP_SEQ_ELEM(n, VARLIST) \ ( \ BOOST_PP_SEQ_ELEM(n, TOKENLIST) \ , \ BOOST_PP_SEQ_ELEM(n, VALIDLIST) \ BOOST_PP_COMMA_IF( BOOST_PP_NOT( BOOST_PP_LIST_IS_NIL( BOOST_PP_SEQ_ELEM(n, DEFAULTLIST) ) ) ) \ BOOST_PP_EXPR_IF( \ BOOST_PP_NOT( BOOST_PP_LIST_IS_NIL( BOOST_PP_SEQ_ELEM(n, DEFAULTLIST) ) ), \ BOOST_PP_LIST_FIRST( BOOST_PP_SEQ_ELEM(n, DEFAULTLIST) )) \ ) // print an initialiser list, i.e. "var( valid . var )(,)" #define validcopy_print(z,n,TOKENLIST, VARLIST, VALID) \ BOOST_PP_COMMA_IF(n) \ BOOST_PP_SEQ_ELEM(n, VARLIST) \ ( \ VALID . \ BOOST_PP_SEQ_ELEM(n, VARLIST) \ ) // prints set/queryCurrentValue (command) for paramreferences and paramtokens #define value_print(z, n, container, prefix) \ prefix \ BOOST_PP_SEQ_ELEM(n, container)\ .set(\ BOOST_PP_SEQ_ELEM(n, container)\ ); // prints set/queryCurrentValue (command) for paramreferences and paramtokens #define valuetype_print(z,n,container, types, prefix) \ prefix \ BOOST_PP_SEQ_ELEM(n, container) \ .setAsString( \ BOOST_PP_SEQ_ELEM(n, container) \ ); #define stringtype std::string #define type2string(s, data, elem) \ stringtype #include "Actions/ActionRegistry.hpp" //#include "Actions/ActionTraits.hpp" #include "UIElements/Dialog.hpp" #ifdef paramtokens #define statenecessary 1 #endif #ifndef statetokens #define statenecessary 1 #endif namespace MoleCuilder { // =========== memento to remember the state when undoing =========== #ifdef statenecessary class STATE : public ActionState { public: STATE( #if defined statetypes && defined statereferences // if we have states, we have to add "_" before each reference and add the params as the last one #define OP(s,data,elem) BOOST_PP_CAT(data, elem) // OP to add "_" #define BOOST_PP_LOCAL_MACRO(n) type_list(~, n, BOOST_PP_SEQ_PUSH_BACK(statetypes, const ACTION::PARAMS &), BOOST_PP_SEQ_TRANSFORM(OP, _, BOOST_PP_SEQ_PUSH_BACK(statereferences, params))) #else /// if not, params is only list #define BOOST_PP_LOCAL_MACRO(n) type_list(~, n, (const ACTION::PARAMS &), (_params)) #endif #define BOOST_PP_LOCAL_LIMITS (0, MAXSTATETYPES) #include BOOST_PP_LOCAL_ITERATE() ) : #if defined statetypes && defined statereferences // do we have states at all? BOOST_PP_REPEAT(MAXSTATETYPES, initialiser_print, statereferences) #endif params(_params) {} #if defined statetypes && defined statereferences // do we have parameters at all? #define BOOST_PP_LOCAL_MACRO(n) type_print(~, n, statetypes, statereferences, ;) #define BOOST_PP_LOCAL_LIMITS (0, MAXSTATETYPES-1) #include BOOST_PP_LOCAL_ITERATE() #endif ACTION::PARAMS params; }; #endif /* statenecessary */ // (const) prototype to be placed into the ActionRegistry (must be deleted by registry itself) //const ACTION INSTANCE; //boost::shared_ptr< ACTION > INSTANCE( new ACTION() ); // =========== constructor =========== ACTION::ACTION () : MakroAction(ActionTraits< ACTION >(), actions), actions(prototype_actions) {} // =========== destructor =========== ACTION::~ACTION () { //std::cout << "Action ACTION is being destroyed." << std::endl; } // =========== parameter constructor =========== ACTION::PARAMS::PARAMS() #if defined paramtokens && defined paramreferences && defined paramvalids : #define BOOST_PP_LOCAL_MACRO(n) valid_print(~, n, paramtokens, paramreferences, paramvalids, paramdefaults) #define BOOST_PP_LOCAL_LIMITS (0, MAXPARAMTYPES-1) #include BOOST_PP_LOCAL_ITERATE() #endif {} ACTION::PARAMS::PARAMS(const PARAMS &p) #if defined paramtokens && defined paramreferences : #define BOOST_PP_LOCAL_MACRO(n) validcopy_print(~, n, paramtokens, paramreferences, p) #define BOOST_PP_LOCAL_LIMITS (0, MAXPARAMTYPES-1) #include BOOST_PP_LOCAL_ITERATE() #endif {} // =========== clone Action =========== Action* ACTION::clone(enum QueryOptions flag) const { return new ACTION(); } // =========== fill a dialog =========== Dialog* ACTION::fillOwnDialog(Dialog *dialog) { ASSERT(dialog,"No Dialog given when filling actionname's dialog"); #if BOOST_PP_EQUAL(MAXPARAMTYPES,0) dialog->queryEmpty(TOKEN, Traits.getDescription()); #else #define BOOST_PP_LOCAL_MACRO(n) dialog_print(~, n, ~) #define BOOST_PP_LOCAL_LIMITS (0, MAXPARAMTYPES-1) #include BOOST_PP_LOCAL_ITERATE() #endif return dialog; }; // =========== output as CLI =========== void ACTION::outputAsCLI(std::ostream &ost) const { // check whether TOKEN is also an option // is a bit ugly as preprocessor cannot compare strings bool status = true; #if defined paramtokens && BOOST_PP_NOT_EQUAL(MAXPARAMTYPES,0) #define BOOST_PP_LOCAL_MACRO(n) checkpresenttoken_print(~, n, TOKEN, status) #define BOOST_PP_LOCAL_LIMITS (0, MAXPARAMTYPES-1) #include BOOST_PP_LOCAL_ITERATE() #endif if (status) { ost << "--" << TOKEN; #if defined paramtypes && defined paramreferences && BOOST_PP_NOT_EQUAL(MAXPARAMTYPES,0) ost << " "; #endif } // then print option along with each argument if set #if defined paramtypes && defined paramreferences && BOOST_PP_NOT_EQUAL(MAXPARAMTYPES,0) #define BOOST_PP_LOCAL_MACRO(n) outputAsCLI_print(~, n, ost) #define BOOST_PP_LOCAL_LIMITS (0, MAXPARAMTYPES-1) #include BOOST_PP_LOCAL_ITERATE() #endif } // =========== output as PYTHTON =========== void ACTION::outputAsPython(std::ostream &ost, const std::string &prefix) const { // print prefix and action command ost << prefix << "." << BOOST_PP_STRINGIZE( COMMAND ) << "("; // then print option along with each argument if set #if defined paramtypes && defined paramreferences && BOOST_PP_NOT_EQUAL(MAXPARAMTYPES,0) #define BOOST_PP_LOCAL_MACRO(n) outputAsPython_print(~, n, ost) #define BOOST_PP_LOCAL_LIMITS (0, MAXPARAMTYPES-1) #include BOOST_PP_LOCAL_ITERATE() #endif ost << ")" << std::endl; } // =========== time the action =========== // we need this here to have the correct function name void ACTION::startTimer() const { Chronos::getInstance().startTiming( std::string( TOKEN ) ); } void ACTION::endTimer() const { Chronos::getInstance().endTiming( std::string( TOKEN ) ); } // =========== command for calling action directly =========== void COMMAND( #if defined paramtypes && defined paramreferences && BOOST_PP_NOT_EQUAL(MAXPARAMTYPES,0) #define BOOST_PP_LOCAL_MACRO(n) type_list(~, n, paramtypes, paramreferences) #define BOOST_PP_LOCAL_LIMITS (0, MAXPARAMTYPES-1) #include BOOST_PP_LOCAL_ITERATE() #endif ) { ACTION * const ToCall = dynamic_cast(ActionQueue::getInstance().getActionByName( TOKEN ).clone()); //ACTION::PARAMS params; #if defined paramreferences && BOOST_PP_NOT_EQUAL(MAXPARAMTYPES,0) #define BOOST_PP_LOCAL_MACRO(n) value_print(~, n, paramreferences, ToCall->params.) #define BOOST_PP_LOCAL_LIMITS (0, MAXPARAMTYPES-1) #include BOOST_PP_LOCAL_ITERATE() #endif Action::insertAction( ToCall, Action::NonInteractive); }; void BOOST_PP_CAT( COMMAND, _stringargs)( #if defined paramtypes && defined paramreferences && BOOST_PP_NOT_EQUAL(MAXPARAMTYPES,0) #define BOOST_PP_LOCAL_MACRO(n) type_list(~, n, BOOST_PP_SEQ_TRANSFORM( type2string, , paramtypes), paramreferences) #define BOOST_PP_LOCAL_LIMITS (0, MAXPARAMTYPES-1) #include BOOST_PP_LOCAL_ITERATE() #endif ) { ACTION * const ToCall = dynamic_cast(ActionQueue::getInstance().getActionByName( TOKEN ).clone()); //ACTION::PARAMS params; #if defined paramtypes && defined paramtypes && BOOST_PP_NOT_EQUAL(MAXPARAMTYPES,0) #define BOOST_PP_LOCAL_MACRO(n) valuetype_print(~, n, paramreferences, paramtypes, ToCall->params. ) #define BOOST_PP_LOCAL_LIMITS (0, MAXPARAMTYPES-1) #include BOOST_PP_LOCAL_ITERATE() #endif Action::insertAction( ToCall, Action::NonInteractive); }; } // free up defines #undef paramvalids #undef paramtypes #undef paramtokens #undef paramreferences #undef paramdescriptions #undef paramdefaults #undef MAXPARAMTYPES #undef MAXPARAMDEFAULTS #undef statetypes #undef statereferences #undef MAXSTATETYPES #undef PARAM_DEFAULT #undef type2string #undef stringtype #undef initialiser_print #undef type_print #undef type_list #undef dialog_print #undef sequencer #undef valid_print #undef validcopy_print #undef value_print #undef valuetype_print #undef ACTION #undef COMMAND #undef PARAMS #undef STATE #undef INSTANCE #undef ACTIONNAME #undef CATEGORY #undef TOKEN