diff --git a/Core/Code/Interactions/mitkEventStateMachine.cpp b/Core/Code/Interactions/mitkEventStateMachine.cpp index edf74300f0..7c211ec145 100644 --- a/Core/Code/Interactions/mitkEventStateMachine.cpp +++ b/Core/Code/Interactions/mitkEventStateMachine.cpp @@ -1,148 +1,189 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkEventStateMachine.h" #include "mitkStateMachineContainer.h" #include "mitkInteractionEvent.h" #include "mitkStateMachineAction.h" #include "mitkStateMachineTransition.h" #include "mitkStateMachineState.h" // us #include "mitkModule.h" #include "mitkModuleResource.h" #include "mitkModuleResourceStream.h" #include "mitkModuleRegistry.h" mitk::EventStateMachine::EventStateMachine() : m_StateMachineContainer(NULL), m_CurrentState(NULL) { } bool mitk::EventStateMachine::LoadStateMachine(const std::string& filename, const std::string& moduleName) { if (m_StateMachineContainer != NULL) { m_StateMachineContainer->Delete(); } m_StateMachineContainer = StateMachineContainer::New(); if (m_StateMachineContainer->LoadBehavior(filename, moduleName)) { m_CurrentState = m_StateMachineContainer->GetStartState(); // clear actions map ,and connect all actions as declared in sub-class + for(std::map::iterator i = m_ActionFunctionsMap.begin(); + i != m_ActionFunctionsMap.end(); ++i) + { + delete i->second; + } m_ActionFunctionsMap.clear(); + for(ActionDelegatesMapType::iterator i = m_ActionDelegatesMap.begin(); + i != m_ActionDelegatesMap.end(); ++i) + { + delete i->second; + } + m_ActionDelegatesMap.clear(); + ConnectActionsAndFunctions(); return true; } else { MITK_WARN<< "Unable to load StateMachine from file: " << filename; return false; } } mitk::EventStateMachine::~EventStateMachine() { if (m_StateMachineContainer != NULL) { m_StateMachineContainer->Delete(); } } void mitk::EventStateMachine::AddActionFunction(const std::string& action, mitk::TActionFunctor* functor) { if (!functor) return; // make sure double calls for same action won't cause memory leaks delete m_ActionFunctionsMap[action]; + ActionDelegatesMapType::iterator i = m_ActionDelegatesMap.find(action); + if (i != m_ActionDelegatesMap.end()) + { + delete i->second; + m_ActionDelegatesMap.erase(i); + } m_ActionFunctionsMap[action] = functor; } +void mitk::EventStateMachine::AddActionFunction(const std::string& action, const ActionFunctionDelegate& delegate) +{ + std::map::iterator i = m_ActionFunctionsMap.find(action); + if (i != m_ActionFunctionsMap.end()) + { + delete i->second; + m_ActionFunctionsMap.erase(i); + } + + delete m_ActionDelegatesMap[action]; + m_ActionDelegatesMap[action] = delegate.Clone(); +} + bool mitk::EventStateMachine::HandleEvent(InteractionEvent* event, DataNode* dataNode) { if (!FilterEvents(event, dataNode)) { return false; } // check if the current state holds a transition that works with the given event. StateMachineTransition::Pointer transition = m_CurrentState->GetTransition(event->GetEventClass(), MapToEventVariant(event)); if (transition.IsNotNull()) { // iterate over all actions in this transition and execute them ActionVectorType actions = transition->GetActions(); bool success = false; for (ActionVectorType::iterator it = actions.begin(); it != actions.end(); ++it) { success |= ExecuteAction(*it, event); // treat an event as handled if at least one of the actions is executed successfully } if (success || actions.empty()) // an empty action list is always successful { // perform state change m_CurrentState = transition->GetNextState(); //MITK_INFO<< "StateChange: " << m_CurrentState->GetName(); } return success; } else { return false; // no transition found that matches event } } void mitk::EventStateMachine::ConnectActionsAndFunctions() { MITK_WARN<< "ConnectActionsAndFunctions in DataInteractor not implemented.\n DataInteractor will not be able to process any events."; } bool mitk::EventStateMachine::ExecuteAction(StateMachineAction* action, InteractionEvent* event) { if (action == NULL) { return false; } - // Maps Action-Name to Functor and executes DoAction on Functor. - TActionFunctor* actionFunction = m_ActionFunctionsMap[action->GetActionName()]; - if (actionFunction == NULL) + + bool retVal = false; + // Maps Action-Name to Functor and executes the Functor. + ActionDelegatesMapType::iterator delegateIter = m_ActionDelegatesMap.find(action->GetActionName()); + if (delegateIter != m_ActionDelegatesMap.end()) { - return false; + retVal = delegateIter->second->Execute(action, event); + } + else + { + // try the legacy system + std::map::iterator functionIter = m_ActionFunctionsMap.find(action->GetActionName()); + if (functionIter != m_ActionFunctionsMap.end()) + { + retVal = functionIter->second->DoAction(action, event); + } } - bool retVal = actionFunction->DoAction(action, event); return retVal; } mitk::StateMachineState* mitk::EventStateMachine::GetCurrentState() const { return m_CurrentState.GetPointer(); } bool mitk::EventStateMachine::FilterEvents(InteractionEvent* interactionEvent, DataNode* dataNode) { if (dataNode == NULL) { MITK_WARN<< "EventStateMachine: Empty DataNode received along with this Event " << interactionEvent; return false; } bool visible = false; if (dataNode->GetPropertyList()->GetBoolProperty("visible", visible) == false) { //property doesn't exist return false; } return visible; } diff --git a/Core/Code/Interactions/mitkEventStateMachine.h b/Core/Code/Interactions/mitkEventStateMachine.h index 222d3b7e7d..bb2f1ea270 100644 --- a/Core/Code/Interactions/mitkEventStateMachine.h +++ b/Core/Code/Interactions/mitkEventStateMachine.h @@ -1,176 +1,189 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKEVENTSTATEMACHINE_H_ #define MITKEVENTSTATEMACHINE_H_ #include "itkObject.h" #include "itkObjectFactory.h" #include "mitkCommon.h" +#include "mitkMessage.h" #include "mitkInteractionEventHandler.h" #include #include namespace mitk { class StateMachineContainer; class StateMachineAction; class InteractionEvent; class StateMachineState; class DataNode; /** * \class TActionFunctor * \brief Base class of ActionFunctors, to provide an easy to connect actions with functions. + * + * \deprecatedSince{2013_03} Use mitk::Message classes instead. */ - class MITK_CORE_EXPORT TActionFunctor { public: virtual bool DoAction(StateMachineAction*, InteractionEvent*)=0; virtual ~TActionFunctor() { } }; /** * \class TSpecificActionFunctor * Specific implementation of ActionFunctor class, implements a reference to the function which is to be executed. It takes two arguments: * StateMachineAction - the action by which the function call is invoked, InteractionEvent - the event that caused the transition. */ template class TSpecificActionFunctor: public TActionFunctor { public: TSpecificActionFunctor(T* object, bool (T::*memberFunctionPointer)(StateMachineAction*, InteractionEvent*)) : m_Object(object), m_MemberFunctionPointer(memberFunctionPointer) { } virtual ~TSpecificActionFunctor() { } virtual bool DoAction(StateMachineAction* action, InteractionEvent* event) { return (*m_Object.*m_MemberFunctionPointer)(action, event);// executes member function } private: T* m_Object; bool (T::*m_MemberFunctionPointer)(StateMachineAction*, InteractionEvent*); }; /** Macro that can be used to connect a StateMachineAction with a function. * It assumes that there is a typedef Classname Self in classes that use this macro, as is provided by e.g. mitkClassMacro */ #define CONNECT_FUNCTION(a, f) \ - EventStateMachine::AddActionFunction(a, new TSpecificActionFunctor(this, &Self::f)); + EventStateMachine::AddActionFunction(a, MessageDelegate2(this, &Self::f)); /** * \class EventStateMachine * * \brief Super-class that provides the functionality of a StateMachine to DataInteractors. * * A state machine is created by loading a state machine pattern. It consists of states, transitions and action. * The state represent the current status of the interaction, transitions are means to switch between states. Each transition * is triggered by an event and it is associated with actions that are to be executed when the state change is performed. * */ class MITK_CORE_EXPORT EventStateMachine : public mitk::InteractionEventHandler { public: mitkClassMacro(EventStateMachine, InteractionEventHandler) itkNewMacro(Self) - typedef std::map ActionFunctionsMapType; + + typedef std::map DEPRECATED(ActionFunctionsMapType); + typedef itk::SmartPointer StateMachineStateType; /** * @brief Loads XML resource * * Loads a XML resource file in the given module context. * Default is the Mitk module (core). * The files have to be placed in the Resources/Interaction folder of their respective module. **/ bool LoadStateMachine(const std::string& filename, const std::string& moduleName="Mitk"); /** * Receives Event from Dispatcher. * Event is mapped using the EventConfig Object to a variant, then it is checked if the StateMachine is listening for * such an Event. If this is the case, the transition to the next state it performed and all actions associated with the transition executed, * and true is returned to the caller. * If the StateMachine can't handle this event false is returned. * Attention: * If a transition is associated with multiple actions - "true" is returned if one action returns true, * and the event is treated as HANDLED even though some actions might not have been executed! So be sure that all actions that occur within * one transitions have the same conditions. */ bool HandleEvent(InteractionEvent* event, DataNode* dataNode); protected: EventStateMachine(); virtual ~EventStateMachine(); + + typedef MessageAbstractDelegate2 ActionFunctionDelegate; + /** * Connects action from StateMachine (String in XML file) with a function that is called when this action is to be executed. */ - void AddActionFunction(const std::string action, TActionFunctor* functor); + DEPRECATED(void AddActionFunction(const std::string& action, TActionFunctor* functor)); + + void AddActionFunction(const std::string& action, const ActionFunctionDelegate& delegate); StateMachineState* GetCurrentState() const; /** * Is called after loading a statemachine. * Overwrite this function in specific interactor implementations. * Connect actions and functions using the CONNECT_FUNCTION macro within this function. */ virtual void ConnectActionsAndFunctions(); /** * Looks up function that is associated with action and executes it. * To implement your own execution scheme overwrite this in your DataInteractor. */ virtual bool ExecuteAction(StateMachineAction* action, InteractionEvent* interactionEvent); /** * Implements filter scheme for events. * Standard implementation accepts events from 2d and 3d windows, * and rejects events if DataNode is not visible. * \return true if event is accepted, else false * * Overwrite this function to adapt for your own needs, for example to filter out events from * 3d windows like this: \code bool mitk::EventStateMachine::FilterEvents(InteractionEvent* interactionEvent, DataNode*dataNode) { return interactionEvent->GetSender()->GetMapperID() == BaseRenderer::Standard2D; // only 2D mappers } \endcode * or to enforce that the interactor only reacts when the corresponding DataNode is selected in the DataManager view.. */ virtual bool FilterEvents(InteractionEvent* interactionEvent, DataNode* dataNode); private: + + typedef std::map ActionDelegatesMapType; + StateMachineContainer* m_StateMachineContainer; // storage of all states, action, transitions on which the statemachine operates. - ActionFunctionsMapType m_ActionFunctionsMap; // stores association between action string + std::map m_ActionFunctionsMap; // stores association between action string + ActionDelegatesMapType m_ActionDelegatesMap; StateMachineStateType m_CurrentState; }; } /* namespace mitk */ #endif /* MITKEVENTSTATEMACHINE_H_ */