Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkEventStateMachine.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3  The Medical Imaging Interaction Toolkit (MITK)
4 
5  Copyright (c) German Cancer Research Center,
6  Division of Medical and Biological Informatics.
7  All rights reserved.
8 
9  This software is distributed WITHOUT ANY WARRANTY; without
10  even the implied warranty of MERCHANTABILITY or FITNESS FOR
11  A PARTICULAR PURPOSE.
12 
13  See LICENSE.txt or http://www.mitk.org for details.
14 
15  ===================================================================*/
16 
17 #include "mitkEventStateMachine.h"
18 #include "mitkApplicationCursor.h"
19 #include "mitkInteractionEvent.h"
20 #include "mitkStateMachineAction.h"
23 #include "mitkStateMachineState.h"
25 #include "mitkUndoController.h"
26 
28  : m_IsActive(true),
29  m_UndoController(NULL),
30  m_StateMachineContainer(NULL),
31  m_CurrentState(NULL),
32  m_MouseCursorSet(false)
33 {
34  if (!m_UndoController)
35  {
37 
41  m_UndoEnabled = true;
42  }
43 }
44 
45 bool mitk::EventStateMachine::LoadStateMachine(const std::string &filename, const us::Module *module)
46 {
47  if (m_StateMachineContainer != NULL)
48  {
49  m_StateMachineContainer->Delete();
50  }
51  m_StateMachineContainer = StateMachineContainer::New();
52 
53  if (m_StateMachineContainer->LoadBehavior(filename, module))
54  {
55  m_CurrentState = m_StateMachineContainer->GetStartState();
56 
57  for (ConditionDelegatesMapType::iterator i = m_ConditionDelegatesMap.begin(); i != m_ConditionDelegatesMap.end();
58  ++i)
59  {
60  delete i->second;
61  }
62  m_ConditionDelegatesMap.clear();
63 
64  // clear actions map ,and connect all actions as declared in sub-class
65  for (std::map<std::string, TActionFunctor *>::iterator i = m_ActionFunctionsMap.begin();
66  i != m_ActionFunctionsMap.end();
67  ++i)
68  {
69  delete i->second;
70  }
71  m_ActionFunctionsMap.clear();
72  for (ActionDelegatesMapType::iterator i = m_ActionDelegatesMap.begin(); i != m_ActionDelegatesMap.end(); ++i)
73  {
74  delete i->second;
75  }
76  m_ActionDelegatesMap.clear();
77 
79  return true;
80  }
81  else
82  {
83  MITK_WARN << "Unable to load StateMachine from file: " << filename;
84  return false;
85  }
86 }
87 
89 {
90  if (m_StateMachineContainer != NULL)
91  {
92  m_StateMachineContainer->Delete();
93  }
94 }
95 
96 void mitk::EventStateMachine::AddActionFunction(const std::string &action, mitk::TActionFunctor *functor)
97 {
98  if (!functor)
99  return;
100  // make sure double calls for same action won't cause memory leaks
101  delete m_ActionFunctionsMap[action];
102  ActionDelegatesMapType::iterator i = m_ActionDelegatesMap.find(action);
103  if (i != m_ActionDelegatesMap.end())
104  {
105  delete i->second;
106  m_ActionDelegatesMap.erase(i);
107  }
108  m_ActionFunctionsMap[action] = functor;
109 }
110 
111 void mitk::EventStateMachine::AddActionFunction(const std::string &action, const ActionFunctionDelegate &delegate)
112 {
113  std::map<std::string, TActionFunctor *>::iterator i = m_ActionFunctionsMap.find(action);
114  if (i != m_ActionFunctionsMap.end())
115  {
116  delete i->second;
117  m_ActionFunctionsMap.erase(i);
118  }
119 
120  delete m_ActionDelegatesMap[action];
121  m_ActionDelegatesMap[action] = delegate.Clone();
122 }
123 
124 void mitk::EventStateMachine::AddConditionFunction(const std::string &condition,
125  const ConditionFunctionDelegate &delegate)
126 {
127  m_ConditionDelegatesMap[condition] = delegate.Clone();
128 }
129 
131 {
132  if (!m_IsActive)
133  return false;
134 
135  if (!FilterEvents(event, dataNode))
136  {
137  return false;
138  }
139 
140  // Get the transition that can be executed
141  mitk::StateMachineTransition::Pointer transition = GetExecutableTransition(event);
142 
143  // check if the current state holds a transition that works with the given event.
144  if (transition.IsNotNull())
145  {
146  // all conditions are fulfilled so we can continue with the actions
147  m_CurrentState = transition->GetNextState();
148 
149  // iterate over all actions in this transition and execute them
150  const ActionVectorType actions = transition->GetActions();
151  for (ActionVectorType::const_iterator it = actions.cbegin(); it != actions.cend(); ++it)
152  {
153  try
154  {
155  ExecuteAction(*it, event);
156  }
157  catch (const std::exception &e)
158  {
159  MITK_ERROR << "Unhandled excaption caught in ExecuteAction(): " << e.what();
160  return false;
161  }
162  catch (...)
163  {
164  MITK_ERROR << "Unhandled excaption caught in ExecuteAction()";
165  return false;
166  }
167  }
168 
169  return true;
170  }
171  return false;
172 }
173 
175 {
176  MITK_WARN << "ConnectActionsAndFunctions in DataInteractor not implemented.\n DataInteractor will not be able to "
177  "process any events.";
178 }
179 
181 {
182  bool retVal = false;
183  ConditionDelegatesMapType::const_iterator delegateIter = m_ConditionDelegatesMap.find(condition.GetConditionName());
184  if (delegateIter != m_ConditionDelegatesMap.cend())
185  {
186  retVal = delegateIter->second->Execute(event);
187  }
188  else
189  {
190  MITK_WARN << "No implementation of condition '" << condition.GetConditionName() << "' has been found.";
191  }
192 
193  return retVal;
194 }
195 
197 {
198  if (action == NULL)
199  {
200  return;
201  }
202 
203  // Maps Action-Name to Functor and executes the Functor.
204  ActionDelegatesMapType::const_iterator delegateIter = m_ActionDelegatesMap.find(action->GetActionName());
205  if (delegateIter != m_ActionDelegatesMap.cend())
206  {
207  delegateIter->second->Execute(action, event);
208  }
209  else
210  {
211  // try the legacy system
212  std::map<std::string, TActionFunctor *>::const_iterator functionIter =
213  m_ActionFunctionsMap.find(action->GetActionName());
214  if (functionIter != m_ActionFunctionsMap.cend())
215  {
216  functionIter->second->DoAction(action, event);
217  }
218  else
219  {
220  MITK_WARN << "No implementation of action '" << action->GetActionName() << "' has been found.";
221  }
222  }
223 }
224 
226 {
227  return m_CurrentState.GetPointer();
228 }
229 
231 {
232  if (dataNode == NULL)
233  {
234  MITK_WARN << "EventStateMachine: Empty DataNode received along with this Event " << interactionEvent;
235  return false;
236  }
237  bool visible = false;
238  if (dataNode->GetBoolProperty("visible", visible, interactionEvent->GetSender()) == false)
239  { // property doesn't exist
240  return false;
241  }
242  return visible;
243 }
244 
246 {
247  // Map that will contain all conditions that are possibly used by the
248  // transitions
249  std::map<std::string, bool> conditionsMap;
250 
251  // Get a list of all transitions that match the given event
252  const mitk::StateMachineState::TransitionVector transitionList =
253  m_CurrentState->GetTransitionList(event->GetNameOfClass(), MapToEventVariant(event));
254 
255  // if there are not transitions, we can return NULL here.
256  if (transitionList.empty())
257  {
258  return NULL;
259  }
260 
261  StateMachineState::TransitionVector::const_iterator transitionIter;
262  ConditionVectorType::const_iterator conditionIter;
263  for (transitionIter = transitionList.cbegin(); transitionIter != transitionList.cend(); ++transitionIter)
264  {
265  bool allConditionsFulfilled(true);
266 
267  // Get all conditions for the current transition
268  const ConditionVectorType conditions = (*transitionIter)->GetConditions();
269  for (conditionIter = conditions.cbegin(); conditionIter != conditions.cend(); ++conditionIter)
270  {
271  bool currentConditionFulfilled(false);
272 
273  // sequentially check all conditions that we have evaluated above
274  const std::string conditionName = (*conditionIter).GetConditionName();
275 
276  // Check if the condition has already been evaluated
277  if (conditionsMap.find(conditionName) == conditionsMap.cend())
278  {
279  // if the condition has not been evaluated yet, do it now and store
280  // the result in the map
281  try
282  {
283  currentConditionFulfilled = CheckCondition((*conditionIter), event);
284  conditionsMap.insert(std::pair<std::string, bool>(conditionName, currentConditionFulfilled));
285  }
286  catch (const std::exception &e)
287  {
288  MITK_ERROR << "Unhandled excaption caught in CheckCondition(): " << e.what();
289  currentConditionFulfilled = false;
290  break;
291  }
292  catch (...)
293  {
294  MITK_ERROR << "Unhandled excaption caught in CheckCondition()";
295  currentConditionFulfilled = false;
296  break;
297  }
298  }
299  else
300  {
301  // if the condition has been evaluated before, use that result
302  currentConditionFulfilled = conditionsMap[conditionName];
303  }
304 
305  // set 'allConditionsFulfilled' under consideration of a possible
306  // inversion of the condition
307  if (currentConditionFulfilled == (*conditionIter).IsInverted())
308  {
309  allConditionsFulfilled = false;
310  break;
311  }
312  }
313 
314  // If all conditions are fulfilled, we execute this transition
315  if (allConditionsFulfilled)
316  {
317  return (*transitionIter);
318  }
319  }
320 
321  // We have found no transition that can be executed, return NULL
322  return NULL;
323 }
324 
326 {
327  m_CurrentState = m_StateMachineContainer->GetStartState();
328 }
329 
330 void mitk::EventStateMachine::SetMouseCursor(const char *xpm[], int hotspotX, int hotspotY)
331 {
332  // Remove previously set mouse cursor
333  if (m_MouseCursorSet)
334  {
336  }
337 
338  ApplicationCursor::GetInstance()->PushCursor(xpm, hotspotX, hotspotY);
339  m_MouseCursorSet = true;
340 }
341 
343 {
344  if (m_MouseCursorSet)
345  {
347  m_MouseCursorSet = false;
348  }
349 }
BaseRenderer * GetSender() const
virtual MessageAbstractDelegate1 * Clone() const =0
StateMachineTransition * GetExecutableTransition(InteractionEvent *event)
Returns the executable transition for the given event.
std::vector< mitk::StateMachineAction::Pointer > ActionVectorType
Base class of ActionFunctors, to provide an easy to connect actions with functions.
#define MITK_ERROR
Definition: mitkLogMacros.h:24
bool HandleEvent(InteractionEvent *event, DataNode *dataNode)
virtual bool FilterEvents(InteractionEvent *interactionEvent, DataNode *dataNode)
bool GetBoolProperty(const char *propertyKey, bool &boolValue, const mitk::BaseRenderer *renderer=nullptr) const
Convenience access method for bool properties (instances of BoolProperty)
bool LoadStateMachine(const std::string &filename, const us::Module *module=nullptr)
Loads XML resource.
void PopCursor()
Restore the previous cursor.
void AddActionFunction(const std::string &action, TActionFunctor *functor)
StateMachineState * GetCurrentState() const
std::string GetConditionName() const
Returns the String-Id of this action.
#define MITK_WARN
Definition: mitkLogMacros.h:23
void AddConditionFunction(const std::string &condition, const ConditionFunctionDelegate &delegate)
static ApplicationCursor * GetInstance()
This class is a singleton.
static StateMachineContainer * New()
virtual void ExecuteAction(StateMachineAction *action, InteractionEvent *interactionEvent)
Represents an action, that is executed after a certain event (in statemachine-mechanism) TODO: implem...
std::string GetActionName() const
Returns the String-Id of this action.
static const std::string filename
virtual void ConnectActionsAndFunctions() override
void ResetMouseCursor()
Resets the mouse cursor (if modified by the SlicesCoordinator) to its original state.
Connects two states, and holds references to corresponding actions and conditions.
void ResetToStartState()
ResetToStartState Reset state machine to it initial starting state.
void PushCursor(const char *XPM[], int hotspotX=-1, int hotspotY=-1)
Change the current application cursor.
void SetMouseCursor(const char *xpm[], int hotspotX, int hotspotY)
Sets the specified mouse cursor.
virtual MessageAbstractDelegate2 * Clone() const =0
virtual bool CheckCondition(const StateMachineCondition &condition, const InteractionEvent *interactionEvent)
Represents a condition, that has to be fulfilled in order to execute a state machine transition after...
std::vector< StateMachineTransition::Pointer > TransitionVector
Class for nodes of the DataTree.
Definition: mitkDataNode.h:66
std::vector< StateMachineCondition > ConditionVectorType