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