Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
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