diff --git a/Core/Code/Interactions/mitkGlobalInteraction.cpp b/Core/Code/Interactions/mitkGlobalInteraction.cpp index a73ccb5d74..4fb2cb141a 100755 --- a/Core/Code/Interactions/mitkGlobalInteraction.cpp +++ b/Core/Code/Interactions/mitkGlobalInteraction.cpp @@ -1,457 +1,510 @@ /*=================================================================== 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 "mitkGlobalInteraction.h" #include "mitkInteractionConst.h" #include "mitkStateEvent.h" #include "mitkPositionEvent.h" #include #include mitk::GlobalInteraction::GlobalInteraction() : StateMachine(NULL) , m_StateMachineFactory(NULL) , m_EventMapper(NULL) , m_CurrentlyInInformListenersLoop(false) , m_CurrentlyInInformInteractorsLoop(false) , m_IsInitialized(false) +, m_EventNotificationPolicy(INFORM_MULTIPLE) { } mitk::GlobalInteraction::~GlobalInteraction() { //s_GlobalInteraction doesn't have to be set = NULL; // StateMachineFactory and EventMapper have to be deleted explicitly, as they inherit from Vtk if (this->IsInitialized()) { m_StateMachineFactory->Delete(); m_StateMachineFactory = NULL; m_EventMapper->Delete(); m_EventMapper = NULL; } m_ListenerList.clear(); m_InteractorList.clear(); m_SelectedList.clear(); - m_JurisdictionMap.clear(); + m_InteractorJurisdictionMap.clear(); + m_ListenerJurisdictionMap.clear(); m_FocusManager = NULL; } inline mitk::StateEvent* GenerateEmptyStateEvent(int eventId) { mitk::Event *noEvent = new mitk::Event(NULL, mitk::Type_User, mitk::BS_NoButton, mitk::BS_NoButton, mitk::Key_none); mitk::StateEvent *stateEvent = new mitk::StateEvent(eventId, noEvent); return stateEvent; } void mitk::GlobalInteraction::AddListener(mitk::StateMachine* listener) { if(listener == NULL) return; if(dynamic_cast(listener)!=NULL) { MITK_WARN << "Trying to add an Interactor (" << listener->GetNameOfClass() << ") as a listener. " << "This will probably cause problems"; } if ( std::find(m_ListenerList.begin(), m_ListenerList.end(),listener) == m_ListenerList.end() ) { m_ListenerList.push_back(listener); } } bool mitk::GlobalInteraction::RemoveListener(mitk::StateMachine* listener) { // Defers removal to a time after the current event handling is finished. Otherwise the implementation of InformListeners would crash sometimes. m_ListenersFlaggedForRemoval.push_back(listener); StateMachineListIter position = std::find(m_ListenerList.begin(), m_ListenerList.end(),listener); bool removePossible = (position != m_ListenerList.end()); RemoveFlaggedListeners(); + //check if in JurisdictionMap + for (StateMachineMapIter it = m_ListenerJurisdictionMap.begin(); it != m_ListenerJurisdictionMap.end(); it++) + { + if ((*it).second == listener) + { + m_ListenerJurisdictionMap.erase(it); + break; + } + } + return removePossible; } void mitk::GlobalInteraction::RemoveFlaggedListeners() { if (m_CurrentlyInInformListenersLoop) return; // iterate flagged listeners, remove them if possible if (m_ListenersFlaggedForRemoval.empty()) return; for (StateMachineCPointerListIter it = m_ListenersFlaggedForRemoval.begin(); it != m_ListenersFlaggedForRemoval.end(); ++it) { StateMachineListIter foundPosition = std::find( m_ListenerList.begin(), m_ListenerList.end(), *it ); if (foundPosition != m_ListenerList.end()) { m_ListenerList.erase( foundPosition ); } } m_ListenersFlaggedForRemoval.clear(); } void mitk::GlobalInteraction::AddInteractor(mitk::Interactor* interactor) { if(interactor == NULL) return; if ( std::find(m_InteractorList.begin(), m_InteractorList.end(),interactor) == m_InteractorList.end() ) { m_InteractorList.push_back(interactor); //if Interactor already selected, then add to selected list if (interactor->GetMode()==Interactor::SMSELECTED) this->AddToSelectedInteractors(interactor); } } bool mitk::GlobalInteraction::InteractorRegistered (mitk::Interactor* interactor) { if ( std::find(m_InteractorList.begin(), m_InteractorList.end(), interactor) == m_InteractorList.end() ) return false; else return true; } bool mitk::GlobalInteraction::ListenerRegistered (mitk::StateMachine* listener) { if ( std::find(m_ListenerList.begin(), m_ListenerList.end(), listener) == m_ListenerList.end() ) return false; else return true; } bool mitk::GlobalInteraction::RemoveInteractor(mitk::Interactor* interactor) { InteractorListIter position = std::find(m_InteractorList.begin(), m_InteractorList.end(),interactor); if (position == m_InteractorList.end()) return false; position = m_InteractorList.erase(position); //check if the interactor is also held in SelectedList this->RemoveFromSelectedInteractors(interactor); //check if in JurisdictionMap - for (InteractorMapIter it = m_JurisdictionMap.begin(); it != m_JurisdictionMap.end(); it++) + for (InteractorMapIter it = m_InteractorJurisdictionMap.begin(); it != m_InteractorJurisdictionMap.end(); it++) { if ((*it).second == interactor) { if (m_CurrentInteractorIter == it) - m_CurrentInteractorIter = m_JurisdictionMap.end(); - m_JurisdictionMap.erase(it); + m_CurrentInteractorIter = m_InteractorJurisdictionMap.end(); + m_InteractorJurisdictionMap.erase(it); break; } } return true; } void mitk::GlobalInteraction::InformListeners(mitk::StateEvent const* stateEvent) { m_CurrentlyInInformListenersLoop = true; for (StateMachineListIter it = m_ListenerList.begin(); it != m_ListenerList.end(); it++) { if((*it).IsNotNull()) (*it)->HandleEvent(stateEvent); } m_CurrentlyInInformListenersLoop = false; RemoveFlaggedListeners(); } bool mitk::GlobalInteraction::AskSelected(mitk::StateEvent const* stateEvent) { if (m_SelectedList.empty()) return false; bool ok = false, oneOk = false; //copy of m_SelectedList to be stable if an iterator gets removed during the following steps InteractorList copyOfSelectedList = m_SelectedList; InteractorListIter it = copyOfSelectedList.begin(); for (; it != copyOfSelectedList.end(); it++) { oneOk = (*it)->HandleEvent(stateEvent); //if one HandleEvent did succeed, then set returnvalue on true; if (oneOk) ok = true; } return ok; } -void mitk::GlobalInteraction::FillJurisdictionMap(mitk::StateEvent const* stateEvent, float threshold) +void mitk::GlobalInteraction::FillInteractorJurisdictionMap(mitk::StateEvent const* stateEvent, float threshold) { - m_JurisdictionMap.clear(); + m_InteractorJurisdictionMap.clear(); for (InteractorListIter it = m_InteractorList.begin(); it != m_InteractorList.end(); it++) { if ((*it).IsNotNull()) { //first ask for CanHandleEvent(..) and write it into the map if > 0 float value = (*it)->CanHandleEvent(stateEvent); if (value > threshold) { - m_JurisdictionMap.insert(InteractorMap::value_type(value, (*it))); + m_InteractorJurisdictionMap.insert(InteractorMap::value_type(value, (*it))); } } } //set the iterator to the first element to start stepping through interactors - if (! m_JurisdictionMap.empty()) - m_CurrentInteractorIter = m_JurisdictionMap.begin(); + if (! m_InteractorJurisdictionMap.empty()) + m_CurrentInteractorIter = m_InteractorJurisdictionMap.begin(); else - m_CurrentInteractorIter = m_JurisdictionMap.end(); + m_CurrentInteractorIter = m_InteractorJurisdictionMap.end(); +} + +void mitk::GlobalInteraction::FillListenerJurisdictionMap(const mitk::StateEvent *stateEvent, float threshold) +{ + m_ListenerJurisdictionMap.clear(); + + for (StateMachineListIter it = m_ListenerList.begin(); it != m_ListenerList.end(); it++) + { + if((*it).IsNotNull()) + { + float value = (*it)->CanHandleEvent(stateEvent); + if (value > threshold) + { + m_ListenerJurisdictionMap.insert(StateMachineMap::value_type(value, (*it))); + } + } + } } /* * Go through the list of interactors, that could possibly handle an event and ask if it has handled the event. * If an interactor has handled an event, it should add itself to the list of selectedInteractors * Ask as long as no interactor answers, that it could be handled */ bool mitk::GlobalInteraction::AskCurrentInteractor(mitk::StateEvent const* stateEvent) { - //no need to check if we don't have any interactors. nearly equal to m_CurrentInteractorIter == m_JurisdictionMap.end - if (m_JurisdictionMap.empty()) + //no need to check if we don't have any interactors. nearly equal to m_CurrentInteractorIter == m_InteractorJurisdictionMap.end + if (m_InteractorJurisdictionMap.empty()) return false; bool handled = false; - while ( m_CurrentInteractorIter != m_JurisdictionMap.end()&& !handled) + while ( m_CurrentInteractorIter != m_InteractorJurisdictionMap.end()&& !handled) { handled = (*m_CurrentInteractorIter).second->HandleEvent(stateEvent); if (!handled) m_CurrentInteractorIter++; } //loop for later usage - if (m_CurrentInteractorIter == m_JurisdictionMap.end()) - m_CurrentInteractorIter = m_JurisdictionMap.begin(); + if (m_CurrentInteractorIter == m_InteractorJurisdictionMap.end()) + m_CurrentInteractorIter = m_InteractorJurisdictionMap.begin(); return handled; } bool mitk::GlobalInteraction::AddFocusElement(mitk::FocusManager::FocusElement* element) { return m_FocusManager->AddElement(element); } bool mitk::GlobalInteraction::RemoveFocusElement(mitk::FocusManager::FocusElement* element) { return m_FocusManager->RemoveElement(element); } mitk::FocusManager::FocusElement* mitk::GlobalInteraction::GetFocus() { return m_FocusManager->GetFocused(); } bool mitk::GlobalInteraction::SetFocus(mitk::FocusManager::FocusElement* element) { return m_FocusManager->SetFocused(element); } mitk::FocusManager* mitk::GlobalInteraction::GetFocusManager() { return m_FocusManager.GetPointer(); } mitk::EventMapper* mitk::GlobalInteraction::GetEventMapper() { if (!this->IsInitialized()) { MITK_FATAL <<"Global Interaction needs initialization!\n"; return NULL; } return m_EventMapper; } bool mitk::GlobalInteraction::ExecuteAction(Action* action, mitk::StateEvent const* stateEvent) { bool ok = false; ok = false; switch (action->GetActionId()) { case AcDONOTHING: ok = true; break; case AcINFORMLISTENERS: - InformListeners(stateEvent); - ok = true; - break; + if (m_EventNotificationPolicy == INFORM_MULTIPLE) + { + InformListeners(stateEvent); + ok = true; + break; + } + else + { + //0.5 since this is the default value which is returned by the superclass implementation of statemachine + this->FillListenerJurisdictionMap(stateEvent, 0.5); + if (!m_ListenerJurisdictionMap.empty()) + { + StateMachineMapIter iter = m_ListenerJurisdictionMap.begin(); + ok = (*iter).second->HandleEvent(stateEvent); + } + break; + } case AcASKINTERACTORS: if (! AskSelected(stateEvent))//no interactor selected anymore { //fill the jurisdictionMap to ask them bit by bit. //currentInteractor is set here to the beginning - FillJurisdictionMap(stateEvent, 0); + FillInteractorJurisdictionMap(stateEvent, 0); //ask the Interactors to handle that event AskCurrentInteractor(stateEvent); } ok = true; break; default: ok = true; } return ok; } mitk::GlobalInteraction* mitk::GlobalInteraction::GetInstance() { static mitk::GlobalInteraction::Pointer s_GlobalInteraction; if (s_GlobalInteraction.IsNull()) { s_GlobalInteraction = mitk::GlobalInteraction::New(); } return s_GlobalInteraction; } mitk::State* mitk::GlobalInteraction::GetStartState(const char* type) { if ( this->IsInitialized() ) return m_StateMachineFactory->GetStartState(type); MITK_FATAL << "Fatal Error in mitkGlobalInteraction.cpp: GlobalInteraction not initialized!\n"; return NULL; } bool mitk::GlobalInteraction::AddToSelectedInteractors(mitk::Interactor* interactor) { InteractorListIter position = std::find(m_SelectedList.begin(), m_SelectedList.end(),interactor); if (position != m_SelectedList.end()) { //already added so don't add once more! return true; } else m_SelectedList.push_back(interactor); return true; } bool mitk::GlobalInteraction::RemoveFromSelectedInteractors(mitk::Interactor* interactor) { if (interactor == NULL) return false; InteractorListIter position = std::find(m_SelectedList.begin(), m_SelectedList.end(),interactor); if (position != m_SelectedList.end()) { position = m_SelectedList.erase(position); return true; } else return false; } mitk::StateMachineFactory* mitk::GlobalInteraction::GetStateMachineFactory() { return m_StateMachineFactory; } bool mitk::GlobalInteraction::Initialize(const char* globalInteractionName, const std::string XMLBehaviorInput) { if (this->IsInitialized()) { MITK_WARN <<"Global Interaction has already been initialized.\n"; return false; } m_FocusManager = FocusManager::New(); // instantiates m_StateMachineFactory and load interaction patterns from XML string //if factory has been initialized before, delete it and initialize once more to not add patterns if (m_StateMachineFactory) m_StateMachineFactory->Delete(); m_StateMachineFactory = StateMachineFactory::New(); //if EventMapper was initialized before, delete it and initialize once more // to create new event descriptions and not to add them if (m_EventMapper) m_EventMapper->Delete(); m_EventMapper = EventMapper::New(); bool success = true; if (XMLBehaviorInput == "") { //load default behavior success &= m_StateMachineFactory->LoadStandardBehavior(); success &= m_EventMapper->LoadStandardBehavior(); } else if (itksys::SystemTools::FileExists(XMLBehaviorInput.c_str()) ) { // load standard behavior from file success &= m_StateMachineFactory->LoadBehavior(XMLBehaviorInput); success &= m_EventMapper->LoadBehavior(XMLBehaviorInput); } else { //load standard behavior from XML string success &= m_StateMachineFactory->LoadBehaviorString(XMLBehaviorInput); success &= m_EventMapper->LoadBehaviorString(XMLBehaviorInput); } if(!success) { MITK_FATAL << "Error initializing global interaction!\n"; return false; } //now instantiate what could not be done in InitializeStateStates because StateMachineFactory was not up yet: // (Re-) Initialize Superclass (StateMachine), because type was not given at time of construction m_Type = globalInteractionName; //get the start state of the pattern State::Pointer startState = m_StateMachineFactory->GetStartState(globalInteractionName); if (startState.IsNull()) { MITK_FATAL << "Fatal Error in mitkGlobalInteraction.cpp: No StartState recieved from StateMachineFactory!\n"; return false; } //clear the vector m_CurrentStateVector.clear(); //add the start state pointer for the first time step to the list m_CurrentStateVector.push_back(startState); m_IsInitialized = true; return true; } +void mitk::GlobalInteraction::SetEventNotificationPolicy(EVENT_NOTIFICATION_POLICY policy) +{ + this->m_EventNotificationPolicy = policy; +} + +mitk::GlobalInteraction::EVENT_NOTIFICATION_POLICY mitk::GlobalInteraction::GetEventNotificationPolicy() +{ + return this->m_EventNotificationPolicy; +} + diff --git a/Core/Code/Interactions/mitkGlobalInteraction.h b/Core/Code/Interactions/mitkGlobalInteraction.h index 8947e9e0e7..34b3daf11a 100755 --- a/Core/Code/Interactions/mitkGlobalInteraction.h +++ b/Core/Code/Interactions/mitkGlobalInteraction.h @@ -1,274 +1,309 @@ /*=================================================================== 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 GLOBALINTERACTION_H_HEADER_INCLUDED_C152938A #define GLOBALINTERACTION_H_HEADER_INCLUDED_C152938A #include "mitkFocusManager.h" #include #include "mitkStateMachineFactory.h" #include "mitkEventMapper.h" #include "mitkInteractor.h" namespace mitk { class PositionEvent; //##Documentation //## @brief handles all global Events //## //## superior statemachine, that spreads the events to all other interactors //## //## Initialization //## Attention: GlobalInteraction must be initialized by the Initialize() method //## before usage by giving it an XML scheme. Possibilities are giving it an empty string (default), //## the filename of an XML file or the actual XML content as std::string. If an empty string is given, //## the content is tried to be loaded from the default file location. //## //## Concept of sending events: //## In this concept of interaction, the statemachines can be divided into two main statemachines: //## Listeners and interactors. //## Listeners only receive the event to process it, but don't change any data. They want to listen to all events. //## Interactors do change data according to the received event. They do not need to receive all events, only //## those they are interested in. //## //## To divide these two types of statemachine this class holds three lists and one map: //## m_ListenerList, m_InteractorList, m_SelectedList and m_JurisdictionMap //## The list m_ListenerList holds all listeners. //## m_InteractorList holds all interactors, and the List m_SelectedList holds all machines, that were set to SELECTED or SUBSELECTED. //## m_JurisdictionMap maps values returned from CanHandleEvent to the asked Interactors. //## Through this map stepping through interactors, that were not selected and could handle that event, can be done. //## //## First the listeners are informed with the event. //## Then the selected or subselected interactors are asked if they can handle that event. //## They can handle it, if the mode of the interactor after HandleEvent(..) is still in SMSELECTED or SMSUBSELECTED. //## They can't handle it, if the mode changed to SMDESELECTED. Then the interactor is removed from the selected-list. //## In that case, all interactors are asked to calculate and return their area of jurisdiction. //## An iterator is held on one interactor in the map. With the iterator, the map can be looped through so //## so that several geometric objects, that lie on top of each other, can be selected. //## @ingroup Interaction class MITK_CORE_EXPORT GlobalInteraction : public StateMachine { public: mitkClassMacro(GlobalInteraction, StateMachine); itkNewMacro(Self); typedef std::vector StateMachineList; typedef std::vector StateMachineCPointerList; typedef StateMachineList::iterator StateMachineListIter; typedef StateMachineCPointerList::iterator StateMachineCPointerListIter; typedef std::vector InteractorList; typedef InteractorList::iterator InteractorListIter; typedef std::multimap > InteractorMap; + typedef std::multimap > StateMachineMap; typedef InteractorMap::iterator InteractorMapIter; + typedef StateMachineMap::iterator StateMachineMapIter; + + enum EVENT_NOTIFICATION_POLICY + { + INFORM_MULTIPLE, INFORM_ONE + }; //##Documentation //## @brief add an Interactor to the list of all interactors that are asked for handling an event //## //## returns true in case of success void AddInteractor(Interactor* interactor); //##Documentation //## @brief remove a certain Interactor from the set of interactors that are asked for handling an event //## //## returns true in case of success bool RemoveInteractor(Interactor* interactor); //##Documentation //## @brief returns true, if the given interactor is already added to the Interactor-List bool InteractorRegistered (Interactor* interactor); //##Documentation //## @brief add a Listener to the list of all Listeners that are informed of an event //## //## returns true in case of success void AddListener(StateMachine* listener); //##Documentation //## @brief remove a certain Listener from the set of Listeners that are informed of an event //## //## returns true in case of success bool RemoveListener(StateMachine* listener); //##Documentation //## @brief returns true, if the given interactor is already added to the Listener-List bool ListenerRegistered (StateMachine* listener); //##Documentation //## @brief adds an element in the list in FocusManager //## //## true if success, false if the element is already in list bool AddFocusElement(FocusManager::FocusElement* element); //##Documentation //## @brief Removes an element in FocusManager //## //## true if success, false if the element was not in the list bool RemoveFocusElement(FocusManager::FocusElement* element); //##Documentation //## @brief Returns the focused Element in FocusManager FocusManager::FocusElement* GetFocus(); //##Documentation //## @brief Sets the given Element to focused //## //## returns true if the given element was found and focused bool SetFocus(FocusManager::FocusElement* element); //##Documentation //## @brief Returns the pointer to the FocusManager //## //## to add the observer for an event FocusManager* GetFocusManager(); //##Documentation //## @brief Returns the pointer to the EventMapper //## //## to add an addon EventMapper* GetEventMapper(); /** * @brief Return StateMachineFactory **/ StateMachineFactory* GetStateMachineFactory(); /** * @brief Returns the StartState of the StateMachine with the name type; * * Asks member StateMachineFactory for the StartState. * Returns NULL if no entry with name type is found. **/ State* GetStartState(const char* type); //##Documentation //## @brief Returns the global (singleton) instance of //## GlobalInteraction. Create it, if it does not exist. static GlobalInteraction* GetInstance(); //##Documentation //## @brief Initializes the global (singleton) instance of //## GlobalInteraction via an XML string. Must! be done before usage. Can be done only once. //## Can be used with an empty string (default), a file name with path, or the actual XML content as string. bool Initialize(const char* globalInteractionName, const std::string XMLBehaviorInput = ""); //##Documentation //## @brief Check if GlobalInteraction has already been initialized. Init must! be done before usage. - bool IsInitialized() {return m_IsInitialized;}; + bool IsInitialized() {return m_IsInitialized;} + + /** + * @brief Set the policy of how the global interaction informs listeners and interactors + * + * INFORM_MULTIPLE broadcasts the event to all listeners and interactors that can handle the event + * INFORM_ONE only informs the listener or interactor which can handle the event best + **/ + void SetEventNotificationPolicy(EVENT_NOTIFICATION_POLICY); + + /** + * Return the current set eventspreading policy + * @returns the current event spreading policy + **/ + EVENT_NOTIFICATION_POLICY GetEventNotificationPolicy(); //so that the interactors can call AddToSelectedInteractors() and RemoveFromSelectedInteractors() friend class Interactor; protected: /** * @brief Default Constructor with type to load the StateMachinePattern of the StateMachine * @param XMLbehaviorFile the file which contains the statemachine and event patterns * @param type the name of the statemachine pattern this class shall use **/ GlobalInteraction(); /** * @brief Default destructor. **/ ~GlobalInteraction(); virtual bool ExecuteAction(Action* action, mitk::StateEvent const* stateEvent); /* *@brief adds the given interactor to the list of selected interactors. * This list is asked first to handle an event. */ virtual bool AddToSelectedInteractors(Interactor* interactor); /* *@brief removes the given interactor from the list of selected interactors * This list is asked first to handle an event. */ virtual bool RemoveFromSelectedInteractors(Interactor* interactor); private: //##Documentation //##@brief informing all statemachines that are held in the list m_ListenerList void InformListeners(mitk::StateEvent const* stateEvent); //##Documentation //##@brief asking the selected Interactor if an event can be handled //## //## returns false if no Interactor could handle the event bool AskSelected(mitk::StateEvent const* stateEvent); //##Documentation //##@brief asking next interactor of m_JurisdictionMap bool AskCurrentInteractor(mitk::StateEvent const* stateEvent); //##Documentation - //##@brief filling m_JurisdictionMap + //##@brief filling m_InteractorJurisdictionMap + //## + //## @ params threshold: if the calculated jurisdiction value is above swell, then add it to the map + void FillInteractorJurisdictionMap(mitk::StateEvent const* stateEvent, float threshold); + + //##Documentation + //##@brief filling m_ListenerJurisdictionMap //## - //## @ params swell: if the calculated jurisdiction value is above swell, then add it to the map - void FillJurisdictionMap(mitk::StateEvent const* stateEvent, float threshold); + //## @ params threshold: if the calculated jurisdiction value is above swell, then add it to the map + void FillListenerJurisdictionMap(mitk::StateEvent const* stateEvent, float threshold); void RemoveFlaggedListeners(); StateMachineCPointerList m_ListenersFlaggedForRemoval; //##Documentation //## @brief list of all listening statemachines, that want to receive all events StateMachineList m_ListenerList; //##Documentation //## @brief list of all interactors (statemachine, that change data) InteractorList m_InteractorList; //##Documentation //## @brief list of all interactors, that are in Mode SELECTED or SUBSELECTED InteractorList m_SelectedList; //##Documentation //## @brief map for sorting all interactors by the value returned from CanHandleEvent(..). //## //## With that list certain interactors can be looped through like diving through layers - InteractorMap m_JurisdictionMap; + InteractorMap m_InteractorJurisdictionMap; + + //##Documentation + //## @brief map for sorting all listeners by the value returned from CanHandleEvent(..). + //## + //## With that list certain listeners can be looped through like diving through layers + StateMachineMap m_ListenerJurisdictionMap; //##Documentation //## @brief iterator on an entry in m_JurisdictionMap for stepping through interactors InteractorMapIter m_CurrentInteractorIter; //##Documentation //## @brief holds a list of BaseRenderer and one focused FocusManager::Pointer m_FocusManager; /** * @brief StatemachineFactory loads statemachine patterns and provides start states **/ StateMachineFactory* m_StateMachineFactory; /** * @brief EventMapper loads event patterns **/ EventMapper* m_EventMapper; bool m_CurrentlyInInformListenersLoop; bool m_CurrentlyInInformInteractorsLoop; bool m_IsInitialized; + + EVENT_NOTIFICATION_POLICY m_EventNotificationPolicy; }; } // namespace mitk #endif /* GLOBALINTERACTION_H_HEADER_INCLUDED_C152938A */ diff --git a/Modules/MitkExt/Controllers/mitkToolManager.cpp b/Modules/MitkExt/Controllers/mitkToolManager.cpp index 70fccfbc7f..52c2dcc88f 100644 --- a/Modules/MitkExt/Controllers/mitkToolManager.cpp +++ b/Modules/MitkExt/Controllers/mitkToolManager.cpp @@ -1,495 +1,501 @@ /*=================================================================== 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 "mitkToolManager.h" #include "mitkGlobalInteraction.h" #include "mitkCoreObjectFactory.h" #include #include #include mitk::ToolManager::ToolManager(DataStorage* storage) :m_ActiveTool(NULL), m_ActiveToolID(-1), m_RegisteredClients(0), m_DataStorage(storage) { CoreObjectFactory::GetInstance(); // to make sure a CoreObjectFactory was instantiated (and in turn, possible tools are registered) - bug 1029 // get a list of all known mitk::Tools std::list thingsThatClaimToBeATool = itk::ObjectFactoryBase::CreateAllInstance("mitkTool"); // remember these tools for ( std::list::iterator iter = thingsThatClaimToBeATool.begin(); iter != thingsThatClaimToBeATool.end(); ++iter ) { if ( Tool* tool = dynamic_cast( iter->GetPointer() ) ) { tool->SetToolManager(this); // important to call right after instantiation tool->ErrorMessage += MessageDelegate1( this, &ToolManager::OnToolErrorMessage ); tool->GeneralMessage += MessageDelegate1( this, &ToolManager::OnGeneralToolMessage ); m_Tools.push_back( tool ); } } //ActivateTool(0); // first one is default } mitk::ToolManager::~ToolManager() { for (DataVectorType::iterator dataIter = m_WorkingData.begin(); dataIter != m_WorkingData.end(); ++dataIter) (*dataIter)->RemoveObserver(m_WorkingDataObserverTags[(*dataIter)]); if (m_ActiveTool) { m_ActiveTool->Deactivated(); GlobalInteraction::GetInstance()->RemoveListener( m_ActiveTool ); m_ActiveTool = NULL; m_ActiveToolID = -1; // no tool active ActiveToolChanged.Send(); } for ( NodeTagMapType::iterator observerTagMapIter = m_ReferenceDataObserverTags.begin(); observerTagMapIter != m_ReferenceDataObserverTags.end(); ++observerTagMapIter ) { observerTagMapIter->first->RemoveObserver( observerTagMapIter->second ); } } void mitk::ToolManager::OnToolErrorMessage(std::string s) { this->ToolErrorMessage(s); } void mitk::ToolManager::OnGeneralToolMessage(std::string s) { this->GeneralToolMessage(s); } const mitk::ToolManager::ToolVectorTypeConst mitk::ToolManager::GetTools() { ToolVectorTypeConst resultList; for ( ToolVectorType::iterator iter = m_Tools.begin(); iter != m_Tools.end(); ++iter ) { resultList.push_back( iter->GetPointer() ); } return resultList; } mitk::Tool* mitk::ToolManager::GetToolById(int id) { try { return m_Tools.at(id); } catch(std::exception&) { return NULL; } } bool mitk::ToolManager::ActivateTool(int id) { //MITK_INFO << "ToolManager::ActivateTool("<SetEventNotificationPolicy(GlobalInteraction::INFORM_MULTIPLE); + if ( GetToolById( id ) == m_ActiveTool ) return true; // no change needed static int nextTool = -1; nextTool = id; //MITK_INFO << "ToolManager::ActivateTool("<Deactivated(); GlobalInteraction::GetInstance()->RemoveListener( m_ActiveTool ); } m_ActiveTool = GetToolById( nextTool ); m_ActiveToolID = m_ActiveTool ? nextTool : -1; // current ID if tool is valid, otherwise -1 ActiveToolChanged.Send(); if (m_ActiveTool) { if (m_RegisteredClients > 0) { m_ActiveTool->Activated(); GlobalInteraction::GetInstance()->AddListener( m_ActiveTool ); + //If a tool is activated set event notification policy to one + GlobalInteraction::GetInstance()->SetEventNotificationPolicy(GlobalInteraction::INFORM_ONE); } } } inActivateTool = false; return (m_ActiveTool != NULL); } void mitk::ToolManager::SetReferenceData(DataVectorType data) { if (data != m_ReferenceData) { // remove observers from old nodes for ( DataVectorType::iterator dataIter = m_ReferenceData.begin(); dataIter != m_ReferenceData.end(); ++dataIter ) { NodeTagMapType::iterator searchIter = m_ReferenceDataObserverTags.find( *dataIter ); if ( searchIter != m_ReferenceDataObserverTags.end() ) { //MITK_INFO << "Stopping observation of " << (void*)(*dataIter) << std::endl; (*dataIter)->RemoveObserver( searchIter->second ); } } m_ReferenceData = data; // TODO tell active tool? // attach new observers m_ReferenceDataObserverTags.clear(); for ( DataVectorType::iterator dataIter = m_ReferenceData.begin(); dataIter != m_ReferenceData.end(); ++dataIter ) { //MITK_INFO << "Observing " << (void*)(*dataIter) << std::endl; itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheReferenceDataDeleted ); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheReferenceDataDeletedConst ); m_ReferenceDataObserverTags.insert( std::pair( (*dataIter), (*dataIter)->AddObserver( itk::DeleteEvent(), command ) ) ); } ReferenceDataChanged.Send(); } } void mitk::ToolManager::OnOneOfTheReferenceDataDeletedConst(const itk::Object* caller, const itk::EventObject& e) { OnOneOfTheReferenceDataDeleted( const_cast(caller), e ); } void mitk::ToolManager::OnOneOfTheReferenceDataDeleted(itk::Object* caller, const itk::EventObject& itkNotUsed(e)) { //MITK_INFO << "Deleted: " << (void*)caller << " Removing from reference data list." << std::endl; DataVectorType v; for (DataVectorType::iterator dataIter = m_ReferenceData.begin(); dataIter != m_ReferenceData.end(); ++dataIter ) { //MITK_INFO << " In list: " << (void*)(*dataIter); if ( (void*)(*dataIter) != (void*)caller ) { v.push_back( *dataIter ); //MITK_INFO << " kept" << std::endl; } else { //MITK_INFO << " removed" << std::endl; m_ReferenceDataObserverTags.erase( *dataIter ); // no tag to remove anymore } } this->SetReferenceData( v ); } void mitk::ToolManager::SetReferenceData(DataNode* data) { //MITK_INFO << "ToolManager::SetReferenceData(" << (void*)data << ")" << std::endl; DataVectorType v; if (data) { v.push_back(data); } SetReferenceData(v); } void mitk::ToolManager::SetWorkingData(DataVectorType data) { if ( data != m_WorkingData ) { // remove observers from old nodes for ( DataVectorType::iterator dataIter = m_WorkingData.begin(); dataIter != m_WorkingData.end(); ++dataIter ) { NodeTagMapType::iterator searchIter = m_WorkingDataObserverTags.find( *dataIter ); if ( searchIter != m_WorkingDataObserverTags.end() ) { //MITK_INFO << "Stopping observation of " << (void*)(*dataIter) << std::endl; (*dataIter)->RemoveObserver( searchIter->second ); } } m_WorkingData = data; // TODO tell active tool? // attach new observers m_WorkingDataObserverTags.clear(); for ( DataVectorType::iterator dataIter = m_WorkingData.begin(); dataIter != m_WorkingData.end(); ++dataIter ) { //MITK_INFO << "Observing " << (void*)(*dataIter) << std::endl; itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheWorkingDataDeleted ); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheWorkingDataDeletedConst ); m_WorkingDataObserverTags.insert( std::pair( (*dataIter), (*dataIter)->AddObserver( itk::DeleteEvent(), command ) ) ); } WorkingDataChanged.Send(); } } void mitk::ToolManager::OnOneOfTheWorkingDataDeletedConst(const itk::Object* caller, const itk::EventObject& e) { OnOneOfTheWorkingDataDeleted( const_cast(caller), e ); } void mitk::ToolManager::OnOneOfTheWorkingDataDeleted(itk::Object* caller, const itk::EventObject& itkNotUsed(e)) { //MITK_INFO << "Deleted: " << (void*)caller << " Removing from reference data list." << std::endl; DataVectorType v; for (DataVectorType::iterator dataIter = m_WorkingData.begin(); dataIter != m_WorkingData.end(); ++dataIter ) { //MITK_INFO << " In list: " << (void*)(*dataIter); if ( (void*)(*dataIter) != (void*)caller ) { v.push_back( *dataIter ); //MITK_INFO << " kept" << std::endl; } else { //MITK_INFO << " removed" << std::endl; m_WorkingDataObserverTags.erase( *dataIter ); // no tag to remove anymore } } this->SetWorkingData( v ); } void mitk::ToolManager::SetWorkingData(DataNode* data) { DataVectorType v; if (data) // don't allow for NULL nodes { v.push_back(data); } SetWorkingData(v); } void mitk::ToolManager::SetRoiData(DataVectorType data) { if (data != m_RoiData) { // remove observers from old nodes for ( DataVectorType::iterator dataIter = m_RoiData.begin(); dataIter != m_RoiData.end(); ++dataIter ) { NodeTagMapType::iterator searchIter = m_RoiDataObserverTags.find( *dataIter ); if ( searchIter != m_RoiDataObserverTags.end() ) { //MITK_INFO << "Stopping observation of " << (void*)(*dataIter) << std::endl; (*dataIter)->RemoveObserver( searchIter->second ); } } m_RoiData = data; // TODO tell active tool? // attach new observers m_RoiDataObserverTags.clear(); for ( DataVectorType::iterator dataIter = m_RoiData.begin(); dataIter != m_RoiData.end(); ++dataIter ) { //MITK_INFO << "Observing " << (void*)(*dataIter) << std::endl; itk::MemberCommand::Pointer command = itk::MemberCommand::New(); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheRoiDataDeleted ); command->SetCallbackFunction( this, &ToolManager::OnOneOfTheRoiDataDeletedConst ); m_RoiDataObserverTags.insert( std::pair( (*dataIter), (*dataIter)->AddObserver( itk::DeleteEvent(), command ) ) ); } RoiDataChanged.Send(); } } void mitk::ToolManager::SetRoiData(DataNode* data) { DataVectorType v; if(data) { v.push_back(data); } this->SetRoiData(v); } void mitk::ToolManager::OnOneOfTheRoiDataDeletedConst(const itk::Object* caller, const itk::EventObject& e) { OnOneOfTheRoiDataDeleted( const_cast(caller), e ); } void mitk::ToolManager::OnOneOfTheRoiDataDeleted(itk::Object* caller, const itk::EventObject& itkNotUsed(e)) { //MITK_INFO << "Deleted: " << (void*)caller << " Removing from roi data list." << std::endl; DataVectorType v; for (DataVectorType::iterator dataIter = m_RoiData.begin(); dataIter != m_RoiData.end(); ++dataIter ) { //MITK_INFO << " In list: " << (void*)(*dataIter); if ( (void*)(*dataIter) != (void*)caller ) { v.push_back( *dataIter ); //MITK_INFO << " kept" << std::endl; } else { //MITK_INFO << " removed" << std::endl; m_RoiDataObserverTags.erase( *dataIter ); // no tag to remove anymore } } this->SetRoiData( v ); } mitk::ToolManager::DataVectorType mitk::ToolManager::GetReferenceData() { return m_ReferenceData; } mitk::DataNode* mitk::ToolManager::GetReferenceData(int idx) { try { return m_ReferenceData.at(idx); } catch(std::exception&) { return NULL; } } mitk::ToolManager::DataVectorType mitk::ToolManager::GetWorkingData() { return m_WorkingData; } mitk::ToolManager::DataVectorType mitk::ToolManager::GetRoiData() { return m_RoiData; } mitk::DataNode* mitk::ToolManager::GetRoiData(int idx) { try { return m_RoiData.at(idx); } catch(std::exception&) { return NULL; } } mitk::DataStorage* mitk::ToolManager::GetDataStorage() { if ( m_DataStorage.IsNotNull() ) { return m_DataStorage; } else { return NULL; } } void mitk::ToolManager::SetDataStorage(DataStorage& storage) { m_DataStorage = &storage; } mitk::DataNode* mitk::ToolManager::GetWorkingData(int idx) { try { return m_WorkingData.at(idx); } catch(std::exception&) { return NULL; } } int mitk::ToolManager::GetActiveToolID() { return m_ActiveToolID; } mitk::Tool* mitk::ToolManager::GetActiveTool() { return m_ActiveTool; } void mitk::ToolManager::RegisterClient() { if ( m_RegisteredClients < 1 ) { if ( m_ActiveTool ) { m_ActiveTool->Activated(); GlobalInteraction::GetInstance()->AddListener( m_ActiveTool ); } } ++m_RegisteredClients; } void mitk::ToolManager::UnregisterClient() { if ( m_RegisteredClients < 1) return; --m_RegisteredClients; if ( m_RegisteredClients < 1 ) { if ( m_ActiveTool ) { m_ActiveTool->Deactivated(); GlobalInteraction::GetInstance()->RemoveListener( m_ActiveTool ); } } } int mitk::ToolManager::GetToolID( const Tool* tool ) { int id(0); for ( ToolVectorType::iterator iter = m_Tools.begin(); iter != m_Tools.end(); ++iter, ++id ) { if ( tool == iter->GetPointer() ) { return id; } } return -1; }