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