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
berryCommandManager.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 BlueBerry Platform
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 "berryCommandManager.h"
18 
19 #include "berryIParameter.h"
20 #include "berryIHandler.h"
21 #include "berryParameterType.h"
23 #include "berryParameterization.h"
24 #include "berryCommand.h"
25 #include "berryCommandCategory.h"
26 #include "berryState.h"
27 
28 #include "berryExecutionEvent.h"
29 #include "berryCommandEvent.h"
33 
34 namespace berry {
35 
36 CommandManager::ExecutionListener::ExecutionListener(CommandManager* commandManager) : commandManager(commandManager)
37 {
38 
39 }
40 
41 void CommandManager::ExecutionListener::NotDefined(const QString& commandId, const NotDefinedException* exception)
42 {
43  commandManager->executionEvents.notDefined(commandId, exception);
44 }
45 
46 void CommandManager::ExecutionListener::NotEnabled(const QString& commandId, const NotEnabledException* exception)
47 {
48  commandManager->executionEvents.notEnabled(commandId, exception);
49 }
50 
51 void CommandManager::ExecutionListener::NotHandled(const QString& commandId, const NotHandledException* exception)
52 {
53  commandManager->executionEvents.notHandled(commandId, exception);
54 }
55 
56 void CommandManager::ExecutionListener::PostExecuteFailure(const QString& commandId,
57  const ExecutionException* exception)
58 {
59  commandManager->executionEvents.postExecuteFailure(commandId, exception);
60 }
61 
62 void CommandManager::ExecutionListener::PostExecuteSuccess(const QString& commandId,
63  const Object::Pointer& returnValue)
64 {
65  commandManager->executionEvents.postExecuteSuccess(commandId, returnValue);
66 }
67 
68 void CommandManager::ExecutionListener::PreExecute(const QString& commandId,
69  const ExecutionEvent::ConstPointer& event)
70 {
71  commandManager->executionEvents.preExecute(commandId, event);
72 }
73 
74 CommandManager::CommandCategoryListener::CommandCategoryListener(CommandManager* commandManager)
75  : commandManager(commandManager)
76 {
77 
78 }
79 
80 void CommandManager::CommandCategoryListener::CategoryChanged(const CommandCategoryEvent::ConstPointer& categoryEvent)
81 {
82  if (categoryEvent->IsDefinedChanged())
83  {
84  const CommandCategory::Pointer category(categoryEvent->GetCategory());
85  const QString categoryId(category->GetId());
86  const bool categoryIdAdded = category->IsDefined();
87  if (categoryIdAdded)
88  {
89  commandManager->definedCategoryIds.insert(categoryId);
90  }
91  else
92  {
93  commandManager->definedCategoryIds.remove(categoryId);
94  }
95  CommandManagerEvent::Pointer event(new CommandManagerEvent(*commandManager, "",
96  false, false, categoryId, categoryIdAdded, true));
97  commandManager->FireCommandManagerChanged(event);
98 
99  }
100 }
101 
102 CommandManager::CommandListener::CommandListener(CommandManager* commandManager)
103  : commandManager(commandManager)
104 {
105 
106 }
107 
108 void CommandManager::CommandListener::CommandChanged(const SmartPointer<const CommandEvent>& commandEvent)
109 {
110  if (commandEvent->IsDefinedChanged())
111  {
112  const Command::Pointer command(commandEvent->GetCommand());
113  const QString commandId = command->GetId();
114  const bool commandIdAdded = command->IsDefined();
115  if (commandIdAdded)
116  {
117  commandManager->definedHandleObjects.insert(command);
118  }
119  else
120  {
121  commandManager->definedHandleObjects.remove(command);
122  }
123  CommandManagerEvent::Pointer event(new CommandManagerEvent(*commandManager,
124  commandId, commandIdAdded, true, "", false, false));
125  commandManager->FireCommandManagerChanged(event);
126 
127  }
128 }
129 
130 CommandManager::ParameterTypeListener::ParameterTypeListener(CommandManager* commandManager)
131  : commandManager(commandManager)
132 {
133 
134 }
135 
136 void CommandManager::ParameterTypeListener::ParameterTypeChanged(
137  const ParameterTypeEvent::ConstPointer& parameterTypeEvent)
138 {
139  if (parameterTypeEvent->IsDefinedChanged())
140  {
141  const ParameterType::Pointer parameterType(parameterTypeEvent
142  ->GetParameterType());
143  const QString parameterTypeId = parameterType->GetId();
144  const bool parameterTypeIdAdded = parameterType->IsDefined();
145  if (parameterTypeIdAdded)
146  {
147  commandManager->definedParameterTypeIds.insert(parameterTypeId);
148  }
149  else
150  {
151  commandManager->definedParameterTypeIds.remove(parameterTypeId);
152  }
153 
154  CommandManagerEvent::Pointer event(new CommandManagerEvent(*commandManager,
155  parameterTypeId, parameterTypeIdAdded, true));
156  commandManager->FireCommandManagerChanged(event);
157  }
158 }
159 
160 
161 const QString CommandManager::AUTOGENERATED_CATEGORY_ID = "org.blueberry.core.commands.categories.autogenerated";
162 const char CommandManager::ESCAPE_CHAR = '%';
163 const char CommandManager::ID_VALUE_CHAR = '=';
164 const char CommandManager::PARAMETER_END_CHAR = ')';
166 const char CommandManager::PARAMETER_START_CHAR = '(';
167 
169  : categoryListener(new CommandCategoryListener(this)),
170  commandListener(new CommandListener(this)),
171  parameterTypeListener(new ParameterTypeListener(this))
172 {
173 
174 }
175 
177 {
178  commandManagerEvents.AddListener(listener);
179 }
180 
182 {
183  if (listener == nullptr)
184  {
185  throw ctkInvalidArgumentException(
186  "Cannot add a null execution listener");
187  }
188 
189  if (executionEvents.IsEmpty())
190  {
191  // Add an execution listener to every command.
192  executionListener.reset(new ExecutionListener(this));
193  for (HandleObjectsByIdMap::Iterator itr = handleObjectsById.begin();
194  itr != handleObjectsById.end(); ++itr)
195  {
196  Command::Pointer command = itr.value().Cast<Command>();
197  if (command)
198  {
199  command->AddExecutionListener(executionListener.data());
200  }
201  }
202  }
203 
204  executionEvents.AddListener(listener);
205 }
206 
208  const QString& description)
209 {
211  category->Define(name, description);
212 }
213 
215  const QString& serializedParameterizedCommand)
216 {
217 
218  const int lparenPosition = this->UnescapedIndexOf(
219  serializedParameterizedCommand, PARAMETER_START_CHAR);
220 
221  QString commandIdEscaped;
222  QString serializedParameters;
223  if (lparenPosition == -1)
224  {
225  commandIdEscaped = serializedParameterizedCommand;
226  }
227  else
228  {
229  commandIdEscaped = serializedParameterizedCommand.left(lparenPosition);
230 
231  if (serializedParameterizedCommand
232  .at(serializedParameterizedCommand.size() - 1) != PARAMETER_END_CHAR)
233  {
234  throw SerializationException(
235  "Parentheses must be balanced in serialized ParameterizedCommand");
236  }
237 
238  serializedParameters = serializedParameterizedCommand.mid(
239  lparenPosition + 1, // skip PARAMETER_START_CHAR
240  serializedParameterizedCommand.size() - lparenPosition - 2); // skip
241  // PARAMETER_END_CHAR
242  }
243 
244  const QString commandId(this->Unescape(commandIdEscaped));
245  Command::Pointer command(this->GetCommand(commandId));
246  const QList<IParameter::Pointer> parameters(command->GetParameters());
247  const QList<Parameterization>parameterizations(this->GetParameterizations(
248  serializedParameters, parameters));
249 
250  ParameterizedCommand::Pointer pCmd(new ParameterizedCommand(command, parameterizations));
251  return pCmd;
252 }
253 
254 QList<SmartPointer<Command> > CommandManager::GetAllCommands() const
255 {
256  QList<Command::Pointer> result;
257  for (HandleObjectsByIdMap::ConstIterator itr = handleObjectsById.begin();
258  itr != handleObjectsById.end(); ++itr)
259  {
260  if (Command::Pointer cmd = itr.value().Cast<Command>())
261  {
262  result.push_back(cmd);
263  }
264  }
265  return result;
266 }
267 
269 {
270  if (categoryId.isEmpty())
271  {
273  }
274 
275  this->CheckId(categoryId);
276 
277  CommandCategory::Pointer category(categoriesById[categoryId]);
278  if (!category)
279  {
280  category = new CommandCategory(categoryId);
281  categoriesById[categoryId] = category;
282  category->AddCategoryListener(categoryListener.data());
283  }
284 
285  return category;
286 }
287 
289 {
290  this->CheckId(commandId);
291 
292  Command::Pointer command(handleObjectsById[commandId].Cast<Command>());
293  if (!command)
294  {
295  command = new Command(commandId);
296  handleObjectsById[commandId] = command;
297  command->AddCommandListener(commandListener.data());
298 
299  if (executionListener)
300  {
301  command->AddExecutionListener(executionListener.data());
302  }
303  }
304 
305  return command;
306 }
307 
308 QList<CommandCategory::Pointer> CommandManager::GetDefinedCategories()
309 {
310  QList<CommandCategory::Pointer> categories;
311  for (QSet<QString>::Iterator itr = definedCategoryIds.begin();
312  itr != definedCategoryIds.end(); ++itr)
313  {
314  categories.push_back(this->GetCategory(*itr));
315  }
316  return categories;
317 }
318 
320 {
321  return definedCategoryIds;
322 }
323 
325 {
326  return this->GetDefinedHandleObjectIds();
327 }
328 
329 QList<SmartPointer<Command> > CommandManager::GetDefinedCommands() const
330 {
331  QList<Command::Pointer> result;
332  for (HandleObjectsSet::ConstIterator itr = definedHandleObjects.begin();
333  itr != definedHandleObjects.end(); ++itr)
334  {
335  if (Command::Pointer cmd = itr->Cast<Command>())
336  result.push_back(cmd);
337  }
338  return result;
339 }
340 
342 {
343  return definedParameterTypeIds;
344 }
345 
346 QList<SmartPointer<ParameterType> > CommandManager::GetDefinedParameterTypes()
347 {
348  QList<ParameterType::Pointer> parameterTypes;
349  for (QSet<QString>::ConstIterator itr = definedParameterTypeIds.begin();
350  itr != definedParameterTypeIds.end(); ++itr)
351  {
352  parameterTypes.push_back(this->GetParameterType(*itr));
353  }
354  return parameterTypes;
355 }
356 
358 {
359  // Check if the command is defined.
360  if (!command->IsDefined())
361  {
362  throw NotDefinedException("The command is not defined. "
363  + command->GetId());
364  }
365 
366  // Check the handler.
367  const IHandler::Pointer handler(command->GetHandler());
368  if (handler)
369  {
370  const IHandler::WeakPtr weakHandler(handler);
371  QHash<WeakPointer<IHandler>, QString>::ConstIterator itr =
372  helpContextIdsByHandler.find(weakHandler);
373  if (itr != helpContextIdsByHandler.end() && !itr.value().isEmpty())
374  {
375  return itr.value();
376  }
377  }
378 
379  // Simply return whatever the command has as a help context identifier.
380  return command->GetHelpContextId();
381 }
382 
384 {
385  this->CheckId(parameterTypeId);
386 
387  ParameterType::Pointer parameterType(parameterTypesById[parameterTypeId]);
388  if (!parameterType)
389  {
390  parameterType = new ParameterType(parameterTypeId);
391  parameterTypesById[parameterTypeId] = parameterType;
392  parameterType->AddListener(parameterTypeListener.data());
393  }
394 
395  return parameterType;
396 }
397 
399 {
400  commandManagerEvents.RemoveListener(listener);
401 }
402 
404 {
405  if (!listener)
406  {
407  throw ctkInvalidArgumentException("Cannot remove a null listener");
408  }
409 
410  if (executionEvents.IsEmpty())
411  {
412  return;
413  }
414 
415  executionEvents.RemoveListener(listener);
416 
417  if (executionEvents.IsEmpty())
418  {
419  // Remove the execution listener from every command.
420  for (HandleObjectsByIdMap::Iterator commandItr = handleObjectsById.begin();
421  commandItr != handleObjectsById.end(); ++commandItr)
422  {
423  Command::Pointer command(commandItr.value().Cast<Command>());
424  command->RemoveExecutionListener(executionListener.data());
425  }
426  executionListener.reset();
427  }
428 }
429 
430 void CommandManager::SetHandlersByCommandId(const QHash<QString, SmartPointer<IHandler> > &handlersByCommandId)
431 {
432  // Make that all the reference commands are created.
433  for (QHash<QString, SmartPointer<IHandler> >::const_iterator commandItr = handlersByCommandId.begin();
434  commandItr != handlersByCommandId.end(); ++commandItr)
435  {
436  this->GetCommand(commandItr.key());
437  }
438 
439  // Now, set-up the handlers on all of the existing commands.
440  for (HandleObjectsByIdMap::Iterator commandItr = handleObjectsById.begin();
441  commandItr != handleObjectsById.end(); ++commandItr)
442  {
443  const Command::Pointer command(commandItr.value().Cast<Command>());
444  const QString commandId(command->GetId());
445  QHash<QString, SmartPointer<IHandler> >::const_iterator handlerItr = handlersByCommandId.find(commandId);
446  if (handlerItr != handlersByCommandId.end())
447  {
448  command->SetHandler(handlerItr.value());
449  }
450  else
451  {
452  command->SetHandler(IHandler::Pointer(nullptr));
453  }
454  }
455 }
456 
458  const QString& helpContextId)
459 {
460  if (!handler)
461  {
462  throw ctkInvalidArgumentException("The handler cannot be null");
463  }
464  IHandler::WeakPtr weakHandler(handler);
465  if (helpContextId.isEmpty())
466  {
467  helpContextIdsByHandler.remove(weakHandler);
468  }
469  else
470  {
471  helpContextIdsByHandler[weakHandler] = helpContextId;
472  }
473 }
474 
475 void CommandManager::FireNotEnabled(const QString& commandId, const NotEnabledException* exception)
476 {
477  executionEvents.notEnabled(commandId, exception);
478 }
479 
480 void CommandManager::FireNotDefined(const QString& commandId, const NotDefinedException* exception)
481 {
482  executionEvents.notDefined(commandId, exception);
483 }
484 
485 void CommandManager::FirePreExecute(const QString& commandId, const SmartPointer<const ExecutionEvent> event)
486 {
487  executionEvents.preExecute(commandId, event);
488 }
489 
490 void CommandManager::FirePostExecuteSuccess(const QString& commandId, Object::Pointer returnValue)
491 {
492  executionEvents.postExecuteSuccess(commandId, returnValue);
493 }
494 
495 void CommandManager::FirePostExecuteFailure(const QString& commandId,
496  const ExecutionException* exception)
497 {
498  executionEvents.postExecuteFailure(commandId, exception);
499 }
500 
501 QString CommandManager::Unescape(const QString& escapedText)
502 {
503 
504  // defer initialization of a StringBuffer until we know we need one
505  QString buffer;
506 
507  int pos = 0;
508  for (QString::const_iterator itr = escapedText.begin();
509  itr != escapedText.end(); ++itr, ++pos)
510  {
511  QString::value_type c = *itr;
512  if (c != ESCAPE_CHAR)
513  {
514  // normal unescaped character
515  if (!buffer.isEmpty())
516  {
517  buffer += c;
518  }
519  }
520  else
521  {
522  if (buffer.isEmpty())
523  {
524  buffer = escapedText.left(pos);
525  }
526 
527  if (++itr != escapedText.end())
528  {
529  c = *itr;
530  if (c == PARAMETER_START_CHAR || c == PARAMETER_END_CHAR ||
532  c == ESCAPE_CHAR)
533  {
534  buffer += c;
535  }
536  else
537  {
538  QString msg("Invalid character '");
539  msg += c;
540  msg += "' in escape sequence";
541  throw SerializationException(msg);
542  }
543  }
544  else
545  {
546  throw SerializationException(
547  "Unexpected termination of escape sequence"); //$NON-NLS-1$
548  }
549  }
550 
551  }
552 
553  if (buffer.isEmpty())
554  {
555  return escapedText;
556  }
557 
558  return buffer;
559 }
560 
561 void CommandManager::FireCommandManagerChanged(const SmartPointer<const CommandManagerEvent> event)
562 {
563  if (!event)
564  {
565  throw ctkInvalidArgumentException("Event cannot be null.");
566  }
567 
568  commandManagerEvents.commandManagerChanged(event);
569 }
570 
571 QList<Parameterization> CommandManager::GetParameterizations(
572  const QString& serializedParams, const QList<SmartPointer<IParameter> >& parameters) const
573 {
574 
575  QString serializedParameters(serializedParams);
576 
577  if (serializedParameters.isEmpty() || parameters.isEmpty())
578  {
579  return QList<Parameterization>();
580  }
581 
582  QList<Parameterization> paramList;
583 
584  int commaPosition; // split off each param by looking for ','
585  do
586  {
587  commaPosition = this->UnescapedIndexOf(serializedParameters, ',');
588 
589  QString idEqualsValue;
590  if (commaPosition == -1)
591  {
592  // no more parameters after this
593  idEqualsValue = serializedParameters;
594  }
595  else
596  {
597  // take the first parameter...
598  idEqualsValue = serializedParameters.left(commaPosition);
599 
600  // ... and put the rest back into serializedParameters
601  serializedParameters = serializedParameters.mid(commaPosition + 1);
602  }
603 
604  int equalsPosition = this->UnescapedIndexOf(idEqualsValue, '=');
605 
606  QString parameterId;
607  QString parameterValue;
608  if (equalsPosition == -1)
609  {
610  // missing values are null
611  parameterId = this->Unescape(idEqualsValue);
612  }
613  else
614  {
615  parameterId = this->Unescape(idEqualsValue.left(equalsPosition));
616  parameterValue = this->Unescape(idEqualsValue.mid(equalsPosition + 1));
617  }
618 
619  for (int i = 0; i < parameters.size(); i++)
620  {
621  const IParameter::Pointer parameter(parameters[i]);
622  if (parameter->GetId() == parameterId)
623  {
624  paramList.push_back(Parameterization(parameter,
625  parameterValue));
626  break;
627  }
628  }
629 
630  } while (commaPosition != -1);
631 
632  return paramList;
633 }
634 
635 int CommandManager::UnescapedIndexOf(const QString& escapedText, const char ch) const
636 {
637 
638  int pos = escapedText.indexOf(ch);
639 
640  // first char can't be escaped
641  if (pos == 0)
642  {
643  return pos;
644  }
645 
646  while (pos != -1)
647  {
648  // look back for the escape character
649  if (escapedText.at(pos - 1) != ESCAPE_CHAR)
650  {
651  return pos;
652  }
653 
654  // scan for the next instance of ch
655  pos = escapedText.indexOf(ch, pos + 1);
656  }
657 
658  return pos;
659 }
660 
661 }
berry::SmartPointer< const Self > ConstPointer
Definition: berryObject.h:89
static MsgHandler handler
Definition: usUtils.cpp:261
QList< SmartPointer< Command > > GetAllCommands() const
Message2< const QString &, const NotEnabledException * > notEnabled
static const char PARAMETER_START_CHAR
SmartPointer< Command > GetCommand(const QString &commandId)
SmartPointer< CommandCategory > GetCategory(const QString &categoryId)
void FireNotDefined(const QString &commandId, const NotDefinedException *exception)
void FirePreExecute(const QString &commandId, const SmartPointer< const ExecutionEvent > event)
void SetHandlersByCommandId(const QHash< QString, SmartPointer< IHandler > > &handlersByCommandId)
QSet< QString > GetDefinedCommandIds() const
QList< SmartPointer< CommandCategory > > GetDefinedCategories()
static const char ESCAPE_CHAR
Message2< const QString &, const ExecutionException * > postExecuteFailure
void FirePostExecuteSuccess(const QString &commandId, Object::Pointer returnValue)
void SetHelpContextId(const SmartPointer< IHandler > handler, const QString &helpContextId)
QSet< QString > GetDefinedHandleObjectIds() const
void RemoveCommandManagerListener(ICommandManagerListener *listener)
berry::SmartPointer< Self > Pointer
Definition: berryObject.h:88
QList< SmartPointer< ParameterType > > GetDefinedParameterTypes()
void FireNotEnabled(const QString &commandId, const NotEnabledException *exception)
static const char PARAMETER_END_CHAR
void RemoveListener(IExecutionListener *listener) override
void FirePostExecuteFailure(const QString &commandId, const ExecutionException *exception)
QString GetHelpContextId(const SmartPointer< const Command > command) const
SmartPointer< ParameterizedCommand > Deserialize(const QString &serializedParameterizedCommand)
Message2< const QString &, const NotDefinedException * > notDefined
void DefineUncategorizedCategory(const QString &name, const QString &description)
QSet< QString > GetDefinedParameterTypeIds() const
void CheckId(const QString &id) const
static const char PARAMETER_SEPARATOR_CHAR
void RemoveListener(ICommandManagerListener *listener)
static const QString AUTOGENERATED_CATEGORY_ID
HandleObjectsByIdMap handleObjectsById
Message2< const QString &, const Object::Pointer & > postExecuteSuccess
static const char ID_VALUE_CHAR
QList< SmartPointer< Command > > GetDefinedCommands() const
QSet< QString > GetDefinedCategoryIds() const
SmartPointer< ParameterType > GetParameterType(const QString &parameterTypeId)
SmartPointer< Other > Cast() const
void RemoveExecutionListener(IExecutionListener *listener)
void AddCommandManagerListener(ICommandManagerListener *listener)
void AddListener(ICommandManagerListener *listener)
void AddExecutionListener(IExecutionListener *listener)
Message2< const QString &, const SmartPointer< const ExecutionEvent > & > preExecute
void AddListener(IExecutionListener *listener) override