Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkDispatcher.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 "mitkDispatcher.h"
18 #include "mitkInteractionEvent.h"
20 #include "mitkInternalEvent.h"
21 #include "usGetModuleContext.h"
22 
23 namespace
24 {
25  struct cmp
26  {
27  bool operator()(mitk::DataInteractor *d1, mitk::DataInteractor *d2) { return (d1->GetLayer() > d2->GetLayer()); }
28  };
29 }
30 
31 mitk::Dispatcher::Dispatcher(const std::string &rendererName) : m_ProcessingMode(REGULAR)
32 {
33  // LDAP filter string to find all listeners specific for the renderer
34  // corresponding to this dispatcher
35  std::string specificRenderer = "(rendererName=" + rendererName + ")";
36 
37  // LDAP filter string to find all listeners that are not specific
38  // to any renderer
39  std::string anyRenderer = "(!(rendererName=*))";
40 
41  // LDAP filter string to find only instances of InteractionEventObserver
42  std::string classInteractionEventObserver =
43  "(" + us::ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid<InteractionEventObserver>() + ")";
44 
45  // Configure the LDAP filter to find all instances of InteractionEventObserver
46  // that are specific to this dispatcher or unspecific to any dispatchers (real global listener)
47  us::LDAPFilter filter("(&(|" + specificRenderer + anyRenderer + ")" + classInteractionEventObserver + ")");
48 
49  // Give the filter to the ObserverTracker
50  m_EventObserverTracker = new us::ServiceTracker<InteractionEventObserver>(us::GetModuleContext(), filter);
51  m_EventObserverTracker->Open();
52 }
53 
55 {
56  RemoveDataInteractor(dataNode);
57  RemoveOrphanedInteractors();
58 
59  auto dataInteractor = dataNode->GetDataInteractor().GetPointer();
60 
61  if (dataInteractor != nullptr)
62  m_Interactors.push_back(dataInteractor);
63 }
64 
65 /*
66  * Note: One DataInteractor can only have one DataNode and vice versa,
67  * BUT the m_Interactors list may contain another DataInteractor that is still connected to this DataNode,
68  * in this case we have to remove >1 DataInteractor. (Some special case of switching DataNodes between DataInteractors
69  * and registering a
70  * DataNode to a DataStorage after assigning it to an DataInteractor)
71  */
72 
74 {
75  for (ListInteractorType::iterator it = m_Interactors.begin(); it != m_Interactors.end();)
76  {
77  if ((*it).IsNull() || (*it)->GetDataNode() == nullptr || (*it)->GetDataNode() == dataNode)
78  {
79  it = m_Interactors.erase(it);
80  }
81  else
82  {
83  ++it;
84  }
85  }
86 }
87 
89 {
90  return m_Interactors.size();
91 }
92 
94 {
95  m_EventObserverTracker->Close();
96  delete m_EventObserverTracker;
97 
98  m_Interactors.clear();
99 }
100 
102 {
103  InteractionEvent::Pointer p = event;
104  bool eventIsHandled = false;
105  /* Filter out and handle Internal Events separately */
106  InternalEvent *internalEvent = dynamic_cast<InternalEvent *>(event);
107  if (internalEvent != nullptr)
108  {
109  eventIsHandled = HandleInternalEvent(internalEvent);
110  // InternalEvents that are handled are not sent to the listeners
111  if (eventIsHandled)
112  {
113  return true;
114  }
115  }
116  switch (m_ProcessingMode)
117  {
118  case CONNECTEDMOUSEACTION:
119  // finished connected mouse action
120  if (std::strcmp(p->GetNameOfClass(), "MouseReleaseEvent") == 0)
121  {
122  m_ProcessingMode = REGULAR;
123 
124  if (m_SelectedInteractor.IsNotNull())
125  eventIsHandled = m_SelectedInteractor->HandleEvent(event, m_SelectedInteractor->GetDataNode());
126 
127  m_SelectedInteractor = nullptr;
128  }
129  // give event to selected interactor
130  if (eventIsHandled == false && m_SelectedInteractor.IsNotNull())
131  eventIsHandled = m_SelectedInteractor->HandleEvent(event, m_SelectedInteractor->GetDataNode());
132 
133  break;
134 
135  case GRABINPUT:
136  if (m_SelectedInteractor.IsNotNull())
137  {
138  eventIsHandled = m_SelectedInteractor->HandleEvent(event, m_SelectedInteractor->GetDataNode());
139  SetEventProcessingMode(m_SelectedInteractor);
140  }
141 
142  break;
143 
144  case PREFERINPUT:
145  if (m_SelectedInteractor.IsNotNull() &&
146  m_SelectedInteractor->HandleEvent(event, m_SelectedInteractor->GetDataNode()) == true)
147  {
148  SetEventProcessingMode(m_SelectedInteractor);
149  eventIsHandled = true;
150  }
151 
152  break;
153 
154  case REGULAR:
155  break;
156  }
157 
158  // Standard behavior. Is executed in STANDARD mode and PREFERINPUT mode, if preferred interactor rejects event.
159  if (m_ProcessingMode == REGULAR || (m_ProcessingMode == PREFERINPUT && eventIsHandled == false))
160  {
161  if (std::strcmp(p->GetNameOfClass(), "MousePressEvent") == 0)
162  event->GetSender()->GetRenderingManager()->SetRenderWindowFocus(event->GetSender()->GetRenderWindow());
163  m_Interactors.sort(cmp()); // sorts interactors by layer (descending);
164 
165  // copy the list to prevent iterator invalidation as executing actions
166  // in HandleEvent() can cause the m_Interactors list to be updated
167  const ListInteractorType tmpInteractorList(m_Interactors);
168  ListInteractorType::const_iterator it;
169  for (it = tmpInteractorList.cbegin(); it != tmpInteractorList.cend(); ++it)
170  {
171  if ((*it).IsNotNull() && (*it)->HandleEvent(event, (*it)->GetDataNode()))
172  {
173  // Interactor can be deleted during HandleEvent(), so check it again
174  if ((*it).IsNotNull())
175  {
176  // if an event is handled several properties are checked, in order to determine the processing mode of the
177  // dispatcher
178  SetEventProcessingMode(*it);
179  }
180  if (std::strcmp(p->GetNameOfClass(), "MousePressEvent") == 0 && m_ProcessingMode == REGULAR)
181  {
182  m_SelectedInteractor = *it;
183  m_ProcessingMode = CONNECTEDMOUSEACTION;
184  }
185  eventIsHandled = true;
186  break;
187  }
188  }
189  }
190 
191  /* Notify InteractionEventObserver */
192  const std::vector<us::ServiceReference<InteractionEventObserver>> listEventObserver =
193  m_EventObserverTracker->GetServiceReferences();
194  for (std::vector<us::ServiceReference<InteractionEventObserver>>::const_iterator it = listEventObserver.cbegin();
195  it != listEventObserver.cend();
196  ++it)
197  {
198  InteractionEventObserver *interactionEventObserver = m_EventObserverTracker->GetService(*it);
199  if (interactionEventObserver != nullptr)
200  {
201  if (interactionEventObserver->IsEnabled())
202  {
203  interactionEventObserver->Notify(event, eventIsHandled);
204  }
205  }
206  }
207 
208  // Process event queue
209  if (!m_QueuedEvents.empty())
210  {
211  InteractionEvent::Pointer e = m_QueuedEvents.front();
212  m_QueuedEvents.pop_front();
213  ProcessEvent(e);
214  }
215  return eventIsHandled;
216 }
217 
218 /*
219  * Checks if DataNodes associated with DataInteractors point back to them.
220  * If not remove the DataInteractors. (This can happen when s.o. tries to set DataNodes to multiple DataInteractors)
221  */
222 void mitk::Dispatcher::RemoveOrphanedInteractors()
223 {
224  for (ListInteractorType::iterator it = m_Interactors.begin(); it != m_Interactors.end();)
225  {
226  if ((*it).IsNull())
227  {
228  it = m_Interactors.erase(it);
229  }
230  else
231  {
232  DataNode::Pointer node = (*it)->GetDataNode();
233 
234  if (node.IsNull())
235  {
236  it = m_Interactors.erase(it);
237  }
238  else
239  {
240  DataInteractor::Pointer interactor = node->GetDataInteractor();
241 
242  if (interactor != it->GetPointer())
243  {
244  it = m_Interactors.erase(it);
245  }
246  else
247  {
248  ++it;
249  }
250  }
251  }
252  }
253 }
254 
256 {
257  m_QueuedEvents.push_back(event);
258 }
259 
260 void mitk::Dispatcher::SetEventProcessingMode(DataInteractor *dataInteractor)
261 {
262  m_ProcessingMode = dataInteractor->GetMode();
263  if (dataInteractor->GetMode() != REGULAR)
264  {
265  m_SelectedInteractor = dataInteractor;
266  }
267 }
268 
269 bool mitk::Dispatcher::HandleInternalEvent(InternalEvent *internalEvent)
270 {
271  if (internalEvent->GetSignalName() == DataInteractor::IntDeactivateMe &&
272  internalEvent->GetTargetInteractor() != nullptr)
273  {
274  internalEvent->GetTargetInteractor()->GetDataNode()->SetDataInteractor(nullptr);
275  internalEvent->GetTargetInteractor()->SetDataNode(nullptr);
276 
278  return true;
279  }
280  return false;
281 }
Base class to implement InteractionEventObservers.
BaseRenderer * GetSender() const
std::list< mitk::WeakPointer< DataInteractor > > ListInteractorType
virtual void Notify(InteractionEvent *interactionEvent, bool isHandled)=0
Class to create events from within the application to signal about internal events.
virtual DataInteractor::Pointer GetDataInteractor() const
bool ProcessEvent(InteractionEvent *event)
Base class from with interactors that handle DataNodes are to be derived.
itk::SmartPointer< Self > Pointer
Definition: mitkDataNode.h:81
vcl_size_t GetNumberOfInteractors()
static RenderingManager * GetInstance()
Dispatcher(const std::string &rendererName)
itk::SmartPointer< Self > Pointer
static const std::string IntDeactivateMe
ProcessEventMode GetMode() const
US_Core_EXPORT const std::string & OBJECTCLASS()
void AddDataInteractor(const DataNode *dataNode)
void QueueEvent(InteractionEvent *event)
static ModuleContext * GetModuleContext()
Returns the module context of the calling module.
vtkRenderWindow * GetRenderWindow() const
Access the RenderWindow into which this renderer renders.
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)
void RemoveDataInteractor(const DataNode *dataNode)
Class for nodes of the DataTree.
Definition: mitkDataNode.h:66