Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
berryCommand.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 "berryCommand.h"
14 
15 #include "berryIParameter.h"
16 #include "berryITypedParameter.h"
17 #include "berryIHandler.h"
18 #include "berryIHandlerListener.h"
20 #include "berryHandlerEvent.h"
21 #include "berryCommandEvent.h"
22 #include "berryExecutionEvent.h"
23 #include "berryCommandCategory.h"
24 #include "berryState.h"
25 
27 #include "internal/berryCommandUtils.h"
28 
29 #include <QTextStream>
30 
31 namespace berry {
32 
34 
35 bool Command::DEBUG_HANDLERS = false;
36 
37 QString Command::DEBUG_HANDLERS_COMMAND_ID = QString::null;
38 
39 
40 Command::Command(const QString& id)
42 {
43 }
44 
46 {
47  if (!commandListener)
48  {
49  throw ctkInvalidArgumentException("Cannot add a null command listener");
50  }
51  commandEvents.AddListener(commandListener);
52 }
53 
55 {
56  if (!executionListener)
57  {
58  throw ctkInvalidArgumentException("Cannot add a null execution listener");
59  }
60  executionEvents.AddListener(executionListener);
61 }
62 
63 void Command::AddState(const QString& id, const State::Pointer& state)
64 {
66  state->SetId(id);
67  if (IObjectWithState::Pointer stateHandler = handler.Cast<IObjectWithState>())
68  {
69  stateHandler->AddState(id, state);
70  }
71 }
72 
73 bool Command::operator<(const Object* object) const
74 {
75  const Command* castedObject = dynamic_cast<const Command*>(object);
76  int compareTo = CommandUtils::CompareObj(category, castedObject->category);
77  if (compareTo == 0)
78  {
79  compareTo = CommandUtils::Compare(defined, castedObject->defined);
80  if (compareTo == 0)
81  {
82  compareTo = CommandUtils::Compare(description, castedObject->description);
83  if (compareTo == 0)
84  {
85  compareTo = CommandUtils::CompareObj(handler, castedObject->handler);
86  if (compareTo == 0)
87  {
88  compareTo = CommandUtils::Compare(id, castedObject->id);
89  if (compareTo == 0)
90  {
91  compareTo = CommandUtils::Compare(name, castedObject->name);
92  if (compareTo == 0)
93  {
94  compareTo = CommandUtils::Compare(parameters,
95  castedObject->parameters);
96  }
97  }
98  }
99  }
100  }
101  }
102  return compareTo < 0;
103 }
104 
105 void Command::Define(const QString& name, const QString& description,
106  const CommandCategory::Pointer category,
107  const QList<IParameter::Pointer>& parameters,
108  const ParameterType::Pointer& returnType,
109  const QString& helpContextId)
110 {
111  if (name == "")
112  {
113  throw ctkInvalidArgumentException("The name of a command cannot be empty");
114  }
115 
116  if (!category)
117  {
118  throw ctkInvalidArgumentException("The category of a command cannot be null");
119  }
120 
121  const bool definedChanged = !this->defined;
122  this->defined = true;
123 
124  const bool nameChanged = this->name != name;
125  this->name = name;
126 
127  const bool descriptionChanged = this->description != description;
128  this->description = description;
129 
130  const bool categoryChanged = this->category != category;
131  this->category = category;
132 
133  const bool parametersChanged = !CommandUtils::Equals(this->parameters,
134  parameters);
135  this->parameters = parameters;
136 
137  const bool returnTypeChanged = this->returnType != returnType;
138  this->returnType = returnType;
139 
140  const bool helpContextIdChanged = this->helpContextId != helpContextId;
141  this->helpContextId = helpContextId;
142 
143  CommandEvent::Pointer event(new CommandEvent(Command::Pointer(this), categoryChanged,
144  definedChanged, descriptionChanged, false, nameChanged,
145  parametersChanged, returnTypeChanged, helpContextIdChanged));
146  this->FireCommandChanged(event);
147 }
148 
150 {
151  this->FirePreExecute(event);
152  const IHandler::Pointer handler(this->handler);
153 
154  if (!this->IsDefined())
155  {
156  const NotDefinedException exception(
157  "Trying to execute a command that is not defined. " + this->GetId());
158  this->FireNotDefined(&exception);
159  throw exception;
160  }
161 
162  // Perform the execution, if there is a handler.
163  if (handler && handler->IsHandled())
164  {
165  this->SetEnabled(event->GetApplicationContext());
166  if (!this->IsEnabled()) {
167  const NotEnabledException exception(
168  "Trying to execute the disabled command " + this->GetId());
169  this->FireNotEnabled(&exception);
170  throw exception;
171  }
172 
173  try
174  {
175  const Object::Pointer returnValue(handler->Execute(event));
176  this->FirePostExecuteSuccess(returnValue);
177  return returnValue;
178  }
179  catch (const ExecutionException* e)
180  {
181  this->FirePostExecuteFailure(e);
182  throw e;
183  }
184  }
185 
186  const NotHandledException e(
187  "There is no handler to execute for command " + this->GetId());
188  this->FireNotHandled(&e);
189  throw e;
190 }
191 
192 void Command::FireCommandChanged(const CommandEvent::ConstPointer commandEvent)
193 {
194  if (!commandEvent)
195  {
196  throw ctkInvalidArgumentException("Cannot fire a null event");
197  }
198 
199  try
200  {
201  commandEvents.commandChanged(commandEvent);
202  }
203  catch (...)
204  {
205  //TODO log exceptions?
206  }
207 }
208 
209 void Command::FireNotDefined(const NotDefinedException* e)
210 {
211  // Debugging output
213  {
215  + "not defined: id=" + this->GetId() + "; exception=" + e->what());
216  }
217 
218  executionEvents.notDefined(this->GetId(), e);
219 }
220 
221 void Command::FireNotEnabled(const NotEnabledException* e)
222 {
223  // Debugging output
225  {
227  + "not enabled: id=" + this->GetId() + "; exception=" + e->what());
228  }
229 
230  executionEvents.notEnabled(this->GetId(), e);
231 }
232 
233 void Command::FireNotHandled(const NotHandledException* e)
234 {
235  // Debugging output
238  + "not handled: id=" + this->GetId() + "; exception=" + e->what());
239  }
240 
241  executionEvents.notHandled(this->GetId(), e);
242 }
243 
244 void Command::FirePostExecuteFailure(const ExecutionException* e)
245 {
246  // Debugging output
248  {
250  + "failure: id=" + this->GetId() + "; exception=" + e->what());
251  }
252 
253  executionEvents.postExecuteFailure(this->GetId(), e);
254 }
255 
256 void Command::FirePostExecuteSuccess(const Object::Pointer returnValue)
257 {
258  // Debugging output
260  {
262  + "success: id=" + this->GetId() + "; returnValue=" +
263  (returnValue.IsNull() ? QString("nullptr") : returnValue->ToString()));
264  }
265 
266  executionEvents.postExecuteSuccess(this->GetId(), returnValue);
267 }
268 
269 void Command::FirePreExecute(const ExecutionEvent::ConstPointer event)
270 {
271  // Debugging output
273  {
275  + "starting: id=" + this->GetId() + "; event=" + event->ToString());
276  }
277 
278  executionEvents.preExecute(this->GetId(), event);
279 }
280 
282 {
283  return handler;
284 }
285 
287 {
288  return helpContextId;
289 }
290 
291 IParameter::Pointer Command::GetParameter(const QString& parameterId) const
292 {
293  if (!this->IsDefined())
294  {
295  throw NotDefinedException(
296  "Cannot get a parameter from an undefined command. " + id);
297  }
298 
299  for (int i = 0; i < parameters.size(); i++)
300  {
301  IParameter::Pointer parameter(parameters[i]);
302  if (parameter->GetId() == parameterId) {
303  return parameter;
304  }
305  }
306 
307  return IParameter::Pointer(nullptr);
308 }
309 
310 QList<SmartPointer<IParameter> > Command::GetParameters() const
311 {
312  if (!this->IsDefined())
313  {
314  throw NotDefinedException(
315  "Cannot get the parameters from an undefined command. " + id);
316  }
317 
318  return parameters;
319 }
320 
321 ParameterType::Pointer Command::GetParameterType(const QString& parameterId) const
322 {
323  const IParameter::Pointer parameter(this->GetParameter(parameterId));
324  if (ITypedParameter::Pointer parameterWithType = parameter.Cast<ITypedParameter>())
325  {
326  return parameterWithType->GetParameterType();
327  }
328  return ParameterType::Pointer(nullptr);
329 }
330 
332 {
333  if (!this->IsDefined())
334  {
335  throw NotDefinedException(
336  "Cannot get the return type of an undefined command. " + id);
337  }
338 
339  return returnType;
340 }
341 
342 bool Command::IsEnabled() const
343 {
344  if (!handler)
345  {
346  return false;
347  }
348 
349  return handler->IsEnabled();
350 }
351 
352 void Command::SetEnabled(const Object::Pointer& evaluationContext)
353 {
354  if (handler)
355  {
356  handler->SetEnabled(evaluationContext);
357  }
358 }
359 
360 bool Command::IsHandled() const
361 {
362  if (!handler)
363  {
364  return false;
365  }
366 
367  return handler->IsHandled();
368 }
369 
371 {
372  if (!commandListener)
373  {
374  throw ctkInvalidArgumentException(
375  "Cannot remove a null command listener");
376  }
377 
378  commandEvents.RemoveListener(commandListener);
379 }
380 
389 {
390  if (!executionListener)
391  {
392  throw Poco::NullPointerException(
393  "Cannot remove a null execution listener");
394  }
395  executionEvents.RemoveListener(executionListener);
396 }
397 
398 void Command::RemoveState(const QString& stateId)
399 {
400  if (IObjectWithState::Pointer stateHandler = handler.Cast<IObjectWithState>())
401  {
402  stateHandler->RemoveState(stateId);
403  }
405 }
406 
408 {
409  if (handler == this->handler)
410  {
411  return false;
412  }
413 
414  // Swap the state around.
415  const QList<QString> stateIds(this->GetStateIds());
416  for (int i = 0; i < stateIds.size(); ++i)
417  {
418  const QString stateId = stateIds[i];
419  if (IObjectWithState::Pointer stateHandler = this->handler.Cast<IObjectWithState>())
420  {
421  stateHandler->RemoveState(stateId);
422  }
423  if (IObjectWithState::Pointer stateHandler = handler.Cast<IObjectWithState>())
424  {
425  const State::Pointer stateToAdd(this->GetState(stateId));
426  stateHandler->AddState(stateId, stateToAdd);
427  }
428  }
429 
430  bool enabled = this->IsEnabled();
431  if (this->handler)
432  {
433  this->handler->RemoveHandlerListener(this->GetHandlerListener());
434  }
435 
436  // Update the handler, and flush the string representation.
437  this->handler = handler;
438  if (this->handler)
439  {
440  this->handler->AddHandlerListener(this->GetHandlerListener());
441  }
442  this->str = "";
443 
444  // Debugging output
445  if ((DEBUG_HANDLERS)
446  && ((DEBUG_HANDLERS_COMMAND_ID.isEmpty()) || (DEBUG_HANDLERS_COMMAND_ID == id)))
447  {
448  QString buffer("Command('");
449  buffer += id + "') has changed to ";
450  if (!handler) {
451  buffer += "no handler";
452  } else {
453  buffer += "\'" + handler->ToString() + "' as its handler";
454  }
455  CommandTracing::PrintTrace("HANDLERS", buffer);
456  }
457 
458  // Send notification
459  CommandEvent::Pointer cmdEvent(new CommandEvent(Command::Pointer(this), false, false, false, true,
460  false, false, false, false, enabled != this->IsEnabled()));
461  this->FireCommandChanged(cmdEvent);
462 
463  return true;
464 }
465 
466 IHandlerListener* Command::GetHandlerListener()
467 {
468  return this;
469 }
470 
471 void Command::HandlerChanged(const SmartPointer<HandlerEvent>& handlerEvent)
472 {
473  bool enabledChanged = handlerEvent->IsEnabledChanged();
474  bool handledChanged = handlerEvent->IsHandledChanged();
475  CommandEvent::Pointer cmdEvent(new CommandEvent(Command::Pointer(this), false,
476  false, false, handledChanged, false, false, false,
477  false, enabledChanged));
478  this->FireCommandChanged(cmdEvent);
479 }
480 
481 QString Command::ToString() const
482 {
483  if (str.isEmpty())
484  {
485  QTextStream buffer(&str);
486 
487  buffer << "Command(" << id << ',' << name << ",\n\t\t";
488  buffer << description << ",\n\t\t" << (category ? category->ToString() : QString(""));
489  buffer << ",\n\t\t" << (handler ? handler->ToString() : "");
490  buffer << ",\n\t\t" << "[";
491  for (int i = 0; i < parameters.size(); ++i)
492  {
493  buffer << parameters[i]->GetId();
494  }
495  buffer << "]," << (returnType ? returnType->ToString() : "");
496  buffer << "," << defined << ")";
497  }
498  return str;
499 }
500 
502 {
503  bool enabledChanged = this->IsEnabled();
504 
505  str = "";
506 
507  const bool definedChanged = defined;
508  defined = false;
509 
510  const bool nameChanged = !name.isEmpty();
511  name = "";
512 
513  const bool descriptionChanged = !description.isEmpty();
514  description = "";
515 
516  const bool categoryChanged = category;
517  category = nullptr;
518 
519  const bool parametersChanged = !parameters.empty();
520  parameters.clear();
521 
522  const bool returnTypeChanged = returnType;
523  returnType = nullptr;
524 
525  const QList<QString> stateIds(this->GetStateIds());
526  if (IObjectWithState::Pointer handlerWithState = handler.Cast<IObjectWithState>())
527  {
528  for (int i = 0; i < stateIds.size(); i++)
529  {
530  const QString stateId(stateIds[i]);
531  handlerWithState->RemoveState(stateId);
532 
533  const State::Pointer state(this->GetState(stateId));
534  this->RemoveState(stateId);
535  //state.dispose();
536  }
537  }
538  else
539  {
540  for (int i = 0; i < stateIds.size(); ++i)
541  {
542  const QString stateId(stateIds[i]);
543  const State::Pointer state(this->GetState(stateId));
544  this->RemoveState(stateId);
545  //state.dispose();
546  }
547  }
548 
549  CommandEvent::Pointer cmdEvent(new CommandEvent(Command::Pointer(this), categoryChanged,
550  definedChanged, descriptionChanged, false, nameChanged,
551  parametersChanged, returnTypeChanged, false, enabledChanged));
552  this->FireCommandChanged(cmdEvent);
553 }
554 
555 }
void RemoveState(const QString &id) override
Message2< const QString &, const NotEnabledException * > notEnabled
Object::Pointer ExecuteWithChecks(const SmartPointer< const ExecutionEvent > event)
void AddExecutionListener(IExecutionListener *executionListener)
void RemoveListener(ICommandListener *listener)
Light weight base class for most BlueBerry classes.
Definition: berryObject.h:72
SmartPointer< Other > Cast() const
void AddState(const QString &id, const SmartPointer< State > &state) override
Message2< const QString &, const ExecutionException * > postExecuteFailure
void AddCommandListener(ICommandListener *commandListener)
static void PrintTrace(const QString &component, const QString &message)
bool operator<(const Object *object) const override
static const QString SEPARATOR
void AddState(const QString &stateId, const SmartPointer< State > &state) override
QList< QString > GetStateIds() const override
QString GetHelpContextId() const
static bool DEBUG_HANDLERS
Definition: berryCommand.h:77
berry::SmartPointer< Self > Pointer
Definition: berryObject.h:82
void RemoveListener(IExecutionListener *listener) override
void Define(const QString &name, const QString &description, const SmartPointer< CommandCategory > category, const QList< SmartPointer< IParameter > > &parameters=QList< SmartPointer< IParameter > >(), const SmartPointer< ParameterType > &returnType=SmartPointer< ParameterType >(nullptr), const QString &helpContextId="")
QList< SmartPointer< IParameter > > GetParameters() const
QString ToString() const override
Message2< const QString &, const NotDefinedException * > notDefined
SmartPointer< IParameter > GetParameter(const QString &parameterId) const
void RemoveExecutionListener(IExecutionListener *executionListener)
bool IsEnabled() const
bool IsHandled() const
static bool DEBUG_COMMAND_EXECUTION
Definition: berryCommand.h:71
SmartPointer< IHandler > GetHandler() const
Message2< const QString &, const Object::Pointer & > postExecuteSuccess
void RemoveState(const QString &stateId) override
bool SetHandler(const SmartPointer< IHandler > handler)
void RemoveCommandListener(ICommandListener *commandListener)
void AddListener(ICommandListener *listener)
SmartPointer< ParameterType > GetParameterType(const QString &parameterId) const
static QString DEBUG_HANDLERS_COMMAND_ID
Definition: berryCommand.h:84
SmartPointer< State > GetState(const QString &stateId) const override
void Undefine() override
SmartPointer< ParameterType > GetReturnType() const
Message2< const QString &, const SmartPointer< const ExecutionEvent > &> preExecute
Command(const QString &id)
Message2< const QString &, const NotHandledException * > notHandled
void AddListener(IExecutionListener *listener) override
void SetEnabled(const Object::Pointer &evaluationContext)