Mercurial > projects > dwt2
comparison org.eclipse.core.commands/src/org/eclipse/core/commands/Command.d @ 12:bc29606a740c
Added dwt-addons in original directory structure of eclipse.org
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 14 Mar 2009 18:23:29 +0100 |
parents | |
children | 735224fcc45f |
comparison
equal
deleted
inserted
replaced
11:43904fec5dca | 12:bc29606a740c |
---|---|
1 /******************************************************************************* | |
2 * Copyright (c) 2004, 2008 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module org.eclipse.core.commands.Command; | |
14 | |
15 // import java.io.BufferedWriter; | |
16 // import java.io.IOException; | |
17 // import java.io.StringWriter; | |
18 | |
19 import org.eclipse.core.commands.common.NotDefinedException; | |
20 import org.eclipse.core.commands.util.Tracing; | |
21 import org.eclipse.core.internal.commands.util.Util; | |
22 import org.eclipse.core.runtime.ISafeRunnable; | |
23 import org.eclipse.core.runtime.ListenerList; | |
24 import org.eclipse.core.runtime.SafeRunner; | |
25 | |
26 import org.eclipse.core.commands.IParameter; | |
27 import org.eclipse.core.commands.IHandlerListener; | |
28 import org.eclipse.core.commands.NotEnabledException; | |
29 import org.eclipse.core.commands.NotHandledException; | |
30 import org.eclipse.core.commands.ExecutionException; | |
31 import org.eclipse.core.commands.CommandEvent; | |
32 import org.eclipse.core.commands.State; | |
33 import org.eclipse.core.commands.Category; | |
34 import org.eclipse.core.commands.NamedHandleObjectWithState; | |
35 import org.eclipse.core.commands.ExecutionEvent; | |
36 import org.eclipse.core.commands.ParameterType; | |
37 import org.eclipse.core.commands.IExecutionListener; | |
38 import org.eclipse.core.commands.ICommandListener; | |
39 import org.eclipse.core.commands.IHandler; | |
40 import org.eclipse.core.commands.IHandler2; | |
41 import org.eclipse.core.commands.IObjectWithState; | |
42 import org.eclipse.core.commands.IExecutionListenerWithChecks; | |
43 import org.eclipse.core.commands.ITypedParameter; | |
44 import org.eclipse.core.commands.HandlerEvent; | |
45 | |
46 import java.lang.all; | |
47 import tango.io.Stdout; | |
48 | |
49 /** | |
50 * <p> | |
51 * A command is an abstract representation for some semantic behaviour. It is | |
52 * not the actual implementation of this behaviour, nor is it the visual | |
53 * appearance of this behaviour in the user interface. Instead, it is a bridge | |
54 * between the two. | |
55 * </p> | |
56 * <p> | |
57 * The concept of a command is based on the command design pattern. The notable | |
58 * difference is how the command delegates responsibility for execution. Rather | |
59 * than allowing concrete subclasses, it uses a handler mechanism (see the | |
60 * <code>handlers</code> extension point). This provides another level of | |
61 * indirection. | |
62 * </p> | |
63 * <p> | |
64 * A command will exist in two states: defined and undefined. A command is | |
65 * defined if it is declared in the XML of a resolved plug-in. If the plug-in is | |
66 * unloaded or the command is simply not declared, then it is undefined. Trying | |
67 * to reference an undefined command will succeed, but trying to access any of | |
68 * its functionality will fail with a <code>NotDefinedException</code>. If | |
69 * you need to know when a command changes from defined to undefined (or vice | |
70 * versa), then attach a command listener. | |
71 * </p> | |
72 * <p> | |
73 * Commands are mutable and will change as their definition changes. | |
74 * </p> | |
75 * | |
76 * @since 3.1 | |
77 */ | |
78 public final class Command : NamedHandleObjectWithState, | |
79 Comparable { | |
80 | |
81 /** | |
82 * This flag can be set to <code>true</code> if commands should print | |
83 * information to <code>System.out</code> when executing. | |
84 */ | |
85 public static bool DEBUG_COMMAND_EXECUTION = false; | |
86 | |
87 /** | |
88 * This flag can be set to <code>true</code> if commands should print | |
89 * information to <code>System.out</code> when changing handlers. | |
90 */ | |
91 public static bool DEBUG_HANDLERS = false; | |
92 | |
93 /** | |
94 * This flag can be set to a particular command identifier if only that | |
95 * command should print information to <code>System.out</code> when | |
96 * changing handlers. | |
97 */ | |
98 public static String DEBUG_HANDLERS_COMMAND_ID = null; | |
99 | |
100 /** | |
101 * The category to which this command belongs. This value should not be | |
102 * <code>null</code> unless the command is undefined. | |
103 */ | |
104 private Category category = null; | |
105 | |
106 /** | |
107 * A collection of objects listening to the execution of this command. This | |
108 * collection is <code>null</code> if there are no listeners. | |
109 */ | |
110 private /+transient+/ ListenerList executionListeners = null; | |
111 | |
112 /** | |
113 * The handler currently associated with this command. This value may be | |
114 * <code>null</code> if there is no handler currently. | |
115 */ | |
116 private /+transient+/ IHandler handler = null; | |
117 | |
118 /** | |
119 * The help context identifier for this command. This can be | |
120 * <code>null</code> if there is no help currently associated with the | |
121 * command. | |
122 * | |
123 * @since 3.2 | |
124 */ | |
125 private String helpContextId; | |
126 | |
127 /** | |
128 * The ordered array of parameters understood by this command. This value | |
129 * may be <code>null</code> if there are no parameters, or if the command | |
130 * is undefined. It may also be empty. | |
131 */ | |
132 private IParameter[] parameters = null; | |
133 | |
134 /** | |
135 * The type of the return value of this command. This value may be | |
136 * <code>null</code> if the command does not declare a return type. | |
137 * | |
138 * @since 3.2 | |
139 */ | |
140 private ParameterType returnType = null; | |
141 | |
142 /** | |
143 * Our command will listen to the active handler for enablement changes so | |
144 * that they can be fired from the command itself. | |
145 * | |
146 * @since 3.3 | |
147 */ | |
148 private IHandlerListener handlerListener; | |
149 | |
150 /** | |
151 * Constructs a new instance of <code>Command</code> based on the given | |
152 * identifier. When a command is first constructed, it is undefined. | |
153 * Commands should only be constructed by the <code>CommandManager</code> | |
154 * to ensure that the identifier remains unique. | |
155 * | |
156 * @param id | |
157 * The identifier for the command. This value must not be | |
158 * <code>null</code>, and must be unique amongst all commands. | |
159 */ | |
160 this(String id) { | |
161 super(id); | |
162 } | |
163 | |
164 /** | |
165 * Adds a listener to this command that will be notified when this command's | |
166 * state changes. | |
167 * | |
168 * @param commandListener | |
169 * The listener to be added; must not be <code>null</code>. | |
170 */ | |
171 public final void addCommandListener(ICommandListener commandListener) { | |
172 if (commandListener is null) { | |
173 throw new NullPointerException("Cannot add a null command listener"); //$NON-NLS-1$ | |
174 } | |
175 addListenerObject(cast(Object)commandListener); | |
176 } | |
177 | |
178 /** | |
179 * Adds a listener to this command that will be notified when this command | |
180 * is about to execute. | |
181 * | |
182 * @param executionListener | |
183 * The listener to be added; must not be <code>null</code>. | |
184 */ | |
185 public final void addExecutionListener( | |
186 IExecutionListener executionListener) { | |
187 if (executionListener is null) { | |
188 throw new NullPointerException( | |
189 "Cannot add a null execution listener"); //$NON-NLS-1$ | |
190 } | |
191 | |
192 if (executionListeners is null) { | |
193 executionListeners = new ListenerList(ListenerList.IDENTITY); | |
194 } | |
195 | |
196 executionListeners.add(cast(Object)executionListener); | |
197 } | |
198 | |
199 /** | |
200 * <p> | |
201 * Adds a state to this command. This will add this state to the active | |
202 * handler, if the active handler is an instance of {@link IObjectWithState}. | |
203 * </p> | |
204 * <p> | |
205 * A single instance of {@link State} cannot be registered with multiple | |
206 * commands. Each command requires its own unique instance. | |
207 * </p> | |
208 * | |
209 * @param id | |
210 * The identifier of the state to add; must not be | |
211 * <code>null</code>. | |
212 * @param state | |
213 * The state to add; must not be <code>null</code>. | |
214 * @since 3.2 | |
215 */ | |
216 public override void addState(String id, State state) { | |
217 super.addState(id, state); | |
218 state.setId(id); | |
219 if ( auto h = cast(IObjectWithState)handler) { | |
220 h.addState(id, state); | |
221 } | |
222 } | |
223 | |
224 /** | |
225 * Compares this command with another command by comparing each of its | |
226 * non-transient attributes. | |
227 * | |
228 * @param object | |
229 * The object with which to compare; must be an instance of | |
230 * <code>Command</code>. | |
231 * @return A negative integer, zero or a postivie integer, if the object is | |
232 * greater than, equal to or less than this command. | |
233 */ | |
234 public final int compareTo(Object object) { | |
235 Command castedObject = cast(Command) object; | |
236 int compareTo = Util.compare(category, castedObject.category); | |
237 if (compareTo is 0) { | |
238 compareTo = Util.compare(defined, castedObject.defined); | |
239 if (compareTo is 0) { | |
240 compareTo = Util.compare(description, castedObject.description); | |
241 if (compareTo is 0) { | |
242 compareTo = Util.compare(cast(Object)handler, cast(Object)castedObject.handler); | |
243 if (compareTo is 0) { | |
244 compareTo = Util.compare(id, castedObject.id); | |
245 if (compareTo is 0) { | |
246 compareTo = Util.compare(name, castedObject.name); | |
247 if (compareTo is 0) { | |
248 Object[] left, right; | |
249 foreach( p; parameters ){ | |
250 left ~= cast(Object)p; | |
251 } | |
252 foreach( p; castedObject.parameters ){ | |
253 right ~= cast(Object)p; | |
254 } | |
255 compareTo = Util.compare(left, | |
256 right); | |
257 } | |
258 } | |
259 } | |
260 } | |
261 } | |
262 } | |
263 return compareTo; | |
264 } | |
265 | |
266 /** | |
267 * <p> | |
268 * Defines this command by giving it a name, and possibly a description as | |
269 * well. The defined property automatically becomes <code>true</code>. | |
270 * </p> | |
271 * <p> | |
272 * Notification is sent to all listeners that something has changed. | |
273 * </p> | |
274 * | |
275 * @param name | |
276 * The name of this command; must not be <code>null</code>. | |
277 * @param description | |
278 * The description for this command; may be <code>null</code>. | |
279 * @param category | |
280 * The category for this command; must not be <code>null</code>. | |
281 * @since 3.2 | |
282 */ | |
283 public final void define(String name, String description, | |
284 Category category) { | |
285 define(name, description, category, null); | |
286 } | |
287 | |
288 /** | |
289 * <p> | |
290 * Defines this command by giving it a name, and possibly a description as | |
291 * well. The defined property automatically becomes <code>true</code>. | |
292 * </p> | |
293 * <p> | |
294 * Notification is sent to all listeners that something has changed. | |
295 * </p> | |
296 * | |
297 * @param name | |
298 * The name of this command; must not be <code>null</code>. | |
299 * @param description | |
300 * The description for this command; may be <code>null</code>. | |
301 * @param category | |
302 * The category for this command; must not be <code>null</code>. | |
303 * @param parameters | |
304 * The parameters understood by this command. This value may be | |
305 * either <code>null</code> or empty if the command does not | |
306 * accept parameters. | |
307 */ | |
308 public final void define(String name, String description, | |
309 Category category, IParameter[] parameters) { | |
310 define(name, description, category, parameters, null); | |
311 } | |
312 | |
313 /** | |
314 * <p> | |
315 * Defines this command by giving it a name, and possibly a description as | |
316 * well. The defined property automatically becomes <code>true</code>. | |
317 * </p> | |
318 * <p> | |
319 * Notification is sent to all listeners that something has changed. | |
320 * </p> | |
321 * | |
322 * @param name | |
323 * The name of this command; must not be <code>null</code>. | |
324 * @param description | |
325 * The description for this command; may be <code>null</code>. | |
326 * @param category | |
327 * The category for this command; must not be <code>null</code>. | |
328 * @param parameters | |
329 * The parameters understood by this command. This value may be | |
330 * either <code>null</code> or empty if the command does not | |
331 * accept parameters. | |
332 * @param returnType | |
333 * The type of value returned by this command. This value may be | |
334 * <code>null</code> if the command does not declare a return | |
335 * type. | |
336 * @since 3.2 | |
337 */ | |
338 public final void define(String name, String description, | |
339 Category category, IParameter[] parameters, | |
340 ParameterType returnType) { | |
341 define(name, description, category, parameters, returnType, null); | |
342 } | |
343 | |
344 /** | |
345 * <p> | |
346 * Defines this command by giving it a name, and possibly a description as | |
347 * well. The defined property automatically becomes <code>true</code>. | |
348 * </p> | |
349 * <p> | |
350 * Notification is sent to all listeners that something has changed. | |
351 * </p> | |
352 * | |
353 * @param name | |
354 * The name of this command; must not be <code>null</code>. | |
355 * @param description | |
356 * The description for this command; may be <code>null</code>. | |
357 * @param category | |
358 * The category for this command; must not be <code>null</code>. | |
359 * @param parameters | |
360 * The parameters understood by this command. This value may be | |
361 * either <code>null</code> or empty if the command does not | |
362 * accept parameters. | |
363 * @param returnType | |
364 * The type of value returned by this command. This value may be | |
365 * <code>null</code> if the command does not declare a return | |
366 * type. | |
367 * @param helpContextId | |
368 * The identifier of the help context to associate with this | |
369 * command; may be <code>null</code> if this command does not | |
370 * have any help associated with it. | |
371 * @since 3.2 | |
372 */ | |
373 public final void define(String name, String description, | |
374 Category category, IParameter[] parameters, | |
375 ParameterType returnType, String helpContextId) { | |
376 if (name is null) { | |
377 throw new NullPointerException( | |
378 "The name of a command cannot be null"); //$NON-NLS-1$ | |
379 } | |
380 | |
381 if (category is null) { | |
382 throw new NullPointerException( | |
383 "The category of a command cannot be null"); //$NON-NLS-1$ | |
384 } | |
385 | |
386 bool definedChanged = !this.defined; | |
387 this.defined = true; | |
388 | |
389 bool nameChanged = !Util.equals(this.name, name); | |
390 this.name = name; | |
391 | |
392 bool descriptionChanged = !Util.equals(this.description, | |
393 description); | |
394 this.description = description; | |
395 | |
396 bool categoryChanged = !Util.equals(this.category, category); | |
397 this.category = category; | |
398 | |
399 Object[] pLeft, pRight; | |
400 foreach( p; this.parameters ){ | |
401 pLeft ~= cast(Object)p; | |
402 } | |
403 foreach( p; parameters ){ | |
404 pRight ~= cast(Object)p; | |
405 } | |
406 bool parametersChanged = !Util.equals(pLeft, | |
407 pRight); | |
408 this.parameters = parameters; | |
409 | |
410 bool returnTypeChanged = !Util.equals(this.returnType, | |
411 returnType); | |
412 this.returnType = returnType; | |
413 | |
414 bool helpContextIdChanged = !Util.equals(this.helpContextId, | |
415 helpContextId); | |
416 this.helpContextId = helpContextId; | |
417 | |
418 fireCommandChanged(new CommandEvent(this, categoryChanged, | |
419 definedChanged, descriptionChanged, false, nameChanged, | |
420 parametersChanged, returnTypeChanged, helpContextIdChanged)); | |
421 } | |
422 | |
423 /** | |
424 * Executes this command by delegating to the current handler, if any. If | |
425 * the debugging flag is set, then this method prints information about | |
426 * which handler is selected for performing this command. This method will | |
427 * succeed regardless of whether the command is enabled or defined. It is | |
428 * generally preferred to call {@link #executeWithChecks(ExecutionEvent)}. | |
429 * | |
430 * @param event | |
431 * An event containing all the information about the current | |
432 * state of the application; must not be <code>null</code>. | |
433 * @return The result of the execution; may be <code>null</code>. This | |
434 * result will be available to the client executing the command, and | |
435 * execution listeners. | |
436 * @throws ExecutionException | |
437 * If the handler has problems executing this command. | |
438 * @throws NotHandledException | |
439 * If there is no handler. | |
440 * @deprecated Please use {@link #executeWithChecks(ExecutionEvent)} | |
441 * instead. | |
442 */ | |
443 public final Object execute(ExecutionEvent event) { | |
444 firePreExecute(event); | |
445 IHandler handler = this.handler; | |
446 | |
447 // Perform the execution, if there is a handler. | |
448 if ((handler !is null) && (handler.isHandled())) { | |
449 try { | |
450 Object returnValue = handler.execute(event); | |
451 firePostExecuteSuccess(returnValue); | |
452 return returnValue; | |
453 } catch (ExecutionException e) { | |
454 firePostExecuteFailure(e); | |
455 throw e; | |
456 } | |
457 } | |
458 | |
459 NotHandledException e = new NotHandledException( | |
460 "There is no handler to execute. " ~ getId()); //$NON-NLS-1$ | |
461 fireNotHandled(e); | |
462 throw e; | |
463 } | |
464 | |
465 /** | |
466 * Executes this command by delegating to the current handler, if any. If | |
467 * the debugging flag is set, then this method prints information about | |
468 * which handler is selected for performing this command. This does checks | |
469 * to see if the command is enabled and defined. If it is not both enabled | |
470 * and defined, then the execution listeners will be notified and an | |
471 * exception thrown. | |
472 * | |
473 * @param event | |
474 * An event containing all the information about the current | |
475 * state of the application; must not be <code>null</code>. | |
476 * @return The result of the execution; may be <code>null</code>. This | |
477 * result will be available to the client executing the command, and | |
478 * execution listeners. | |
479 * @throws ExecutionException | |
480 * If the handler has problems executing this command. | |
481 * @throws NotDefinedException | |
482 * If the command you are trying to execute is not defined. | |
483 * @throws NotEnabledException | |
484 * If the command you are trying to execute is not enabled. | |
485 * @throws NotHandledException | |
486 * If there is no handler. | |
487 * @since 3.2 | |
488 */ | |
489 public final Object executeWithChecks(ExecutionEvent event) { | |
490 firePreExecute(event); | |
491 IHandler handler = this.handler; | |
492 | |
493 if (!isDefined()) { | |
494 NotDefinedException exception = new NotDefinedException( | |
495 "Trying to execute a command that is not defined. " //$NON-NLS-1$ | |
496 ~ getId()); | |
497 fireNotDefined(exception); | |
498 throw exception; | |
499 } | |
500 | |
501 // Perform the execution, if there is a handler. | |
502 if ((handler !is null) && (handler.isHandled())) { | |
503 setEnabled(event.getApplicationContext()); | |
504 if (!isEnabled()) { | |
505 NotEnabledException exception = new NotEnabledException( | |
506 "Trying to execute the disabled command " ~ getId()); //$NON-NLS-1$ | |
507 fireNotEnabled(exception); | |
508 throw exception; | |
509 } | |
510 | |
511 try { | |
512 Object returnValue = handler.execute(event); | |
513 firePostExecuteSuccess(returnValue); | |
514 return returnValue; | |
515 } catch (ExecutionException e) { | |
516 firePostExecuteFailure(e); | |
517 throw e; | |
518 } | |
519 } | |
520 | |
521 NotHandledException e = new NotHandledException( | |
522 "There is no handler to execute for command " ~ getId()); //$NON-NLS-1$ | |
523 fireNotHandled(e); | |
524 throw e; | |
525 } | |
526 | |
527 /** | |
528 * Notifies the listeners for this command that it has changed in some way. | |
529 * | |
530 * @param commandEvent | |
531 * The event to send to all of the listener; must not be | |
532 * <code>null</code>. | |
533 */ | |
534 private final void fireCommandChanged(CommandEvent commandEvent) { | |
535 if (commandEvent is null) { | |
536 throw new NullPointerException("Cannot fire a null event"); //$NON-NLS-1$ | |
537 } | |
538 | |
539 Object[] listeners = getListeners(); | |
540 for (int i = 0; i < listeners.length; i++) { | |
541 ICommandListener listener = cast(ICommandListener) listeners[i]; | |
542 SafeRunner.run(new class(listener) ISafeRunnable { | |
543 ICommandListener listener_; | |
544 this(ICommandListener a){ this.listener_ = a; } | |
545 public void handleException(Exception exception) { | |
546 } | |
547 | |
548 public void run() { | |
549 listener_.commandChanged(commandEvent); | |
550 } | |
551 }); | |
552 } | |
553 } | |
554 | |
555 /** | |
556 * Notifies the execution listeners for this command that an attempt to | |
557 * execute has failed because the command is not defined. | |
558 * | |
559 * @param e | |
560 * The exception that is about to be thrown; never | |
561 * <code>null</code>. | |
562 * @since 3.2 | |
563 */ | |
564 private final void fireNotDefined(NotDefinedException e) { | |
565 // Debugging output | |
566 if (DEBUG_COMMAND_EXECUTION) { | |
567 Tracing.printTrace("COMMANDS", "execute" ~ Tracing.SEPARATOR //$NON-NLS-1$ //$NON-NLS-2$ | |
568 ~ "not defined: id=" ~ getId() ~ "; exception=" ~ e.toString ); //$NON-NLS-1$ //$NON-NLS-2$ | |
569 } | |
570 | |
571 if (executionListeners !is null) { | |
572 Object[] listeners = executionListeners.getListeners(); | |
573 for (int i = 0; i < listeners.length; i++) { | |
574 Object object = listeners[i]; | |
575 if ( auto listener = cast(IExecutionListenerWithChecks)object ) { | |
576 listener.notDefined(getId(), e); | |
577 } | |
578 } | |
579 } | |
580 } | |
581 | |
582 /** | |
583 * Notifies the execution listeners for this command that an attempt to | |
584 * execute has failed because there is no handler. | |
585 * | |
586 * @param e | |
587 * The exception that is about to be thrown; never | |
588 * <code>null</code>. | |
589 * @since 3.2 | |
590 */ | |
591 private final void fireNotEnabled(NotEnabledException e) { | |
592 // Debugging output | |
593 if (DEBUG_COMMAND_EXECUTION) { | |
594 Tracing.printTrace("COMMANDS", "execute" ~ Tracing.SEPARATOR //$NON-NLS-1$ //$NON-NLS-2$ | |
595 ~ "not enabled: id=" ~ getId() ~ "; exception=" ~ e.toString ); //$NON-NLS-1$ //$NON-NLS-2$ | |
596 } | |
597 | |
598 if (executionListeners !is null) { | |
599 Object[] listeners = executionListeners.getListeners(); | |
600 for (int i = 0; i < listeners.length; i++) { | |
601 Object object = listeners[i]; | |
602 if ( auto listener = cast(IExecutionListenerWithChecks)object ) { | |
603 listener.notEnabled(getId(), e); | |
604 } | |
605 } | |
606 } | |
607 } | |
608 | |
609 /** | |
610 * Notifies the execution listeners for this command that an attempt to | |
611 * execute has failed because there is no handler. | |
612 * | |
613 * @param e | |
614 * The exception that is about to be thrown; never | |
615 * <code>null</code>. | |
616 */ | |
617 private final void fireNotHandled(NotHandledException e) { | |
618 // Debugging output | |
619 if (DEBUG_COMMAND_EXECUTION) { | |
620 Tracing.printTrace("COMMANDS", "execute" ~ Tracing.SEPARATOR //$NON-NLS-1$ //$NON-NLS-2$ | |
621 ~ "not handled: id=" ~ getId() ~ "; exception=" ~ e.toString ); //$NON-NLS-1$ //$NON-NLS-2$ | |
622 } | |
623 | |
624 if (executionListeners !is null) { | |
625 Object[] listeners = executionListeners.getListeners(); | |
626 for (int i = 0; i < listeners.length; i++) { | |
627 IExecutionListener listener = cast(IExecutionListener) listeners[i]; | |
628 listener.notHandled(getId(), e); | |
629 } | |
630 } | |
631 } | |
632 | |
633 /** | |
634 * Notifies the execution listeners for this command that an attempt to | |
635 * execute has failed during the execution. | |
636 * | |
637 * @param e | |
638 * The exception that has been thrown; never <code>null</code>. | |
639 * After this method completes, the exception will be thrown | |
640 * again. | |
641 */ | |
642 private final void firePostExecuteFailure(ExecutionException e) { | |
643 // Debugging output | |
644 if (DEBUG_COMMAND_EXECUTION) { | |
645 Tracing.printTrace("COMMANDS", "execute" ~ Tracing.SEPARATOR //$NON-NLS-1$ //$NON-NLS-2$ | |
646 ~ "failure: id=" ~ getId() ~ "; exception=" ~ e.toString ); //$NON-NLS-1$ //$NON-NLS-2$ | |
647 } | |
648 | |
649 if (executionListeners !is null) { | |
650 Object[] listeners = executionListeners.getListeners(); | |
651 for (int i = 0; i < listeners.length; i++) { | |
652 IExecutionListener listener = cast(IExecutionListener) listeners[i]; | |
653 listener.postExecuteFailure(getId(), e); | |
654 } | |
655 } | |
656 } | |
657 | |
658 /** | |
659 * Notifies the execution listeners for this command that an execution has | |
660 * completed successfully. | |
661 * | |
662 * @param returnValue | |
663 * The return value from the command; may be <code>null</code>. | |
664 */ | |
665 private final void firePostExecuteSuccess(Object returnValue) { | |
666 // Debugging output | |
667 if (DEBUG_COMMAND_EXECUTION) { | |
668 Tracing.printTrace("COMMANDS", "execute" ~ Tracing.SEPARATOR //$NON-NLS-1$ //$NON-NLS-2$ | |
669 ~ "success: id=" ~ getId() ~ "; returnValue=" //$NON-NLS-1$ //$NON-NLS-2$ | |
670 ~ returnValue.toString ); | |
671 } | |
672 | |
673 if (executionListeners !is null) { | |
674 Object[] listeners = executionListeners.getListeners(); | |
675 for (int i = 0; i < listeners.length; i++) { | |
676 IExecutionListener listener = cast(IExecutionListener) listeners[i]; | |
677 listener.postExecuteSuccess(getId(), returnValue); | |
678 } | |
679 } | |
680 } | |
681 | |
682 /** | |
683 * Notifies the execution listeners for this command that an attempt to | |
684 * execute is about to start. | |
685 * | |
686 * @param event | |
687 * The execution event that will be used; never <code>null</code>. | |
688 */ | |
689 private final void firePreExecute(ExecutionEvent event) { | |
690 // Debugging output | |
691 if (DEBUG_COMMAND_EXECUTION) { | |
692 Tracing.printTrace("COMMANDS", "execute" ~ Tracing.SEPARATOR //$NON-NLS-1$ //$NON-NLS-2$ | |
693 ~ "starting: id=" ~ getId() ~ "; event=" ~ event.toString ); //$NON-NLS-1$ //$NON-NLS-2$ | |
694 } | |
695 | |
696 if (executionListeners !is null) { | |
697 Object[] listeners = executionListeners.getListeners(); | |
698 for (int i = 0; i < listeners.length; i++) { | |
699 IExecutionListener listener = cast(IExecutionListener) listeners[i]; | |
700 listener.preExecute(getId(), event); | |
701 } | |
702 } | |
703 } | |
704 | |
705 /** | |
706 * Returns the category for this command. | |
707 * | |
708 * @return The category for this command; never <code>null</code>. | |
709 * @throws NotDefinedException | |
710 * If the handle is not currently defined. | |
711 */ | |
712 public final Category getCategory() { | |
713 if (!isDefined()) { | |
714 throw new NotDefinedException( | |
715 "Cannot get the category from an undefined command. " //$NON-NLS-1$ | |
716 ~ id); | |
717 } | |
718 | |
719 return category; | |
720 } | |
721 | |
722 /** | |
723 * Returns the current handler for this command. This is used by the command | |
724 * manager for determining the appropriate help context identifiers and by | |
725 * the command service to allow handlers to update elements. | |
726 * <p> | |
727 * This value can change at any time and should never be cached. | |
728 * </p> | |
729 * | |
730 * @return The current handler for this command; may be <code>null</code>. | |
731 * @since 3.3 | |
732 */ | |
733 public final IHandler getHandler() { | |
734 return handler; | |
735 } | |
736 | |
737 /** | |
738 * Returns the help context identifier associated with this command. This | |
739 * method should not be called by clients. Clients should use | |
740 * {@link CommandManager#getHelpContextId(Command)} instead. | |
741 * | |
742 * @return The help context identifier for this command; may be | |
743 * <code>null</code> if there is none. | |
744 * @since 3.2 | |
745 */ | |
746 final String getHelpContextId() { | |
747 return helpContextId; | |
748 } | |
749 | |
750 /** | |
751 * Returns the parameter with the provided id or <code>null</code> if this | |
752 * command does not have a parameter with the id. | |
753 * | |
754 * @param parameterId | |
755 * The id of the parameter to retrieve. | |
756 * @return The parameter with the provided id or <code>null</code> if this | |
757 * command does not have a parameter with the id. | |
758 * @throws NotDefinedException | |
759 * If the handle is not currently defined. | |
760 * @since 3.2 | |
761 */ | |
762 public final IParameter getParameter(String parameterId) { | |
763 if (!isDefined()) { | |
764 throw new NotDefinedException( | |
765 "Cannot get a parameter from an undefined command. " //$NON-NLS-1$ | |
766 ~ id); | |
767 } | |
768 | |
769 if (parameters is null) { | |
770 return null; | |
771 } | |
772 | |
773 for (int i = 0; i < parameters.length; i++) { | |
774 IParameter parameter = parameters[i]; | |
775 if (parameter.getId().equals(parameterId)) { | |
776 return parameter; | |
777 } | |
778 } | |
779 | |
780 return null; | |
781 } | |
782 | |
783 /** | |
784 * Returns the parameters for this command. This call triggers provides a | |
785 * copy of the array, so excessive calls to this method should be avoided. | |
786 * | |
787 * @return The parameters for this command. This value might be | |
788 * <code>null</code>, if the command has no parameters. | |
789 * @throws NotDefinedException | |
790 * If the handle is not currently defined. | |
791 */ | |
792 public final IParameter[] getParameters() { | |
793 if (!isDefined()) { | |
794 throw new NotDefinedException( | |
795 "Cannot get the parameters from an undefined command. " //$NON-NLS-1$ | |
796 ~ id); | |
797 } | |
798 | |
799 if ((parameters is null) || (parameters.length is 0)) { | |
800 return null; | |
801 } | |
802 | |
803 IParameter[] returnValue = new IParameter[parameters.length]; | |
804 SimpleType!(IParameter).arraycopy(parameters, 0, returnValue, 0, parameters.length); | |
805 return returnValue; | |
806 } | |
807 | |
808 /** | |
809 * Returns the {@link ParameterType} for the parameter with the provided id | |
810 * or <code>null</code> if this command does not have a parameter type | |
811 * with the id. | |
812 * | |
813 * @param parameterId | |
814 * The id of the parameter to retrieve the {@link ParameterType} | |
815 * of. | |
816 * @return The {@link ParameterType} for the parameter with the provided id | |
817 * or <code>null</code> if this command does not have a parameter | |
818 * type with the provided id. | |
819 * @throws NotDefinedException | |
820 * If the handle is not currently defined. | |
821 * @since 3.2 | |
822 */ | |
823 public final ParameterType getParameterType(String parameterId) { | |
824 IParameter parameter = getParameter(parameterId); | |
825 if ( auto parameterWithType = cast(ITypedParameter)parameter ) { | |
826 return parameterWithType.getParameterType(); | |
827 } | |
828 return null; | |
829 } | |
830 | |
831 /** | |
832 * Returns the {@link ParameterType} for the return value of this command or | |
833 * <code>null</code> if this command does not declare a return value | |
834 * parameter type. | |
835 * | |
836 * @return The {@link ParameterType} for the return value of this command or | |
837 * <code>null</code> if this command does not declare a return | |
838 * value parameter type. | |
839 * @throws NotDefinedException | |
840 * If the handle is not currently defined. | |
841 * @since 3.2 | |
842 */ | |
843 public final ParameterType getReturnType() { | |
844 if (!isDefined()) { | |
845 throw new NotDefinedException( | |
846 "Cannot get the return type of an undefined command. " //$NON-NLS-1$ | |
847 ~ id); | |
848 } | |
849 | |
850 return returnType; | |
851 } | |
852 | |
853 /** | |
854 * Returns whether this command has a handler, and whether this handler is | |
855 * also handled and enabled. | |
856 * | |
857 * @return <code>true</code> if the command is handled; <code>false</code> | |
858 * otherwise. | |
859 */ | |
860 public final bool isEnabled() { | |
861 if (handler is null) { | |
862 return false; | |
863 } | |
864 | |
865 try { | |
866 return handler.isEnabled(); | |
867 } catch (Exception e) { | |
868 if (DEBUG_HANDLERS) { | |
869 // since this has the ability to generate megs of logs, only | |
870 // provide information if tracing | |
871 Tracing.printTrace("HANDLERS", "Handler " ~ (cast(Object)handler).toString() ~ " for " //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ | |
872 ~ id ~ " threw unexpected exception"); //$NON-NLS-1$ | |
873 ExceptionPrintStackTrace( e, Stdout ); | |
874 } | |
875 } | |
876 return false; | |
877 } | |
878 | |
879 /** | |
880 * Called be the framework to allow the handler to update its enabled state. | |
881 * | |
882 * @param evaluationContext | |
883 * the state to evaluate against. May be <code>null</code> | |
884 * which indicates that the handler can query whatever model that | |
885 * is necessary. This context must not be cached. | |
886 * @since 3.4 | |
887 */ | |
888 public void setEnabled(Object evaluationContext) { | |
889 if (null !is cast(IHandler2)handler ) { | |
890 (cast(IHandler2) handler).setEnabled(evaluationContext); | |
891 } | |
892 } | |
893 | |
894 /** | |
895 * Returns whether this command has a handler, and whether this handler is | |
896 * also handled. | |
897 * | |
898 * @return <code>true</code> if the command is handled; <code>false</code> | |
899 * otherwise. | |
900 */ | |
901 public final bool isHandled() { | |
902 if (handler is null) { | |
903 return false; | |
904 } | |
905 | |
906 return handler.isHandled(); | |
907 } | |
908 | |
909 /** | |
910 * Removes a listener from this command. | |
911 * | |
912 * @param commandListener | |
913 * The listener to be removed; must not be <code>null</code>. | |
914 * | |
915 */ | |
916 public final void removeCommandListener( | |
917 ICommandListener commandListener) { | |
918 if (commandListener is null) { | |
919 throw new NullPointerException( | |
920 "Cannot remove a null command listener"); //$NON-NLS-1$ | |
921 } | |
922 | |
923 removeListenerObject(cast(Object)commandListener); | |
924 } | |
925 | |
926 /** | |
927 * Removes a listener from this command. | |
928 * | |
929 * @param executionListener | |
930 * The listener to be removed; must not be <code>null</code>. | |
931 * | |
932 */ | |
933 public final void removeExecutionListener( | |
934 IExecutionListener executionListener) { | |
935 if (executionListener is null) { | |
936 throw new NullPointerException( | |
937 "Cannot remove a null execution listener"); //$NON-NLS-1$ | |
938 } | |
939 | |
940 if (executionListeners !is null) { | |
941 executionListeners.remove(cast(Object)executionListener); | |
942 if (executionListeners.isEmpty()) { | |
943 executionListeners = null; | |
944 } | |
945 } | |
946 } | |
947 | |
948 /** | |
949 * <p> | |
950 * Removes a state from this command. This will remove the state from the | |
951 * active handler, if the active handler is an instance of | |
952 * {@link IObjectWithState}. | |
953 * </p> | |
954 * | |
955 * @param stateId | |
956 * The identifier of the state to remove; must not be | |
957 * <code>null</code>. | |
958 * @since 3.2 | |
959 */ | |
960 public override void removeState(String stateId) { | |
961 if ( auto h = cast(IObjectWithState)handler ) { | |
962 h.removeState(stateId); | |
963 } | |
964 super.removeState(stateId); | |
965 } | |
966 | |
967 /** | |
968 * Changes the handler for this command. This will remove all the state from | |
969 * the currently active handler (if any), and add it to <code>handler</code>. | |
970 * If debugging is turned on, then this will also print information about | |
971 * the change to <code>System.out</code>. | |
972 * | |
973 * @param handler | |
974 * The new handler; may be <code>null</code> if none. | |
975 * @return <code>true</code> if the handler changed; <code>false</code> | |
976 * otherwise. | |
977 */ | |
978 public final bool setHandler(IHandler handler) { | |
979 if (Util.equals(cast(Object)handler, cast(Object)this.handler)) { | |
980 return false; | |
981 } | |
982 | |
983 // Swap the state around. | |
984 String[] stateIds = getStateIds(); | |
985 if (stateIds !is null) { | |
986 for (int i = 0; i < stateIds.length; i++) { | |
987 String stateId = stateIds[i]; | |
988 if ( auto h = cast(IObjectWithState)this.handler ) { | |
989 h.removeState(stateId); | |
990 } | |
991 if ( auto h = cast(IObjectWithState)handler ) { | |
992 State stateToAdd = getState(stateId); | |
993 h.addState(stateId, stateToAdd); | |
994 } | |
995 } | |
996 } | |
997 | |
998 bool enabled = isEnabled(); | |
999 if (this.handler !is null) { | |
1000 this.handler.removeHandlerListener(getHandlerListener()); | |
1001 } | |
1002 | |
1003 // Update the handler, and flush the string representation. | |
1004 this.handler = handler; | |
1005 if (this.handler !is null) { | |
1006 this.handler.addHandlerListener(getHandlerListener()); | |
1007 } | |
1008 string = null; | |
1009 | |
1010 // Debugging output | |
1011 if ((DEBUG_HANDLERS) | |
1012 && ((DEBUG_HANDLERS_COMMAND_ID is null) || (DEBUG_HANDLERS_COMMAND_ID | |
1013 .equals(id)))) { | |
1014 StringBuffer buffer = new StringBuffer("Command('"); //$NON-NLS-1$ | |
1015 buffer.append(id); | |
1016 buffer.append("') has changed to "); //$NON-NLS-1$ | |
1017 if (handler is null) { | |
1018 buffer.append("no handler"); //$NON-NLS-1$ | |
1019 } else { | |
1020 buffer.append('\''); | |
1021 buffer.append(( cast(Object)handler).toString); | |
1022 buffer.append("' as its handler"); //$NON-NLS-1$ | |
1023 } | |
1024 Tracing.printTrace("HANDLERS", buffer.toString()); //$NON-NLS-1$ | |
1025 } | |
1026 | |
1027 // Send notification | |
1028 fireCommandChanged(new CommandEvent(this, false, false, false, true, | |
1029 false, false, false, false, enabled !is isEnabled())); | |
1030 | |
1031 return true; | |
1032 } | |
1033 | |
1034 /** | |
1035 * @return the handler listener | |
1036 */ | |
1037 private IHandlerListener getHandlerListener() { | |
1038 if (handlerListener is null) { | |
1039 handlerListener = new class IHandlerListener { | |
1040 public void handlerChanged(HandlerEvent handlerEvent) { | |
1041 bool enabledChanged = handlerEvent.isEnabledChanged(); | |
1042 bool handledChanged = handlerEvent.isHandledChanged(); | |
1043 fireCommandChanged(new CommandEvent(this.outer, false, | |
1044 false, false, handledChanged, false, false, false, | |
1045 false, enabledChanged)); | |
1046 } | |
1047 }; | |
1048 } | |
1049 return handlerListener; | |
1050 } | |
1051 | |
1052 /** | |
1053 * The string representation of this command -- for debugging purposes only. | |
1054 * This string should not be shown to an end user. | |
1055 * | |
1056 * @return The string representation; never <code>null</code>. | |
1057 */ | |
1058 public override final String toString() { | |
1059 if (string is null) { | |
1060 String parms; | |
1061 foreach( p; parameters ){ | |
1062 parms ~= "{"~(cast(Object)p).toString~"}"; | |
1063 } | |
1064 string = Format("Command({},{},\n\t\t{},\n\t\t{},\n\t\t{},\n\t\t{},{},{})", | |
1065 id, | |
1066 name is null ? "":name, | |
1067 description is null?"":description, | |
1068 category is null?"":category.toString(), | |
1069 handler is null?"": (cast(Object)handler).toString(), | |
1070 parms, | |
1071 returnType is null?"":returnType.toString(), | |
1072 defined | |
1073 ); | |
1074 } | |
1075 return string; | |
1076 } | |
1077 | |
1078 /** | |
1079 * Makes this command become undefined. This has the side effect of changing | |
1080 * the name and description to <code>null</code>. This also removes all | |
1081 * state and disposes of it. Notification is sent to all listeners. | |
1082 */ | |
1083 public override final void undefine() { | |
1084 bool enabledChanged = isEnabled(); | |
1085 | |
1086 string = null; | |
1087 | |
1088 bool definedChanged = defined; | |
1089 defined = false; | |
1090 | |
1091 bool nameChanged = name !is null; | |
1092 name = null; | |
1093 | |
1094 bool descriptionChanged = description !is null; | |
1095 description = null; | |
1096 | |
1097 bool categoryChanged = category !is null; | |
1098 category = null; | |
1099 | |
1100 bool parametersChanged = parameters !is null; | |
1101 parameters = null; | |
1102 | |
1103 bool returnTypeChanged = returnType !is null; | |
1104 returnType = null; | |
1105 | |
1106 String[] stateIds = getStateIds(); | |
1107 if (stateIds !is null) { | |
1108 if ( auto handlerWithState = cast(IObjectWithState)handler ) { | |
1109 for (int i = 0; i < stateIds.length; i++) { | |
1110 String stateId = stateIds[i]; | |
1111 handlerWithState.removeState(stateId); | |
1112 | |
1113 State state = getState(stateId); | |
1114 removeState(stateId); | |
1115 state.dispose(); | |
1116 } | |
1117 } else { | |
1118 for (int i = 0; i < stateIds.length; i++) { | |
1119 String stateId = stateIds[i]; | |
1120 State state = getState(stateId); | |
1121 removeState(stateId); | |
1122 state.dispose(); | |
1123 } | |
1124 } | |
1125 } | |
1126 | |
1127 fireCommandChanged(new CommandEvent(this, categoryChanged, | |
1128 definedChanged, descriptionChanged, false, nameChanged, | |
1129 parametersChanged, returnTypeChanged, false, enabledChanged)); | |
1130 } | |
1131 } |