Mercurial > projects > dwt2
comparison org.eclipse.core.commands/src/org/eclipse/core/commands/CommandManager.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 |
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.CommandManager; | |
14 | |
15 import org.eclipse.core.commands.common.HandleObjectManager; | |
16 import org.eclipse.core.commands.common.NotDefinedException; | |
17 import org.eclipse.core.runtime.ListenerList; | |
18 | |
19 import org.eclipse.core.commands.ICategoryListener; | |
20 import org.eclipse.core.commands.ICommandListener; | |
21 import org.eclipse.core.commands.IExecutionListener; | |
22 import org.eclipse.core.commands.IExecutionListenerWithChecks; | |
23 import org.eclipse.core.commands.IParameterTypeListener; | |
24 import org.eclipse.core.commands.ICommandManagerListener; | |
25 import org.eclipse.core.commands.CommandEvent; | |
26 import org.eclipse.core.commands.CommandManagerEvent; | |
27 import org.eclipse.core.commands.Command; | |
28 import org.eclipse.core.commands.Category; | |
29 import org.eclipse.core.commands.CategoryEvent; | |
30 import org.eclipse.core.commands.IHandler; | |
31 import org.eclipse.core.commands.ParameterType; | |
32 import org.eclipse.core.commands.IParameter; | |
33 import org.eclipse.core.commands.Parameterization; | |
34 import org.eclipse.core.commands.ParameterizedCommand; | |
35 import org.eclipse.core.commands.ParameterTypeEvent; | |
36 import org.eclipse.core.commands.SerializationException; | |
37 | |
38 import org.eclipse.core.commands.NotEnabledException; | |
39 import org.eclipse.core.commands.NotHandledException; | |
40 import org.eclipse.core.commands.ExecutionException; | |
41 import org.eclipse.core.commands.ExecutionEvent; | |
42 | |
43 import java.lang.all; | |
44 | |
45 import java.util.WeakHashMap; | |
46 import java.util.HashMap; | |
47 import java.util.Map; | |
48 import java.util.Iterator; | |
49 import java.util.Collections; | |
50 import java.util.ArrayList; | |
51 import java.util.Set; | |
52 import java.util.HashSet; | |
53 | |
54 /** | |
55 * <p> | |
56 * A central repository for commands -- both in the defined and undefined | |
57 * states. Commands can be created and retrieved using this manager. It is | |
58 * possible to listen to changes in the collection of commands by attaching a | |
59 * listener to the manager. | |
60 * </p> | |
61 * | |
62 * @see CommandManager#getCommand(String) | |
63 * @since 3.1 | |
64 */ | |
65 public final class CommandManager : HandleObjectManager, | |
66 ICategoryListener, ICommandListener, IParameterTypeListener { | |
67 | |
68 /** | |
69 * A listener that forwards incoming execution events to execution listeners | |
70 * on this manager. The execution events will come from any command on this | |
71 * manager. | |
72 * | |
73 * @since 3.1 | |
74 */ | |
75 private final class ExecutionListener : | |
76 IExecutionListenerWithChecks { | |
77 | |
78 public void notDefined(String commandId, NotDefinedException exception) { | |
79 if (executionListeners !is null) { | |
80 Object[] listeners = executionListeners.getListeners(); | |
81 for (int i = 0; i < listeners.length; i++) { | |
82 Object object = listeners[i]; | |
83 if ( auto listener = cast(IExecutionListenerWithChecks)object ) { | |
84 listener.notDefined(commandId, exception); | |
85 } | |
86 } | |
87 } | |
88 } | |
89 | |
90 public void notEnabled(String commandId, NotEnabledException exception) { | |
91 if (executionListeners !is null) { | |
92 Object[] listeners = executionListeners.getListeners(); | |
93 for (int i = 0; i < listeners.length; i++) { | |
94 Object object = listeners[i]; | |
95 if ( auto listener = cast(IExecutionListenerWithChecks)object ) { | |
96 listener.notEnabled(commandId, exception); | |
97 } | |
98 } | |
99 } | |
100 } | |
101 | |
102 public final void notHandled(String commandId, | |
103 NotHandledException exception) { | |
104 if (executionListeners !is null) { | |
105 Object[] listeners = executionListeners.getListeners(); | |
106 for (int i = 0; i < listeners.length; i++) { | |
107 Object object = listeners[i]; | |
108 if ( auto listener = cast(IExecutionListener)object ) { | |
109 listener.notHandled(commandId, exception); | |
110 } | |
111 } | |
112 } | |
113 } | |
114 | |
115 public final void postExecuteFailure(String commandId, | |
116 ExecutionException exception) { | |
117 if (executionListeners !is null) { | |
118 Object[] listeners = executionListeners.getListeners(); | |
119 for (int i = 0; i < listeners.length; i++) { | |
120 Object object = listeners[i]; | |
121 if ( auto listener = cast(IExecutionListener)object ) { | |
122 listener.postExecuteFailure(commandId, exception); | |
123 } | |
124 } | |
125 } | |
126 } | |
127 | |
128 public final void postExecuteSuccess(String commandId, | |
129 Object returnValue) { | |
130 if (executionListeners !is null) { | |
131 Object[] listeners = executionListeners.getListeners(); | |
132 for (int i = 0; i < listeners.length; i++) { | |
133 Object object = listeners[i]; | |
134 if ( auto listener = cast(IExecutionListener)object ) { | |
135 listener.postExecuteSuccess(commandId, returnValue); | |
136 } | |
137 } | |
138 } | |
139 } | |
140 | |
141 public final void preExecute(String commandId, | |
142 ExecutionEvent event) { | |
143 if (executionListeners !is null) { | |
144 Object[] listeners = executionListeners.getListeners(); | |
145 for (int i = 0; i < listeners.length; i++) { | |
146 Object object = listeners[i]; | |
147 if ( auto listener = cast(IExecutionListener)object ) { | |
148 listener.preExecute(commandId, event); | |
149 } | |
150 } | |
151 } | |
152 } | |
153 } | |
154 | |
155 /** | |
156 * The identifier of the category in which all auto-generated commands will | |
157 * appear. This value must never be <code>null</code>. | |
158 * | |
159 * @since 3.2 | |
160 */ | |
161 public static const String AUTOGENERATED_CATEGORY_ID = "org.eclipse.core.commands.categories.autogenerated"; //$NON-NLS-1$ | |
162 | |
163 /** | |
164 * The escape character to use for serialization and deserialization of | |
165 * parameterized commands. | |
166 */ | |
167 static const char ESCAPE_CHAR = '%'; | |
168 | |
169 /** | |
170 * The character that separates a parameter id from its value. | |
171 */ | |
172 static const char ID_VALUE_CHAR = '='; | |
173 | |
174 /** | |
175 * The character that indicates the end of a list of parameters. | |
176 */ | |
177 static const char PARAMETER_END_CHAR = ')'; | |
178 | |
179 /** | |
180 * The character that separators parameters from each other. | |
181 */ | |
182 static const char PARAMETER_SEPARATOR_CHAR = ','; | |
183 | |
184 /** | |
185 * The character that indicates the start of a list of parameters. | |
186 */ | |
187 static const char PARAMETER_START_CHAR = '('; | |
188 | |
189 this(){ | |
190 categoriesById = new HashMap(); | |
191 definedCategoryIds = new HashSet(); | |
192 definedParameterTypeIds = new HashSet(); | |
193 helpContextIdsByHandler = new WeakHashMap(); | |
194 parameterTypesById = new HashMap(); | |
195 } | |
196 | |
197 /** | |
198 * Unescapes special characters in the command id, parameter ids and | |
199 * parameter values for {@link #deserialize(String)}. The special characters | |
200 * {@link #PARAMETER_START_CHAR}, {@link #PARAMETER_END_CHAR}, | |
201 * {@link #ID_VALUE_CHAR}, {@link #PARAMETER_SEPARATOR_CHAR} and | |
202 * {@link #ESCAPE_CHAR} are escaped by prepending an {@link #ESCAPE_CHAR} | |
203 * character. | |
204 * <p> | |
205 * See also ParameterizedCommand.escape(String) | |
206 * </p> | |
207 * | |
208 * @param escapedText | |
209 * a <code>String</code> that may contain escaped special | |
210 * characters for command serialization. | |
211 * @return a <code>String</code> representing <code>escapedText</code> | |
212 * with any escaped characters replaced by their literal values | |
213 * @throws SerializationException | |
214 * if <code>escapedText</code> contains an invalid escape | |
215 * sequence | |
216 * @since 3.2 | |
217 */ | |
218 private static final String unescape(String escapedText) { | |
219 | |
220 // defer initialization of a StringBuffer until we know we need one | |
221 StringBuffer buffer; | |
222 | |
223 for (int i = 0; i < escapedText.length; i++) { | |
224 | |
225 char c = escapedText.charAt(i); | |
226 if (c !is ESCAPE_CHAR) { | |
227 // normal unescaped character | |
228 if (buffer !is null) { | |
229 buffer.append(c); | |
230 } | |
231 } else { | |
232 if (buffer is null) { | |
233 buffer = new StringBuffer(escapedText.substring(0, i)); | |
234 } | |
235 | |
236 if (++i < escapedText.length) { | |
237 c = escapedText.charAt(i); | |
238 switch (c) { | |
239 case PARAMETER_START_CHAR: | |
240 case PARAMETER_END_CHAR: | |
241 case ID_VALUE_CHAR: | |
242 case PARAMETER_SEPARATOR_CHAR: | |
243 case ESCAPE_CHAR: | |
244 buffer.append(c); | |
245 break; | |
246 default: | |
247 throw new SerializationException( | |
248 "Invalid character '" ~ c ~ "' in escape sequence"); //$NON-NLS-1$ //$NON-NLS-2$ | |
249 } | |
250 } else { | |
251 throw new SerializationException( | |
252 "Unexpected termination of escape sequence"); //$NON-NLS-1$ | |
253 } | |
254 } | |
255 | |
256 } | |
257 | |
258 if (buffer is null) { | |
259 return escapedText; | |
260 } | |
261 | |
262 return buffer.toString(); | |
263 } | |
264 | |
265 /** | |
266 * The map of category identifiers (<code>String</code>) to categories ( | |
267 * <code>Category</code>). This collection may be empty, but it is never | |
268 * <code>null</code>. | |
269 */ | |
270 private const Map categoriesById; | |
271 | |
272 /** | |
273 * The set of identifiers for those categories that are defined. This value | |
274 * may be empty, but it is never <code>null</code>. | |
275 */ | |
276 private const Set definedCategoryIds; | |
277 | |
278 /** | |
279 * The set of identifiers for those command parameter types that are | |
280 * defined. This value may be empty, but it is never <code>null</code>. | |
281 * | |
282 * @since 3.2 | |
283 */ | |
284 private const Set definedParameterTypeIds; | |
285 | |
286 /** | |
287 * The execution listener for this command manager. This just forwards | |
288 * events from commands controlled by this manager to listeners on this | |
289 * manager. | |
290 */ | |
291 private IExecutionListenerWithChecks executionListener = null; | |
292 | |
293 /** | |
294 * The collection of execution listeners. This collection is | |
295 * <code>null</code> if there are no listeners. | |
296 */ | |
297 private ListenerList executionListeners = null; | |
298 | |
299 /** | |
300 * The help context identifiers ({@link String}) for a handler ({@link IHandler}). | |
301 * This map may be empty, but it is never <code>null</code>. Entries are | |
302 * removed if all strong references to the handler are removed. | |
303 * | |
304 * @since 3.2 | |
305 */ | |
306 private const WeakHashMap helpContextIdsByHandler; | |
307 | |
308 /** | |
309 * The map of parameter type identifiers (<code>String</code>) to | |
310 * parameter types ( <code>ParameterType</code>). This collection may be | |
311 * empty, but it is never <code>null</code>. | |
312 * | |
313 * @since 3.2 | |
314 */ | |
315 private const Map parameterTypesById; | |
316 | |
317 /** | |
318 * Adds a listener to this command manager. The listener will be notified | |
319 * when the set of defined commands changes. This can be used to track the | |
320 * global appearance and disappearance of commands. | |
321 * | |
322 * @param listener | |
323 * The listener to attach; must not be <code>null</code>. | |
324 */ | |
325 public final void addCommandManagerListener( | |
326 ICommandManagerListener listener) { | |
327 addListenerObject(cast(Object)listener); | |
328 } | |
329 | |
330 /** | |
331 * Adds an execution listener to this manager. This listener will be | |
332 * notified if any of the commands controlled by this manager execute. This | |
333 * can be used to support macros and instrumentation of commands. | |
334 * | |
335 * @param listener | |
336 * The listener to attach; must not be <code>null</code>. | |
337 */ | |
338 public final void addExecutionListener(IExecutionListener listener) { | |
339 if (listener is null) { | |
340 throw new NullPointerException( | |
341 "Cannot add a null execution listener"); //$NON-NLS-1$ | |
342 } | |
343 | |
344 if (executionListeners is null) { | |
345 executionListeners = new ListenerList(ListenerList.IDENTITY); | |
346 | |
347 // Add an execution listener to every command. | |
348 executionListener = new ExecutionListener(); | |
349 Iterator commandItr = handleObjectsById.values().iterator(); | |
350 while (commandItr.hasNext()) { | |
351 Command command = cast(Command) commandItr.next(); | |
352 command.addExecutionListener(executionListener); | |
353 } | |
354 | |
355 } | |
356 | |
357 executionListeners.add(cast(Object)listener); | |
358 } | |
359 | |
360 /* | |
361 * (non-Javadoc) | |
362 * | |
363 * @see org.eclipse.core.commands.ICategoryListener#categoryChanged(org.eclipse.core.commands.CategoryEvent) | |
364 */ | |
365 public final void categoryChanged(CategoryEvent categoryEvent) { | |
366 if (categoryEvent.isDefinedChanged()) { | |
367 Category category = categoryEvent.getCategory(); | |
368 String categoryId = category.getId(); | |
369 bool categoryIdAdded = category.isDefined(); | |
370 if (categoryIdAdded) { | |
371 definedCategoryIds.add(categoryId); | |
372 } else { | |
373 definedCategoryIds.remove(categoryId); | |
374 } | |
375 if (isListenerAttached()) { | |
376 fireCommandManagerChanged(new CommandManagerEvent(this, null, | |
377 false, false, categoryId, categoryIdAdded, true)); | |
378 } | |
379 } | |
380 } | |
381 | |
382 /* | |
383 * (non-Javadoc) | |
384 * | |
385 * @see org.eclipse.commands.ICommandListener#commandChanged(org.eclipse.commands.CommandEvent) | |
386 */ | |
387 public final void commandChanged(CommandEvent commandEvent) { | |
388 if (commandEvent.isDefinedChanged()) { | |
389 Command command = commandEvent.getCommand(); | |
390 String commandId = command.getId(); | |
391 bool commandIdAdded = command.isDefined(); | |
392 if (commandIdAdded) { | |
393 definedHandleObjects.add(command); | |
394 } else { | |
395 definedHandleObjects.remove(command); | |
396 } | |
397 if (isListenerAttached()) { | |
398 fireCommandManagerChanged(new CommandManagerEvent(this, | |
399 commandId, commandIdAdded, true, null, false, false)); | |
400 } | |
401 } | |
402 } | |
403 | |
404 /** | |
405 * Sets the name and description of the category for uncategorized commands. | |
406 * This is the category that will be returned if | |
407 * {@link #getCategory(String)} is called with <code>null</code>. | |
408 * | |
409 * @param name | |
410 * The name of the category for uncategorized commands; must not | |
411 * be <code>null</code>. | |
412 * @param description | |
413 * The description of the category for uncategorized commands; | |
414 * may be <code>null</code>. | |
415 * @since 3.2 | |
416 */ | |
417 public final void defineUncategorizedCategory(String name, | |
418 String description) { | |
419 Category category = getCategory(AUTOGENERATED_CATEGORY_ID); | |
420 category.define(name, description); | |
421 } | |
422 | |
423 /** | |
424 * <p> | |
425 * Returns a {@link ParameterizedCommand} with a command and | |
426 * parameterizations as specified in the provided | |
427 * <code>serializedParameterizedCommand</code> string. The | |
428 * <code>serializedParameterizedCommand</code> must use the format | |
429 * returned by {@link ParameterizedCommand#serialize()} and described in the | |
430 * Javadoc for that method. | |
431 * </p> | |
432 * <p> | |
433 * If a parameter id encoded in the | |
434 * <code>serializedParameterizedCommand</code> does not exist in the | |
435 * encoded command, that parameter id and value are ignored. A given | |
436 * parameter id should not be used more than once in | |
437 * <code>serializedParameterizedCommand</code>. This will not result in | |
438 * an exception, but in this case the value of the parameter when the | |
439 * command is executed is unspecified. | |
440 * </p> | |
441 * <p> | |
442 * This method will never return <code>null</code>, however it may throw | |
443 * an exception if there is a problem processing the serialization string or | |
444 * the encoded command is undefined. | |
445 * </p> | |
446 * | |
447 * @param serializedParameterizedCommand | |
448 * a string representing a command id and parameter ids and | |
449 * values; must not be <code>null</code> | |
450 * @return a {@link ParameterizedCommand} with the command and | |
451 * parameterizations encoded in the | |
452 * <code>serializedParameterizedCommand</code>; never | |
453 * <code>null</code>. | |
454 * @throws NotDefinedException | |
455 * if the command indicated in | |
456 * <code>serializedParameterizedCommand</code> is not defined | |
457 * @throws SerializationException | |
458 * if there is an error deserializing | |
459 * <code>serializedParameterizedCommand</code> | |
460 * @see ParameterizedCommand#serialize() | |
461 * @since 3.2 | |
462 */ | |
463 public final ParameterizedCommand deserialize( | |
464 String serializedParameterizedCommand) { | |
465 | |
466 int lparenPosition = unescapedIndexOf( | |
467 serializedParameterizedCommand, PARAMETER_START_CHAR); | |
468 | |
469 String commandIdEscaped; | |
470 String serializedParameters; | |
471 if (lparenPosition is -1) { | |
472 commandIdEscaped = serializedParameterizedCommand; | |
473 serializedParameters = null; | |
474 } else { | |
475 commandIdEscaped = serializedParameterizedCommand.substring(0, | |
476 lparenPosition); | |
477 | |
478 if (serializedParameterizedCommand | |
479 .charAt(serializedParameterizedCommand.length - 1) !is PARAMETER_END_CHAR) { | |
480 throw new SerializationException( | |
481 "Parentheses must be balanced in serialized ParameterizedCommand"); //$NON-NLS-1$ | |
482 } | |
483 | |
484 serializedParameters = serializedParameterizedCommand.substring( | |
485 lparenPosition + 1, // skip PARAMETER_START_CHAR | |
486 serializedParameterizedCommand.length - 1); // skip | |
487 // PARAMETER_END_CHAR | |
488 } | |
489 | |
490 String commandId = unescape(commandIdEscaped); | |
491 Command command = getCommand(commandId); | |
492 IParameter[] parameters = command.getParameters(); | |
493 Parameterization[] parameterizations = getParameterizations( | |
494 serializedParameters, parameters); | |
495 | |
496 return new ParameterizedCommand(command, parameterizations); | |
497 } | |
498 | |
499 /** | |
500 * Notifies all of the listeners to this manager that the set of defined | |
501 * command identifiers has changed. | |
502 * | |
503 * @param event | |
504 * The event to send to all of the listeners; must not be | |
505 * <code>null</code>. | |
506 */ | |
507 private final void fireCommandManagerChanged(CommandManagerEvent event) { | |
508 if (event is null) { | |
509 throw new NullPointerException(); | |
510 } | |
511 | |
512 Object[] listeners = getListeners(); | |
513 for (int i = 0; i < listeners.length; i++) { | |
514 ICommandManagerListener listener = cast(ICommandManagerListener) listeners[i]; | |
515 listener.commandManagerChanged(event); | |
516 } | |
517 } | |
518 | |
519 /** | |
520 * Returns all of the commands known by this manager -- defined and | |
521 * undefined. | |
522 * | |
523 * @return All of the commands; may be empty, but never <code>null</code>. | |
524 * @since 3.2 | |
525 */ | |
526 public final Command[] getAllCommands() { | |
527 return arraycast!(Command)( handleObjectsById.values().toArray()); | |
528 } | |
529 | |
530 /** | |
531 * Gets the category with the given identifier. If no such category | |
532 * currently exists, then the category will be created (but be undefined). | |
533 * | |
534 * @param categoryId | |
535 * The identifier to find; must not be <code>null</code>. If | |
536 * the category is <code>null</code>, then a category suitable | |
537 * for uncategorized items is defined and returned. | |
538 * @return The category with the given identifier; this value will never be | |
539 * <code>null</code>, but it might be undefined. | |
540 * @see Category | |
541 */ | |
542 public final Category getCategory(String categoryId) { | |
543 if (categoryId is null) { | |
544 return getCategory(AUTOGENERATED_CATEGORY_ID); | |
545 } | |
546 | |
547 checkId(categoryId); | |
548 | |
549 Category category = cast(Category) categoriesById.get(categoryId); | |
550 if (category is null) { | |
551 category = new Category(categoryId); | |
552 categoriesById.put(categoryId, category); | |
553 category.addCategoryListener(this); | |
554 } | |
555 | |
556 return category; | |
557 } | |
558 | |
559 /** | |
560 * Gets the command with the given identifier. If no such command currently | |
561 * exists, then the command will be created (but will be undefined). | |
562 * | |
563 * @param commandId | |
564 * The identifier to find; must not be <code>null</code> and | |
565 * must not be zero-length. | |
566 * @return The command with the given identifier; this value will never be | |
567 * <code>null</code>, but it might be undefined. | |
568 * @see Command | |
569 */ | |
570 public final Command getCommand(String commandId) { | |
571 checkId(commandId); | |
572 | |
573 Command command = cast(Command) handleObjectsById.get(commandId); | |
574 if (command is null) { | |
575 command = new Command(commandId); | |
576 handleObjectsById.put(commandId, command); | |
577 command.addCommandListener(this); | |
578 | |
579 if (executionListener !is null) { | |
580 command.addExecutionListener(executionListener); | |
581 } | |
582 } | |
583 | |
584 return command; | |
585 } | |
586 | |
587 /** | |
588 * Returns the categories that are defined. | |
589 * | |
590 * @return The defined categories; this value may be empty, but it is never | |
591 * <code>null</code>. | |
592 * @since 3.2 | |
593 */ | |
594 public final Category[] getDefinedCategories() { | |
595 Category[] categories = new Category[definedCategoryIds.size()]; | |
596 Iterator categoryIdItr = definedCategoryIds.iterator(); | |
597 int i = 0; | |
598 while (categoryIdItr.hasNext()) { | |
599 String categoryId = stringcast( categoryIdItr.next()); | |
600 categories[i++] = getCategory(categoryId); | |
601 } | |
602 return categories; | |
603 } | |
604 | |
605 /** | |
606 * Returns the set of identifiers for those category that are defined. | |
607 * | |
608 * @return The set of defined category identifiers; this value may be empty, | |
609 * but it is never <code>null</code>. | |
610 */ | |
611 public final Set getDefinedCategoryIds() { | |
612 return Collections.unmodifiableSet(definedCategoryIds); | |
613 } | |
614 | |
615 /** | |
616 * Returns the set of identifiers for those commands that are defined. | |
617 * | |
618 * @return The set of defined command identifiers; this value may be empty, | |
619 * but it is never <code>null</code>. | |
620 */ | |
621 public final Set getDefinedCommandIds() { | |
622 return getDefinedHandleObjectIds(); | |
623 } | |
624 | |
625 /** | |
626 * Returns the commands that are defined. | |
627 * | |
628 * @return The defined commands; this value may be empty, but it is never | |
629 * <code>null</code>. | |
630 * @since 3.2 | |
631 */ | |
632 public final Command[] getDefinedCommands() { | |
633 return arraycast!(Command)( definedHandleObjects | |
634 .toArray()); | |
635 } | |
636 | |
637 /** | |
638 * Returns the set of identifiers for those parameter types that are | |
639 * defined. | |
640 * | |
641 * @return The set of defined command parameter type identifiers; this value | |
642 * may be empty, but it is never <code>null</code>. | |
643 * @since 3.2 | |
644 */ | |
645 public final Set getDefinedParameterTypeIds() { | |
646 return Collections.unmodifiableSet(definedParameterTypeIds); | |
647 } | |
648 | |
649 /** | |
650 * Returns the command parameter types that are defined. | |
651 * | |
652 * @return The defined command parameter types; this value may be empty, but | |
653 * it is never <code>null</code>. | |
654 * @since 3.2 | |
655 */ | |
656 public final ParameterType[] getDefinedParameterTypes() { | |
657 ParameterType[] parameterTypes = new ParameterType[definedParameterTypeIds | |
658 .size()]; | |
659 Iterator iterator = definedParameterTypeIds.iterator(); | |
660 int i = 0; | |
661 while (iterator.hasNext()) { | |
662 String parameterTypeId = stringcast( iterator.next()); | |
663 parameterTypes[i++] = getParameterType(parameterTypeId); | |
664 } | |
665 return parameterTypes; | |
666 } | |
667 | |
668 /** | |
669 * Gets the help context identifier for a particular command. The command's | |
670 * handler is first checked for a help context identifier. If the handler | |
671 * does not have a help context identifier, then the help context identifier | |
672 * for the command is returned. If neither has a help context identifier, | |
673 * then <code>null</code> is returned. | |
674 * | |
675 * @param command | |
676 * The command for which the help context should be retrieved; | |
677 * must not be <code>null</code>. | |
678 * @return The help context identifier to use for the given command; may be | |
679 * <code>null</code>. | |
680 * @throws NotDefinedException | |
681 * If the given command is not defined. | |
682 * @since 3.2 | |
683 */ | |
684 public final String getHelpContextId(Command command) { | |
685 // Check if the command is defined. | |
686 if (!command.isDefined()) { | |
687 throw new NotDefinedException("The command is not defined. " //$NON-NLS-1$ | |
688 ~ command.getId()); | |
689 } | |
690 | |
691 // Check the handler. | |
692 IHandler handler = command.getHandler(); | |
693 if (handler !is null) { | |
694 String helpContextId = stringcast( helpContextIdsByHandler.get( cast(Object) handler) ); | |
695 if (helpContextId !is null) { | |
696 return helpContextId; | |
697 } | |
698 } | |
699 | |
700 // Simply return whatever the command has as a help context identifier. | |
701 return command.getHelpContextId(); | |
702 } | |
703 | |
704 /** | |
705 * Returns an array of parameterizations for the provided command by | |
706 * deriving the parameter ids and values from the provided | |
707 * <code>serializedParameters</code> string. | |
708 * | |
709 * @param serializedParameters | |
710 * a String encoding parameter ids and values; must not be | |
711 * <code>null</code>. | |
712 * @param parameters | |
713 * array of parameters of the command being deserialized; may be | |
714 * <code>null</code>. | |
715 * @return an array of parameterizations; may be <code>null</code>. | |
716 * @throws SerializationException | |
717 * if there is an error deserializing the parameters | |
718 * @since 3.2 | |
719 */ | |
720 private final Parameterization[] getParameterizations( | |
721 String serializedParameters, IParameter[] parameters) { | |
722 | |
723 if (serializedParameters is null | |
724 || (serializedParameters.length is 0)) { | |
725 return null; | |
726 } | |
727 | |
728 if ((parameters is null) || (parameters.length is 0)) { | |
729 return null; | |
730 } | |
731 | |
732 ArrayList paramList = new ArrayList(); | |
733 | |
734 int commaPosition; // split off each param by looking for ',' | |
735 do { | |
736 commaPosition = unescapedIndexOf(serializedParameters, ','); | |
737 | |
738 String idEqualsValue; | |
739 if (commaPosition is -1) { | |
740 // no more parameters after this | |
741 idEqualsValue = serializedParameters; | |
742 } else { | |
743 // take the first parameter... | |
744 idEqualsValue = serializedParameters | |
745 .substring(0, commaPosition); | |
746 | |
747 // ... and put the rest back into serializedParameters | |
748 serializedParameters = serializedParameters | |
749 .substring(commaPosition + 1); | |
750 } | |
751 | |
752 int equalsPosition = unescapedIndexOf(idEqualsValue, '='); | |
753 | |
754 String parameterId; | |
755 String parameterValue; | |
756 if (equalsPosition is -1) { | |
757 // missing values are null | |
758 parameterId = unescape(idEqualsValue); | |
759 parameterValue = null; | |
760 } else { | |
761 parameterId = unescape(idEqualsValue.substring(0, | |
762 equalsPosition)); | |
763 parameterValue = unescape(idEqualsValue | |
764 .substring(equalsPosition + 1)); | |
765 } | |
766 | |
767 for (int i = 0; i < parameters.length; i++) { | |
768 IParameter parameter = parameters[i]; | |
769 if (parameter.getId().equals(parameterId)) { | |
770 paramList.add(new Parameterization(parameter, | |
771 parameterValue)); | |
772 break; | |
773 } | |
774 } | |
775 | |
776 } while (commaPosition !is -1); | |
777 | |
778 return arraycast!(Parameterization)( paramList | |
779 .toArray()); | |
780 } | |
781 | |
782 /** | |
783 * Gets the command {@link ParameterType} with the given identifier. If no | |
784 * such command parameter type currently exists, then the command parameter | |
785 * type will be created (but will be undefined). | |
786 * | |
787 * @param parameterTypeId | |
788 * The identifier to find; must not be <code>null</code> and | |
789 * must not be zero-length. | |
790 * @return The {@link ParameterType} with the given identifier; this value | |
791 * will never be <code>null</code>, but it might be undefined. | |
792 * @since 3.2 | |
793 */ | |
794 public final ParameterType getParameterType(String parameterTypeId) { | |
795 checkId(parameterTypeId); | |
796 | |
797 ParameterType parameterType = cast(ParameterType) parameterTypesById | |
798 .get(parameterTypeId); | |
799 if (parameterType is null) { | |
800 parameterType = new ParameterType(parameterTypeId); | |
801 parameterTypesById.put(parameterTypeId, parameterType); | |
802 parameterType.addListener(this); | |
803 } | |
804 | |
805 return parameterType; | |
806 } | |
807 | |
808 /** | |
809 * {@inheritDoc} | |
810 * | |
811 * @since 3.2 | |
812 */ | |
813 public final void parameterTypeChanged( | |
814 ParameterTypeEvent parameterTypeEvent) { | |
815 if (parameterTypeEvent.isDefinedChanged()) { | |
816 ParameterType parameterType = parameterTypeEvent | |
817 .getParameterType(); | |
818 String parameterTypeId = parameterType.getId(); | |
819 bool parameterTypeIdAdded = parameterType.isDefined(); | |
820 if (parameterTypeIdAdded) { | |
821 definedParameterTypeIds.add(parameterTypeId); | |
822 } else { | |
823 definedParameterTypeIds.remove(parameterTypeId); | |
824 } | |
825 | |
826 fireCommandManagerChanged(new CommandManagerEvent(this, | |
827 parameterTypeId, parameterTypeIdAdded, true)); | |
828 } | |
829 } | |
830 | |
831 /** | |
832 * Removes a listener from this command manager. | |
833 * | |
834 * @param listener | |
835 * The listener to be removed; must not be <code>null</code>. | |
836 */ | |
837 public final void removeCommandManagerListener( | |
838 ICommandManagerListener listener) { | |
839 removeListenerObject(cast(Object)listener); | |
840 } | |
841 | |
842 /** | |
843 * Removes an execution listener from this command manager. | |
844 * | |
845 * @param listener | |
846 * The listener to be removed; must not be <code>null</code>. | |
847 */ | |
848 public final void removeExecutionListener(IExecutionListener listener) { | |
849 if (listener is null) { | |
850 throw new NullPointerException("Cannot remove a null listener"); //$NON-NLS-1$ | |
851 } | |
852 | |
853 if (executionListeners is null) { | |
854 return; | |
855 } | |
856 | |
857 executionListeners.remove(cast(Object)listener); | |
858 | |
859 if (executionListeners.isEmpty()) { | |
860 executionListeners = null; | |
861 | |
862 // Remove the execution listener to every command. | |
863 Iterator commandItr = handleObjectsById.values().iterator(); | |
864 while (commandItr.hasNext()) { | |
865 Command command = cast(Command) commandItr.next(); | |
866 command.removeExecutionListener(executionListener); | |
867 } | |
868 executionListener = null; | |
869 | |
870 } | |
871 } | |
872 | |
873 /** | |
874 * Block updates all of the handlers for all of the commands. If the handler | |
875 * is <code>null</code> or the command id does not exist in the map, then | |
876 * the command becomes unhandled. Otherwise, the handler is set to the | |
877 * corresponding value in the map. | |
878 * | |
879 * @param handlersByCommandId | |
880 * A map of command identifiers (<code>String</code>) to | |
881 * handlers (<code>IHandler</code>). This map may be | |
882 * <code>null</code> if all handlers should be cleared. | |
883 * Similarly, if the map is empty, then all commands will become | |
884 * unhandled. | |
885 */ | |
886 public final void setHandlersByCommandId(Map handlersByCommandId) { | |
887 // Make that all the reference commands are created. | |
888 Iterator commandIdItr = handlersByCommandId.keySet().iterator(); | |
889 while (commandIdItr.hasNext()) { | |
890 getCommand(stringcast(commandIdItr.next())); | |
891 } | |
892 | |
893 // Now, set-up the handlers on all of the existing commands. | |
894 Iterator commandItr = handleObjectsById.values().iterator(); | |
895 while (commandItr.hasNext()) { | |
896 Command command = cast(Command) commandItr.next(); | |
897 String commandId = command.getId(); | |
898 Object value = handlersByCommandId.get(commandId); | |
899 if ( cast(IHandler)value ) { | |
900 command.setHandler(cast(IHandler) value); | |
901 } else { | |
902 command.setHandler(null); | |
903 } | |
904 } | |
905 } | |
906 | |
907 /** | |
908 * Sets the help context identifier to associate with a particular handler. | |
909 * | |
910 * @param handler | |
911 * The handler with which to register a help context identifier; | |
912 * must not be <code>null</code>. | |
913 * @param helpContextId | |
914 * The help context identifier to register; may be | |
915 * <code>null</code> if the help context identifier should be | |
916 * removed. | |
917 * @since 3.2 | |
918 */ | |
919 public final void setHelpContextId(IHandler handler, | |
920 String helpContextId) { | |
921 if (handler is null) { | |
922 throw new NullPointerException("The handler cannot be null"); //$NON-NLS-1$ | |
923 } | |
924 if (helpContextId is null) { | |
925 helpContextIdsByHandler.remove(cast(Object) handler); | |
926 } else { | |
927 helpContextIdsByHandler.put(cast(Object) handler, stringcast(helpContextId)); | |
928 } | |
929 } | |
930 | |
931 /** | |
932 * Searches for the index of a <code>char</code> in a <code>String</code> | |
933 * but disregards characters prefixed with the {@link #ESCAPE_CHAR} escape | |
934 * character. This is used by {@link #deserialize(String)} and | |
935 * {@link #getParameterizations(String, IParameter[])} to parse the | |
936 * serialized parameterized command string. | |
937 * | |
938 * @param escapedText | |
939 * the string to search for the index of <code>ch</code> in | |
940 * @param ch | |
941 * a character to search for in <code>escapedText</code> | |
942 * @return the index of the first unescaped occurrence of the character in | |
943 * <code>escapedText</code>, or <code>-1</code> if the | |
944 * character does not occur unescaped. | |
945 * @see String#indexOf(int) | |
946 */ | |
947 private final int unescapedIndexOf(String escapedText, char ch) { | |
948 | |
949 int pos = escapedText.indexOf(ch); | |
950 | |
951 // first char can't be escaped | |
952 if (pos is 0) { | |
953 return pos; | |
954 } | |
955 | |
956 while (pos !is -1) { | |
957 // look back for the escape character | |
958 if (escapedText.charAt(pos - 1) !is ESCAPE_CHAR) { | |
959 return pos; | |
960 } | |
961 | |
962 // scan for the next instance of ch | |
963 pos = escapedText.indexOf(ch, pos + 1); | |
964 } | |
965 | |
966 return pos; | |
967 | |
968 } | |
969 /** | |
970 * Fires the <code>notEnabled</code> event for | |
971 * <code>executionListeners</code>. | |
972 * <p> | |
973 * <b>Note:</b> This supports bridging actions to the command framework, | |
974 * and should not be used outside the framework. | |
975 * </p> | |
976 * | |
977 * @param commandId | |
978 * The command id of the command about to execute, never | |
979 * <code>null</code>. | |
980 * @param exception | |
981 * The exception, never <code>null</code>. | |
982 * @since 3.4 | |
983 */ | |
984 public void fireNotEnabled(String commandId, NotEnabledException exception) { | |
985 if (executionListener !is null) { | |
986 executionListener.notEnabled(commandId, exception); | |
987 } | |
988 } | |
989 | |
990 /** | |
991 * Fires the <code>notDefined</code> event for | |
992 * <code>executionListeners</code>. | |
993 * <p> | |
994 * <b>Note:</b> This supports bridging actions to the command framework, | |
995 * and should not be used outside the framework. | |
996 * </p> | |
997 * | |
998 * @param commandId | |
999 * The command id of the command about to execute, never | |
1000 * <code>null</code>. | |
1001 * @param exception | |
1002 * The exception, never <code>null</code>. | |
1003 * @since 3.4 | |
1004 */ | |
1005 public void fireNotDefined(String commandId, NotDefinedException exception) { | |
1006 if (executionListener !is null) { | |
1007 executionListener.notDefined(commandId, exception); | |
1008 } | |
1009 } | |
1010 | |
1011 /** | |
1012 * Fires the <code>preExecute</code> event for | |
1013 * <code>executionListeners</code>. | |
1014 * <p> | |
1015 * <b>Note:</b> This supports bridging actions to the command framework, | |
1016 * and should not be used outside the framework. | |
1017 * </p> | |
1018 * | |
1019 * @param commandId | |
1020 * The command id of the command about to execute, never | |
1021 * <code>null</code>. | |
1022 * @param event | |
1023 * The event that triggered the command, may be <code>null</code>. | |
1024 * @since 3.4 | |
1025 */ | |
1026 public void firePreExecute(String commandId, ExecutionEvent event) { | |
1027 if (executionListener !is null) { | |
1028 executionListener.preExecute(commandId, event); | |
1029 } | |
1030 } | |
1031 | |
1032 /** | |
1033 * Fires the <code>postExecuteSuccess</code> event for | |
1034 * <code>executionListeners</code>. | |
1035 * <p> | |
1036 * <b>Note:</b> This supports bridging actions to the command framework, | |
1037 * and should not be used outside the framework. | |
1038 * </p> | |
1039 * | |
1040 * @param commandId | |
1041 * The command id of the command executed, never | |
1042 * <code>null</code>. | |
1043 * @param returnValue | |
1044 * The value returned from the command, may be <code>null</code>. | |
1045 * @since 3.4 | |
1046 */ | |
1047 public void firePostExecuteSuccess(String commandId, Object returnValue) { | |
1048 if (executionListener !is null) { | |
1049 executionListener.postExecuteSuccess(commandId, returnValue); | |
1050 } | |
1051 } | |
1052 | |
1053 /** | |
1054 * Fires the <code>postExecuteFailure</code> event for | |
1055 * <code>executionListeners</code>. | |
1056 * <p> | |
1057 * <b>Note:</b> This supports bridging actions to the command framework, | |
1058 * and should not be used outside the framework. | |
1059 * </p> | |
1060 * | |
1061 * @param commandId | |
1062 * The command id of the command executed, never | |
1063 * <code>null</code>. | |
1064 * @param exception | |
1065 * The exception, never <code>null</code>. | |
1066 * @since 3.4 | |
1067 */ | |
1068 public void firePostExecuteFailure(String commandId, | |
1069 ExecutionException exception) { | |
1070 if (executionListener !is null) { | |
1071 executionListener.postExecuteFailure(commandId, exception); | |
1072 } | |
1073 } | |
1074 } |