diff --git a/Core/Code/Interactions/mitkStateMachineFactory.cpp b/Core/Code/Interactions/mitkStateMachineFactory.cpp index 29da306c5d..68c855cb0d 100755 --- a/Core/Code/Interactions/mitkStateMachineFactory.cpp +++ b/Core/Code/Interactions/mitkStateMachineFactory.cpp @@ -1,468 +1,478 @@ /*=================================================================== - The Medical Imaging Interaction Toolkit (MITK) +The Medical Imaging Interaction Toolkit (MITK) - Copyright (c) German Cancer Research Center, - Division of Medical and Biological Informatics. - All rights reserved. +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. +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. +See LICENSE.txt or http://www.mitk.org for details. - ===================================================================*/ +===================================================================*/ #include "mitkStateMachineFactory.h" #include "mitkGlobalInteraction.h" #include #include #include #include #include // us #include "mitkModule.h" #include "mitkModuleResource.h" #include "mitkModuleResourceStream.h" #include "mitkModuleRegistry.h" /** * @brief This class builds up all the necessary structures for a statemachine. * and stores one start-state for all built statemachines. **/ //mitk::StateMachineFactory::StartStateMap mitk::StateMachineFactory::m_StartStates; //mitk::StateMachineFactory::AllStateMachineMapType mitk::StateMachineFactory::m_AllStateMachineMap; //std::string mitk::StateMachineFactory::s_LastLoadedBehavior; + //XML StateMachine const std::string STYLE = "STYLE"; const std::string NAME = "NAME"; const std::string ID = "ID"; const std::string START_STATE = "START_STATE"; const std::string NEXT_STATE_ID = "NEXT_STATE_ID"; const std::string EVENT_ID = "EVENT_ID"; const std::string SIDE_EFFECT_ID = "SIDE_EFFECT_ID"; const std::string ISTRUE = "TRUE"; const std::string ISFALSE = "FALSE"; const std::string CONFIG = "stateMachine"; const std::string STATE = "state"; const std::string TRANSITION = "transition"; const std::string STATE_MACHINE_NAME = "stateMachine"; const std::string ACTION = "action"; const std::string BOOL_PARAMETER = "boolParameter"; const std::string INT_PARAMETER = "intParameter"; const std::string FLOAT_PARAMETER = "floatParameter"; const std::string DOUBLE_PARAMETER = "doubleParameter"; const std::string STRING_PARAMETER = "stringParameter"; const std::string VALUE = "VALUE"; #include namespace mitk { vtkStandardNewMacro(StateMachineFactory); } -mitk::StateMachineFactory::StateMachineFactory() : - m_AktStateMachineName(""), m_SkipStateMachine(false) +mitk::StateMachineFactory::StateMachineFactory() + : m_AktTransition(NULL) + , m_AktStateMachineName("") + , m_SkipStateMachine(false) { } mitk::StateMachineFactory::~StateMachineFactory() { //free memory while (!m_AllStateMachineMap.empty()) { StateMachineMapType* temp = m_AllStateMachineMap.begin()->second; m_AllStateMachineMap.erase(m_AllStateMachineMap.begin()); delete temp; } //should not be necessary due to SmartPointers m_StartStates.clear(); - - //delete WeakPointer - if (m_AktTransition) - delete m_AktTransition; } + /** * @brief Returns NULL if no entry with string type is found. **/ mitk::State* mitk::StateMachineFactory::GetStartState(const char * type) { StartStateMapIter tempState = m_StartStates.find(type); if (tempState != m_StartStates.end()) return (tempState)->second.GetPointer(); MITK_ERROR<< "Error in StateMachineFactory: StartState for pattern \""<< type<< "\"not found! StateMachine might not work!\n"; return NULL; } /** * @brief Loads the xml file filename and generates the necessary instances. **/ bool mitk::StateMachineFactory::LoadBehavior(std::string fileName) { if (fileName.empty()) return false; m_LastLoadedBehavior = fileName; this->SetFileName(fileName.c_str()); return this->Parse(); } /** * @brief Loads the xml string and generates the necessary instances. **/ bool mitk::StateMachineFactory::LoadBehaviorString(std::string xmlString) { if (xmlString.empty()) return false; m_LastLoadedBehavior = "String"; return (this->Parse(xmlString.c_str(), (unsigned int) xmlString.length())); } bool mitk::StateMachineFactory::LoadStandardBehavior() { Module* module = ModuleRegistry::GetModule("Mitk"); ModuleResource resource = module->GetResource("Interactions/Legacy/StateMachine.xml"); if (!resource.IsValid()) { mitkThrow()<< ("Resource not valid. State machine pattern not found:Interactions/Legacy/StateMachine.xml" ); } mitk::ModuleResourceStream stream(resource); std::string patternString((std::istreambuf_iterator(stream)), std::istreambuf_iterator()); return this->LoadBehaviorString(patternString); } /** * @brief Recursive method, that parses this brand of * the stateMachine; if the history has the same * size at the end, then the StateMachine is correct **/ bool mitk::StateMachineFactory::RParse(mitk::State::StateMap* states, mitk::State::StateMapIter thisState, HistorySet *history) { history->insert((thisState->second)->GetId()); //log our path //or thisState->first. but this seems safer std::set nextStatesSet = (thisState->second)->GetAllNextStates(); //remove loops in nextStatesSet; //nether do we have to go there, nor will it clear a deadlock std::set::iterator position = nextStatesSet.find((thisState->second)->GetId()); //look for the same state in nextStateSet if (position != nextStatesSet.end()) { //found the same state we are in! nextStatesSet.erase(position); //delete it, cause, we don't have to go there a second time! } //nextStatesSet is empty, so deadlock! if (nextStatesSet.empty()) { MITK_INFO<::iterator i = nextStatesSet.begin(); i != nextStatesSet.end(); i++) { if (history->find(*i) == history->end()) //if we haven't been in this nextstate { mitk::State::StateMapIter nextState = states->find(*i); //search the iterator for our nextState if (nextState == states->end()) { MITK_INFO<size() > 1) //only one state; don't have to be parsed for deadlocks! { //parse all the given states an check for deadlock or not connected states HistorySet *history = new HistorySet; mitk::State::StateMapIter firstState = states->begin(); //parse through all the given states, log the parsed elements in history bool ok = RParse(states, firstState, history); if ((states->size() == history->size()) && ok) { delete history; } else //ether !ok or sizeA!=sizeB { delete history; MITK_INFO<begin(); tempState != states->end(); tempState++) { //searched through the States and Connects all Transitions bool tempbool = ( ( tempState->second )->ConnectTransitions( states ) ); if ( tempbool == false ) { MITK_INFO< ok = m_AllStatesOfOneStateMachine.insert(mitk::State::StateMap::value_type(id , m_AktState)); if ( ok.second == false ) { MITK_INFO<AddTransition( m_AktTransition ); + { + mitk::Transition* transition = new Transition(transitionName, nextStateId, eventId); + if (!m_AktState->AddTransition( transition )) + { + delete transition; + m_AktTransition = const_cast(m_AktState->GetTransition(eventId)); + } + else + { + m_AktTransition = transition; + } + } } - else if ( name == ACTION ) + else if ( name == ACTION && m_AktTransition) { int actionId = ReadXMLIntegerAttribut( ID, atts ); m_AktAction = Action::New( actionId ); m_AktTransition->AddAction( m_AktAction ); } else if ( name == BOOL_PARAMETER ) { if ( !m_AktAction ) return; bool value = ReadXMLBooleanAttribut( VALUE, atts ); std::string name = ReadXMLStringAttribut( NAME, atts ); m_AktAction->AddProperty( name.c_str(), BoolProperty::New( value ) ); } else if ( name == INT_PARAMETER ) { if ( !m_AktAction ) return; int value = ReadXMLIntegerAttribut( VALUE, atts ); std::string name = ReadXMLStringAttribut( NAME, atts ); m_AktAction->AddProperty( name.c_str(), IntProperty::New( value ) ); } else if ( name == FLOAT_PARAMETER ) { if ( !m_AktAction ) return; float value = ReadXMLIntegerAttribut( VALUE, atts ); std::string name = ReadXMLStringAttribut( NAME, atts ); m_AktAction->AddProperty( name.c_str(), FloatProperty::New( value ) ); } else if ( name == DOUBLE_PARAMETER ) { if ( !m_AktAction ) return; double value = ReadXMLDoubleAttribut( VALUE, atts ); std::string name = ReadXMLStringAttribut( NAME, atts ); m_AktAction->AddProperty( name.c_str(), DoubleProperty::New( value ) ); } else if ( name == STRING_PARAMETER ) { if ( !m_AktAction ) return; std::string value = ReadXMLStringAttribut( VALUE, atts ); std::string name = ReadXMLStringAttribut( NAME, atts ); m_AktAction->AddProperty( name.c_str(), StringProperty::New( value ) ); } } void mitk::StateMachineFactory::EndElement(const char* elementName) { //bool ok = true; std::string name(elementName); //skip the state machine pattern because the name was not unique! if (m_SkipStateMachine && (name != CONFIG)) return; if (name == STATE_MACHINE_NAME) { if (m_SkipStateMachine) { m_SkipStateMachine = false; return; } /*ok =*/ConnectStates(&m_AllStatesOfOneStateMachine); m_AllStatesOfOneStateMachine.clear(); } else if (name == CONFIG) { //doesn't have to be done } else if (name == TRANSITION) { m_AktTransition = NULL; //pointer stored in its state. memory will be freed in destructor of class state } else if (name == ACTION) { m_AktAction = NULL; } else if (name == STATE) { m_AktState = NULL; } } std::string mitk::StateMachineFactory::ReadXMLStringAttribut(std::string name, const char** atts) { if (atts) { const char** attsIter = atts; while (*attsIter) { if (name == *attsIter) { attsIter++; return *attsIter; } attsIter++; attsIter++; } } return std::string(); } int mitk::StateMachineFactory::ReadXMLIntegerAttribut(std::string name, const char** atts) { std::string s = ReadXMLStringAttribut(name, atts); return atoi(s.c_str()); } float mitk::StateMachineFactory::ReadXMLFloatAttribut(std::string name, const char** atts) { std::string s = ReadXMLStringAttribut(name, atts); return (float) atof(s.c_str()); } double mitk::StateMachineFactory::ReadXMLDoubleAttribut(std::string name, const char** atts) { std::string s = ReadXMLStringAttribut(name, atts); return atof(s.c_str()); } bool mitk::StateMachineFactory::ReadXMLBooleanAttribut(std::string name, const char** atts) { std::string s = ReadXMLStringAttribut(name, atts); if (s == ISTRUE) return true; else return false; } mitk::State* mitk::StateMachineFactory::GetState(const char * type, int StateId) { //check if the state exists AllStateMachineMapType::iterator i = m_AllStateMachineMap.find(type); if (i == m_AllStateMachineMap.end()) return NULL; //get the statemachine of the state StateMachineMapType* sm = m_AllStateMachineMap[type]; //get the state from its statemachine if (sm != NULL) return (*sm)[StateId].GetPointer(); else return NULL; } bool mitk::StateMachineFactory::AddStateMachinePattern(const char * type, mitk::State* startState, mitk::StateMachineFactory::StateMachineMapType* allStatesOfStateMachine) { if (startState == NULL || allStatesOfStateMachine == NULL) return false; //check if the pattern has already been added StartStateMapIter tempState = m_StartStates.find(type); if (tempState != m_StartStates.end()) { MITK_WARN<< "Pattern " << type << " has already been added!\n"; return false; } //add the start state m_StartStates.insert(StartStateMap::value_type(type, startState)); //add all states of the new pattern to hold their references m_AllStateMachineMap.insert(AllStateMachineMapType::value_type(type, allStatesOfStateMachine)); return true; } diff --git a/Core/Code/Interactions/mitkStateMachineFactory.h b/Core/Code/Interactions/mitkStateMachineFactory.h index 9840a80224..2ee96d0d4f 100755 --- a/Core/Code/Interactions/mitkStateMachineFactory.h +++ b/Core/Code/Interactions/mitkStateMachineFactory.h @@ -1,232 +1,232 @@ /*=================================================================== 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 STATEMACHINEFACTORY_H_HEADER_INCLUDED_C19AEDDD #define STATEMACHINEFACTORY_H_HEADER_INCLUDED_C19AEDDD #include #include "mitkState.h" #include "mitkTransition.h" #include "mitkAction.h" #include #include #include namespace mitk { /** *@brief builds up all specifiyed statemachines and hold them for later access * * According to the XML-File every different statemachine is build up. A new * instance of a new StateMachine grabs a StartState of one certain * state machine. Two instances of one kind of state machine share that * state machine. * During buildprocess at runtime each state machine is parsed for well formed style. * Currently different interaction styles are not yet supported. * To add individual state machine patterns, call LoadBehavior(...) * and it will be parsed added to the internal list of patterns * * @ingroup Interaction **/ /** * \deprecatedSince{2013_03} StateMachineFactory is deprecated. Please use mitk::StateMachineContainer instead. * Refer to \see DataInteractionPage for general information about the concept of the new implementation. */ class MITK_CORE_EXPORT StateMachineFactory : public vtkXMLParser { public: static StateMachineFactory *New(); vtkTypeMacro(StateMachineFactory,vtkXMLParser); /** * @brief Typedef for all states that are defined as start-states **/ typedef std::map StartStateMap; typedef StartStateMap::iterator StartStateMapIter; /** * @brief Typedef to be used for parsing all states of one statemachine **/ typedef std::set HistorySet; typedef HistorySet::iterator HistorySetIter; /** * @brief This type holds all states of one statemachine. **/ typedef std::map StateMachineMapType; /** * @brief this type holds all states of all statemachines so that a specific state can be accessed for persistence **/ typedef std::map AllStateMachineMapType; /** * @brief Returns the StartState of the StateMachine with the name type; * * Returns NULL if no entry with name type is found. * Here a Smartpointer is returned to ensure, that StateMachines are also considered during reference counting. **/ State* GetStartState(const char* type); /** * @brief loads the xml file filename and generates the necessary instances **/ bool LoadBehavior(std::string fileName); /** * @brief loads the xml string and generates the necessary instances **/ bool LoadBehaviorString(std::string xmlString); /** * @brief Try to load standard behavior file "StateMachine.xml" * * Search strategy: * \li try environment variable "MITKCONF" (path to "StateMachine.xml") * \li try "./StateMachine.xml" * \li try via source directory (using MITKROOT from cmake-created * mitkConfig.h) "MITKROOT/Interactions/mitkBaseInteraction/StateMachine.xml" **/ bool LoadStandardBehavior(); const std::string& GetLastLoadedBehavior() { return m_LastLoadedBehavior; } /** * @brief Adds the given pattern to the internal list of patterns * * Method to support addition of externaly loaded patterns. * Instances of states, transitions and actions are maintained within this class and freed on destruction. * The states already have to be connected by transitions and actions and checked for errors. * @params type name of the pattern to add. Will be used during initialization of a new interactor. * @params startState the start state of this pattern. * @params allStatesOfStateMachine a map of state ids and its states to hold their reference and delete them in destructor **/ bool AddStateMachinePattern(const char * type, mitk::State* startState, StateMachineMapType* allStatesOfStateMachine); /** * brief To enable StateMachine to access states **/ friend class StateMachine; protected: /** * @brief Default Constructor **/ StateMachineFactory(); /** * @brief Default Destructor **/ ~StateMachineFactory(); /** * @brief Derived from XMLReader **/ void StartElement (const char* elementName, const char **atts); /** * @brief Derived from XMLReader **/ void EndElement (const char* elementName); private: /** * @brief Derived from XMLReader **/ std::string ReadXMLStringAttribut( std::string name, const char** atts); /** * @brief Derived from XMLReader **/ float ReadXMLFloatAttribut( std::string name, const char** atts ); /** * @brief Derived from XMLReader **/ double ReadXMLDoubleAttribut( std::string name, const char** atts ); /** * @brief Derived from XMLReader **/ int ReadXMLIntegerAttribut( std::string name, const char** atts ); /** * @brief Derived from XMLReader **/ bool ReadXMLBooleanAttribut( std::string name, const char** atts ); /** * @brief Returns a Pointer to the desired state if found. **/ mitk::State* GetState( const char* type, int StateId ); /** * @brief Sets the pointers in Transition (setNextState(..)) according to the extracted xml-file content **/ bool ConnectStates(mitk::State::StateMap* states); /** * @brief Recusive method, that parses this pattern of the stateMachine and returns true if correct **/ bool RParse(mitk::State::StateMap* states, mitk::State::StateMapIter thisState, HistorySet *history); /** * @brief Holds all created States that are defined as StartState **/ StartStateMap m_StartStates; /** * @brief Holds all States of one StateMachine to build up the pattern. **/ mitk::State::StateMap m_AllStatesOfOneStateMachine; /** * @brief A pointer to a State to help building up the pattern **/ State::Pointer m_AktState; /** * @brief A pointer to a Transition to help building up the pattern **/ - itk::WeakPointer m_AktTransition; + Transition* m_AktTransition; /** * @brief A pointer to an Action to help building up the pattern **/ Action::Pointer m_AktAction; /** * @brief map to hold all statemachines to call GetState for friends **/ AllStateMachineMapType m_AllStateMachineMap; std::string m_LastLoadedBehavior; std::string m_AktStateMachineName; /** * @brief Variable to skip a state machine pattern if the state machine name is not unique **/ bool m_SkipStateMachine; }; } // namespace mitk #endif /* STATEMACHINEFACTORY_H_HEADER_INCLUDED_C19AEDDD */