Medical Imaging Interaction Toolkit  2018.4.99-1640525a
Medical Imaging Interaction Toolkit
mitkEventConfig.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 "mitkEventConfig.h"
14 
15 #include "mitkEventFactory.h"
16 #include "mitkInteractionEvent.h"
19 #include "mitkInternalEvent.h"
20 
21 // VTK
22 #include <vtkXMLDataElement.h>
23 #include <vtkXMLParser.h>
24 
25 // us
26 #include "usGetModuleContext.h"
27 #include "usModule.h"
28 #include "usModuleResource.h"
29 #include "usModuleResourceStream.h"
30 
31 namespace mitk
32 {
33  class EventConfigXMLParser : public vtkXMLParser
34  {
35  public:
36  EventConfigXMLParser(EventConfigPrivate *d);
37 
38  protected:
42  void StartElement(const char *elementName, const char **atts) override;
43 
47  void EndElement(const char *elementName) override;
48 
49  std::string ReadXMLStringAttribute(const std::string &name, const char **atts);
50  bool ReadXMLBooleanAttribute(const std::string &name, const char **atts);
51 
52  private:
53  EventConfigPrivate *const d;
54  };
55 
56  struct EventConfigPrivate : public us::SharedData
57  {
58  EventConfigPrivate();
59  EventConfigPrivate(const EventConfigPrivate &other);
60 
61  struct EventMapping
62  {
63  std::string variantName;
64  InteractionEvent::ConstPointer interactionEvent;
65  };
66 
67  typedef std::list<EventMapping> EventListType;
68 
73  void InsertMapping(const EventMapping &mapping);
74 
75  void CopyMapping(const EventListType);
76 
80  PropertyList::Pointer m_PropertyList;
81 
87  PropertyList::Pointer m_EventPropertyList;
88 
89  EventMapping m_CurrEventMapping;
90 
94  EventListType m_EventList;
95 
96  bool
97  m_Errors; // use member, because of inheritance from vtkXMLParser we can't return a success value for parsing the
98  // file.
99 
100  EventConfigXMLParser m_XmlParser;
101  };
102 }
103 
104 mitk::EventConfigPrivate::EventConfigPrivate()
105  : m_PropertyList(PropertyList::New()), m_EventPropertyList(PropertyList::New()), m_Errors(false), m_XmlParser(this)
106 {
107  // Avoid VTK warning: Trying to delete object with non-zero reference count.
108  m_XmlParser.SetReferenceCount(0);
109 }
110 
111 mitk::EventConfigPrivate::EventConfigPrivate(const EventConfigPrivate &other)
112  : us::SharedData(other),
113  m_PropertyList(other.m_PropertyList->Clone()),
114  m_EventPropertyList(other.m_EventPropertyList->Clone()),
115  m_CurrEventMapping(other.m_CurrEventMapping),
116  m_EventList(other.m_EventList),
117  m_Errors(other.m_Errors),
118  m_XmlParser(this)
119 {
120  // Avoid VTK warning: Trying to delete object with non-zero reference count.
121  m_XmlParser.SetReferenceCount(0);
122 }
123 
124 void mitk::EventConfigPrivate::InsertMapping(const EventMapping &mapping)
125 {
126  for (auto it = m_EventList.begin(); it != m_EventList.end(); ++it)
127  {
128  if (*(it->interactionEvent) == *mapping.interactionEvent)
129  {
130  // MITK_INFO<< "Configuration overwritten:" << (*it).variantName;
131  m_EventList.erase(it);
132  break;
133  }
134  }
135  m_EventList.push_back(mapping);
136 }
137 
138 void mitk::EventConfigPrivate::CopyMapping(const EventListType eventList)
139 {
140  EventListType::const_iterator iter;
141  for (iter = eventList.begin(); iter != eventList.end(); ++iter)
142  {
143  InsertMapping(*(iter));
144  }
145 }
146 
147 mitk::EventConfigXMLParser::EventConfigXMLParser(EventConfigPrivate *d) : d(d)
148 {
149 }
150 
151 void mitk::EventConfigXMLParser::StartElement(const char *elementName, const char **atts)
152 {
153  std::string name(elementName);
154 
156  {
157  //
158  }
159  else if (name == InteractionEventConst::xmlTagParam())
160  {
161  const std::string name = ReadXMLStringAttribute(InteractionEventConst::xmlParameterName(), atts);
162  const std::string value = ReadXMLStringAttribute(InteractionEventConst::xmlParameterValue(), atts);
163  d->m_PropertyList->SetStringProperty(name.c_str(), value.c_str());
164  }
166  {
167  const std::string eventClass = ReadXMLStringAttribute(InteractionEventConst::xmlParameterEventClass(), atts);
168  const std::string eventVariant = ReadXMLStringAttribute(InteractionEventConst::xmlParameterName(), atts);
169  // New list in which all parameters are stored that are given within the <input/> tag
170  d->m_EventPropertyList = PropertyList::New();
171  d->m_EventPropertyList->SetStringProperty(InteractionEventConst::xmlParameterEventClass().c_str(),
172  eventClass.c_str());
173  d->m_EventPropertyList->SetStringProperty(InteractionEventConst::xmlParameterEventVariant().c_str(),
174  eventVariant.c_str());
175  d->m_CurrEventMapping.variantName = eventVariant;
176  }
177  else if (name == InteractionEventConst::xmlTagAttribute())
178  {
179  // Attributes that describe an Input Event, such as which MouseButton triggered the event,or which modifier keys are
180  // pressed
181  const std::string name = ReadXMLStringAttribute(InteractionEventConst::xmlParameterName(), atts);
182  const std::string value = ReadXMLStringAttribute(InteractionEventConst::xmlParameterValue(), atts);
183  d->m_EventPropertyList->SetStringProperty(name.c_str(), value.c_str());
184  }
185 }
186 
187 void mitk::EventConfigXMLParser::EndElement(const char *elementName)
188 {
189  const std::string name(elementName);
190  // At end of input section, all necessary infos are collected to created an interaction event.
192  {
193  InteractionEvent::Pointer event = EventFactory::CreateEvent(d->m_EventPropertyList);
194  if (event.IsNotNull())
195  {
196  d->m_CurrEventMapping.interactionEvent = event;
197  d->InsertMapping(d->m_CurrEventMapping);
198  }
199  else
200  {
201  MITK_WARN << "EventConfig: Unknown Event-Type in config. Entry skipped: " << name;
202  }
203  }
204 }
205 
206 std::string mitk::EventConfigXMLParser::ReadXMLStringAttribute(const std::string &name, const char **atts)
207 {
208  if (atts)
209  {
210  const char **attsIter = atts;
211 
212  while (*attsIter)
213  {
214  if (name == *attsIter)
215  {
216  attsIter++;
217  return *attsIter;
218  }
219  attsIter += 2;
220  }
221  }
222  return std::string();
223 }
224 
225 bool mitk::EventConfigXMLParser::ReadXMLBooleanAttribute(const std::string &name, const char **atts)
226 {
227  std::string s = ReadXMLStringAttribute(name, atts);
228  std::transform(s.begin(), s.end(), s.begin(), ::toupper);
229 
230  return s == "TRUE";
231 }
232 
233 mitk::EventConfig::EventConfig() : d(new EventConfigPrivate)
234 {
235 }
236 
237 mitk::EventConfig::EventConfig(const EventConfig &other) : d(other.d)
238 {
239 }
240 
241 mitk::EventConfig::EventConfig(const std::string &filename, const us::Module *module) : d(new EventConfigPrivate)
242 {
243  if (module == nullptr)
244  {
245  module = us::GetModuleContext()->GetModule();
246  }
247  us::ModuleResource resource = module->GetResource("Interactions/" + filename);
248  if (!resource.IsValid())
249  {
250  MITK_ERROR << "Resource not valid. State machine pattern in module " << module->GetName()
251  << " not found: /Interactions/" << filename;
252  return;
253  }
254 
255  EventConfig newConfig;
256  us::ModuleResourceStream stream(resource);
257  newConfig.d->m_XmlParser.SetStream(&stream);
258  bool success = newConfig.d->m_XmlParser.Parse() && !newConfig.d->m_Errors;
259  if (success)
260  {
261  *this = newConfig;
262  }
263 }
264 
265 mitk::EventConfig::EventConfig(std::istream &inputStream) : d(new EventConfigPrivate)
266 {
267  EventConfig newConfig;
268  newConfig.d->m_XmlParser.SetStream(&inputStream);
269  bool success = newConfig.d->m_XmlParser.Parse() && !newConfig.d->m_Errors;
270  if (success)
271  {
272  *this = newConfig;
273  }
274 }
275 
276 mitk::EventConfig::EventConfig(const std::vector<PropertyList::Pointer> &configDescription) : d(new EventConfigPrivate)
277 {
278  auto it_end = configDescription.end();
279  for (auto it = configDescription.begin(); it != it_end; ++it)
280  {
281  std::string typeVariant;
282  (*it)->GetStringProperty(InteractionEventConst::xmlTagEventVariant().c_str(), typeVariant);
283  if (typeVariant != "")
284  {
286  if (event.IsNotNull())
287  {
288  d->m_CurrEventMapping.interactionEvent = event;
289  std::string eventVariant;
290  (*it)->GetStringProperty(InteractionEventConst::xmlTagEventVariant().c_str(), eventVariant);
291  d->m_CurrEventMapping.variantName = eventVariant;
292  d->InsertMapping(d->m_CurrEventMapping);
293  }
294  else
295  {
296  MITK_WARN << "EventConfig: Unknown Event-Type in config. When constructing from PropertyList.";
297  }
298  }
299  else
300  {
301  (*it)->GetStringProperty(InteractionEventConst::xmlTagParam().c_str(), typeVariant);
302  if (typeVariant != "")
303  {
304  std::string name, value;
305  (*it)->GetStringProperty(InteractionEventConst::xmlParameterName().c_str(), name);
306  (*it)->GetStringProperty(InteractionEventConst::xmlParameterValue().c_str(), value);
307  d->m_PropertyList->SetStringProperty(name.c_str(), value.c_str());
308  }
309  }
310  }
311 }
312 
314 {
315  d = other.d;
316  return *this;
317 }
318 
320 {
321 }
322 
324 {
325  return !(d->m_EventList.empty() && d->m_PropertyList->IsEmpty());
326 }
327 
328 bool mitk::EventConfig::AddConfig(const std::string &fileName, const us::Module *module)
329 {
330  if (module == nullptr)
331  {
332  module = us::GetModuleContext()->GetModule();
333  }
334  us::ModuleResource resource = module->GetResource("Interactions/" + fileName);
335  if (!resource.IsValid())
336  {
337  MITK_ERROR << "Resource not valid. State machine pattern in module " << module->GetName()
338  << " not found: /Interactions/" << fileName;
339  return false;
340  }
341 
342  EventConfig newConfig(*this);
343  us::ModuleResourceStream stream(resource);
344  newConfig.d->m_XmlParser.SetStream(&stream);
345  bool success = newConfig.d->m_XmlParser.Parse() && !newConfig.d->m_Errors;
346  if (success)
347  {
348  *this = newConfig;
349  }
350  return success;
351 }
352 
354 {
355  if (!config.IsValid())
356  return false;
357 
358  d->m_PropertyList->ConcatenatePropertyList(config.d->m_PropertyList->Clone(), true);
359  d->m_EventPropertyList = config.d->m_EventPropertyList->Clone();
360  d->m_CurrEventMapping = config.d->m_CurrEventMapping;
361  d->CopyMapping(config.d->m_EventList);
362 
363  return true;
364 }
365 
367 {
368  return d->m_PropertyList;
369 }
370 
371 std::string mitk::EventConfig::GetMappedEvent(const EventType &interactionEvent) const
372 {
373  // internal events are excluded from mapping
374  if (std::strcmp(interactionEvent->GetNameOfClass(), "InternalEvent") == 0)
375  {
376  auto *internalEvent = dynamic_cast<InternalEvent *>(interactionEvent.GetPointer());
377  return internalEvent->GetSignalName();
378  }
379 
380  for (auto it = d->m_EventList.begin(); it != d->m_EventList.end(); ++it)
381  {
382  if (*(it->interactionEvent) == *interactionEvent)
383  {
384  return (*it).variantName;
385  }
386  }
387  // if this part is reached, no mapping has been found,
388  // so here we handle key events and map a key event to the string "Std" + letter/code
389  // so "A" will be returned as "StdA"
390  if (std::strcmp(interactionEvent->GetNameOfClass(), "InteractionKeyEvent") == 0)
391  {
392  auto *keyEvent = dynamic_cast<InteractionKeyEvent *>(interactionEvent.GetPointer());
393  return ("Std" + keyEvent->GetKey());
394  }
395  return "";
396 }
397 
399 {
400  d->m_PropertyList->Clear();
401  d->m_EventPropertyList->Clear();
402  d->m_CurrEventMapping.variantName.clear();
403  d->m_CurrEventMapping.interactionEvent = nullptr;
404  d->m_EventList.clear();
405  d->m_Errors = false;
406 }
static const std::string xmlParameterName()
itk::SmartPointer< Self > Pointer
void ClearConfig()
Reset this EventConfig object, rendering it invalid.
static Pointer New()
Pointer Clone() const
itk::SmartPointer< const Self > ConstPointer
static const std::string xmlParameterValue()
EventConfig()
Constructs an invalid EventConfig object.
#define MITK_ERROR
Definition: mitkLogMacros.h:20
static const std::string xmlTagConfigRoot()
std::string GetMappedEvent(const EventType &interactionEvent) const
static const std::string xmlTagParam()
DataCollection - Class to facilitate loading/accessing structured data.
Class to create events from within the application to signal about internal events.
EventConfig & operator=(const EventConfig &other)
static const std::string xmlParameterEventClass()
static InteractionEvent::Pointer CreateEvent(PropertyList::Pointer eventDescription)
bool AddConfig(const std::string &filename, const us::Module *module=nullptr)
This method extends this configuration.
static const std::string xmlParameterEventVariant()
std::string GetSignalName() const
#define MITK_WARN
Definition: mitkLogMacros.h:19
bool IsValid() const
Checks wether this EventConfig object is valid.
Module * GetModule() const
ModuleResource GetResource(const std::string &path) const
Definition: usModule.cpp:267
static const std::string xmlTagEventVariant()
Handles key events. Takes a std::string for pressed key or special key description, mitk::ModifierKeys for modifiers
Configuration Object for Statemachines.
itk::SmartPointer< Self > Pointer
std::string GetName() const
Definition: usModule.cpp:221
static ModuleContext * GetModuleContext()
Returns the module context of the calling module.
PropertyList::Pointer GetAttributes() const
static const std::string xmlTagAttribute()