Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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.