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