001: /*******************************************************************************
002: * Copyright (c) 2005, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.commands;
011:
012: import java.util.ArrayList;
013: import java.util.List;
014:
015: import org.eclipse.core.commands.AbstractParameterValueConverter;
016: import org.eclipse.core.commands.Category;
017: import org.eclipse.core.commands.Command;
018: import org.eclipse.core.commands.ParameterType;
019: import org.eclipse.core.commands.State;
020: import org.eclipse.core.commands.common.HandleObject;
021: import org.eclipse.core.runtime.IConfigurationElement;
022: import org.eclipse.core.runtime.IExtensionDelta;
023: import org.eclipse.core.runtime.IExtensionRegistry;
024: import org.eclipse.core.runtime.IRegistryChangeEvent;
025: import org.eclipse.core.runtime.Platform;
026: import org.eclipse.ui.PlatformUI;
027: import org.eclipse.ui.commands.ICommandService;
028: import org.eclipse.ui.internal.WorkbenchMessages;
029: import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
030: import org.eclipse.ui.internal.services.RegistryPersistence;
031: import org.eclipse.ui.internal.util.PrefUtil;
032:
033: /**
034: * <p>
035: * A static class for accessing the registry and the preference store.
036: * </p>
037: *
038: * @since 3.1
039: */
040: final class CommandPersistence extends RegistryPersistence {
041:
042: /**
043: * The index of the category elements in the indexed array.
044: *
045: * @see CommandPersistence#read()
046: */
047: private static final int INDEX_CATEGORY_DEFINITIONS = 0;
048:
049: /**
050: * The index of the command elements in the indexed array.
051: *
052: * @see CommandPersistence#read()
053: */
054: private static final int INDEX_COMMAND_DEFINITIONS = 1;
055:
056: /**
057: * The index of the commandParameterType elements in the indexed array.
058: *
059: * @see CommandPersistence#read()
060: * @since 3.2
061: */
062: private static final int INDEX_PARAMETER_TYPE_DEFINITIONS = 2;
063:
064: /**
065: * Reads all of the category definitions from the commands extension point.
066: *
067: * @param configurationElements
068: * The configuration elements in the commands extension point;
069: * must not be <code>null</code>, but may be empty.
070: * @param configurationElementCount
071: * The number of configuration elements that are really in the
072: * array.
073: * @param commandService
074: * The command service to which the categories should be added;
075: * must not be <code>null</code>.
076: */
077: private static final void readCategoriesFromRegistry(
078: final IConfigurationElement[] configurationElements,
079: final int configurationElementCount,
080: final ICommandService commandService) {
081: // Undefine all the previous handle objects.
082: final HandleObject[] handleObjects = commandService
083: .getDefinedCategories();
084: if (handleObjects != null) {
085: for (int i = 0; i < handleObjects.length; i++) {
086: handleObjects[i].undefine();
087: }
088: }
089:
090: // Define the uncategorized category.
091: commandService
092: .defineUncategorizedCategory(
093: WorkbenchMessages.CommandService_AutogeneratedCategoryName,
094: WorkbenchMessages.CommandService_AutogeneratedCategoryDescription);
095:
096: final List warningsToLog = new ArrayList(1);
097:
098: for (int i = 0; i < configurationElementCount; i++) {
099: final IConfigurationElement configurationElement = configurationElements[i];
100:
101: // Read out the category identifier.
102: final String categoryId = readRequired(
103: configurationElement, ATT_ID, warningsToLog,
104: "Categories need an id"); //$NON-NLS-1$
105: if (categoryId == null) {
106: continue;
107: }
108:
109: // Read out the name.
110: final String name = readRequired(configurationElement,
111: ATT_NAME, warningsToLog, "Categories need a name", //$NON-NLS-1$
112: categoryId);
113: if (name == null) {
114: continue;
115: }
116:
117: // Read out the description.
118: final String description = readOptional(
119: configurationElement, ATT_DESCRIPTION);
120:
121: final Category category = commandService
122: .getCategory(categoryId);
123: category.define(name, description);
124: }
125:
126: // If there were any warnings, then log them now.
127: logWarnings(
128: warningsToLog,
129: "Warnings while parsing the commands from the 'org.eclipse.ui.commands' and 'org.eclipse.ui.actionDefinitions' extension points."); //$NON-NLS-1$
130: }
131:
132: /**
133: * Reads all of the command definitions from the commands extension point.
134: *
135: * @param configurationElements
136: * The configuration elements in the commands extension point;
137: * must not be <code>null</code>, but may be empty.
138: * @param configurationElementCount
139: * The number of configuration elements that are really in the
140: * array.
141: * @param commandService
142: * The command service to which the commands should be added;
143: * must not be <code>null</code>.
144: */
145: private static final void readCommandsFromRegistry(
146: final IConfigurationElement[] configurationElements,
147: final int configurationElementCount,
148: final ICommandService commandService) {
149: // Undefine all the previous handle objects.
150: final HandleObject[] handleObjects = commandService
151: .getDefinedCommands();
152: if (handleObjects != null) {
153: for (int i = 0; i < handleObjects.length; i++) {
154: handleObjects[i].undefine();
155: }
156: }
157:
158: final List warningsToLog = new ArrayList(1);
159:
160: for (int i = 0; i < configurationElementCount; i++) {
161: final IConfigurationElement configurationElement = configurationElements[i];
162:
163: // Read out the command identifier.
164: final String commandId = readRequired(configurationElement,
165: ATT_ID, warningsToLog, "Commands need an id"); //$NON-NLS-1$
166: if (commandId == null) {
167: continue;
168: }
169:
170: // Read out the name.
171: final String name = readRequired(configurationElement,
172: ATT_NAME, warningsToLog, "Commands need a name"); //$NON-NLS-1$
173: if (name == null) {
174: continue;
175: }
176:
177: // Read out the description.
178: final String description = readOptional(
179: configurationElement, ATT_DESCRIPTION);
180:
181: // Read out the category id.
182: String categoryId = configurationElement
183: .getAttribute(ATT_CATEGORY_ID);
184: if ((categoryId == null) || (categoryId.length() == 0)) {
185: categoryId = configurationElement
186: .getAttribute(ATT_CATEGORY);
187: if ((categoryId != null) && (categoryId.length() == 0)) {
188: categoryId = null;
189: }
190: }
191:
192: // Read out the parameters.
193: final Parameter[] parameters = readParameters(
194: configurationElement, warningsToLog, commandService);
195:
196: // Read out the returnTypeId.
197: final String returnTypeId = readOptional(
198: configurationElement, ATT_RETURN_TYPE_ID);
199:
200: // Read out the help context identifier.
201: final String helpContextId = readOptional(
202: configurationElement, ATT_HELP_CONTEXT_ID);
203:
204: final Command command = commandService
205: .getCommand(commandId);
206: final Category category = commandService
207: .getCategory(categoryId);
208: if (!category.isDefined()) {
209: addWarning(
210: warningsToLog,
211: "Commands should really have a category", //$NON-NLS-1$
212: configurationElement, commandId,
213: "categoryId", categoryId); //$NON-NLS-1$
214: }
215:
216: final ParameterType returnType;
217: if (returnTypeId == null) {
218: returnType = null;
219: } else {
220: returnType = commandService
221: .getParameterType(returnTypeId);
222: }
223:
224: command.define(name, description, category, parameters,
225: returnType, helpContextId);
226: readState(configurationElement, warningsToLog, command);
227: }
228:
229: // If there were any warnings, then log them now.
230: logWarnings(
231: warningsToLog,
232: "Warnings while parsing the commands from the 'org.eclipse.ui.commands' and 'org.eclipse.ui.actionDefinitions' extension points."); //$NON-NLS-1$
233: }
234:
235: /**
236: * Reads the parameters from a parent configuration element. This is used to
237: * read the parameter sub-elements from a command element. Each parameter is
238: * guaranteed to be valid. If invalid parameters are found, then a warning
239: * status will be appended to the <code>warningsToLog</code> list.
240: *
241: * @param configurationElement
242: * The configuration element from which the parameters should be
243: * read; must not be <code>null</code>.
244: * @param warningsToLog
245: * The list of warnings found during parsing. Warnings found
246: * while parsing the parameters will be appended to this list.
247: * This value must not be <code>null</code>.
248: * @param commandService
249: * The command service from which the parameter can get parameter
250: * types; must not be <code>null</code>.
251: * @return The array of parameters found for this configuration element;
252: * <code>null</code> if none can be found.
253: */
254: private static final Parameter[] readParameters(
255: final IConfigurationElement configurationElement,
256: final List warningsToLog,
257: final ICommandService commandService) {
258: final IConfigurationElement[] parameterElements = configurationElement
259: .getChildren(TAG_COMMAND_PARAMETER);
260: if ((parameterElements == null)
261: || (parameterElements.length == 0)) {
262: return null;
263: }
264:
265: int insertionIndex = 0;
266: Parameter[] parameters = new Parameter[parameterElements.length];
267: for (int i = 0; i < parameterElements.length; i++) {
268: final IConfigurationElement parameterElement = parameterElements[i];
269: // Read out the id
270: final String id = readRequired(parameterElement, ATT_ID,
271: warningsToLog, "Parameters need an id"); //$NON-NLS-1$
272: if (id == null) {
273: continue;
274: }
275:
276: // Read out the name.
277: final String name = readRequired(parameterElement,
278: ATT_NAME, warningsToLog, "Parameters need a name"); //$NON-NLS-1$
279: if (name == null) {
280: continue;
281: }
282:
283: /*
284: * The IParameterValues will be initialized lazily as an
285: * IExecutableExtension.
286: */
287:
288: // Read out the typeId attribute, if present.
289: final String typeId = readOptional(parameterElement,
290: ATT_TYPE_ID);
291:
292: // Read out the optional attribute, if present.
293: final boolean optional = readBoolean(parameterElement,
294: ATT_OPTIONAL, true);
295:
296: final ParameterType type;
297: if (typeId == null) {
298: type = null;
299: } else {
300: type = commandService.getParameterType(typeId);
301: }
302:
303: final Parameter parameter = new Parameter(id, name,
304: parameterElement, type, optional);
305: parameters[insertionIndex++] = parameter;
306: }
307:
308: if (insertionIndex != parameters.length) {
309: final Parameter[] compactedParameters = new Parameter[insertionIndex];
310: System.arraycopy(parameters, 0, compactedParameters, 0,
311: insertionIndex);
312: parameters = compactedParameters;
313: }
314:
315: return parameters;
316: }
317:
318: /**
319: * Reads all of the commandParameterType definitions from the commands
320: * extension point.
321: *
322: * @param configurationElements
323: * The configuration elements in the commands extension point;
324: * must not be <code>null</code>, but may be empty.
325: * @param configurationElementCount
326: * The number of configuration elements that are really in the
327: * array.
328: * @param commandService
329: * The command service to which the commands should be added;
330: * must not be <code>null</code>.
331: * @since 3.2
332: */
333: private static final void readParameterTypesFromRegistry(
334: final IConfigurationElement[] configurationElements,
335: final int configurationElementCount,
336: final ICommandService commandService) {
337:
338: // Undefine all the previous handle objects.
339: final HandleObject[] handleObjects = commandService
340: .getDefinedParameterTypes();
341: if (handleObjects != null) {
342: for (int i = 0; i < handleObjects.length; i++) {
343: handleObjects[i].undefine();
344: }
345: }
346:
347: final List warningsToLog = new ArrayList(1);
348:
349: for (int i = 0; i < configurationElementCount; i++) {
350: final IConfigurationElement configurationElement = configurationElements[i];
351:
352: // Read out the commandParameterType identifier.
353: final String parameterTypeId = readRequired(
354: configurationElement, ATT_ID, warningsToLog,
355: "Command parameter types need an id"); //$NON-NLS-1$
356: if (parameterTypeId == null) {
357: continue;
358: }
359:
360: // Read out the type.
361: final String type = readOptional(configurationElement,
362: ATT_TYPE);
363:
364: // Read out the converter.
365: final String converter = readOptional(configurationElement,
366: ATT_CONVERTER);
367:
368: /*
369: * if the converter attribute was given, create a proxy
370: * AbstractParameterValueConverter for the ParameterType, otherwise
371: * null indicates there is no converter
372: */
373: final AbstractParameterValueConverter parameterValueConverter = (converter == null) ? null
374: : new ParameterValueConverterProxy(
375: configurationElement);
376:
377: final ParameterType parameterType = commandService
378: .getParameterType(parameterTypeId);
379: parameterType.define(type, parameterValueConverter);
380: }
381:
382: // If there were any warnings, then log them now.
383: logWarnings(
384: warningsToLog,
385: "Warnings while parsing the commandParameterTypes from the 'org.eclipse.ui.commands' extension point."); //$NON-NLS-1$
386:
387: }
388:
389: /**
390: * Reads the states from a parent configuration element. This is used to
391: * read the state sub-elements from a command element. Each state is
392: * guaranteed to be valid. If invalid states are found, then a warning
393: * status will be appended to the <code>warningsToLog</code> list.
394: *
395: * @param configurationElement
396: * The configuration element from which the states should be
397: * read; must not be <code>null</code>.
398: * @param warningsToLog
399: * The list of warnings found during parsing. Warnings found
400: * while parsing the parameters will be appended to this list.
401: * This value must not be <code>null</code>.
402: * @param command
403: * The command for which the state is being read; may be
404: * <code>null</code>.
405: */
406: private static final void readState(
407: final IConfigurationElement configurationElement,
408: final List warningsToLog, final Command command) {
409: final IConfigurationElement[] stateElements = configurationElement
410: .getChildren(TAG_STATE);
411: if ((stateElements == null) || (stateElements.length == 0)) {
412: return;
413: }
414:
415: for (int i = 0; i < stateElements.length; i++) {
416: final IConfigurationElement stateElement = stateElements[i];
417:
418: final String id = readRequired(stateElement, ATT_ID,
419: warningsToLog, "State needs an id"); //$NON-NLS-1$
420: if (id == null) {
421: continue;
422: }
423:
424: if (checkClass(stateElement, warningsToLog,
425: "State must have an associated class", id)) { //$NON-NLS-1$
426: final State state = new CommandStateProxy(stateElement,
427: ATT_CLASS, PrefUtil
428: .getInternalPreferenceStore(),
429: CommandService.createPreferenceKey(command, id));
430: command.addState(id, state);
431: }
432: }
433: }
434:
435: /**
436: * The command service with which this persistence class is associated;
437: * never <code>null</code>.
438: */
439: private final ICommandService commandService;
440:
441: /**
442: * Constructs a new instance of <code>CommandPersistence</code>.
443: *
444: * @param commandService
445: * The command service which should be populated with the values
446: * from the registry; must not be <code>null</code>.
447: */
448: CommandPersistence(final ICommandService commandService) {
449: if (commandService == null) {
450: throw new NullPointerException(
451: "The command service cannot be null"); //$NON-NLS-1$
452: }
453: this .commandService = commandService;
454: }
455:
456: protected final boolean isChangeImportant(
457: final IRegistryChangeEvent event) {
458: final IExtensionDelta[] commandDeltas = event
459: .getExtensionDeltas(PlatformUI.PLUGIN_ID,
460: IWorkbenchRegistryConstants.PL_COMMANDS);
461: if (commandDeltas.length == 0) {
462: final IExtensionDelta[] actionDefinitionDeltas = event
463: .getExtensionDeltas(
464: PlatformUI.PLUGIN_ID,
465: IWorkbenchRegistryConstants.PL_ACTION_DEFINITIONS);
466: if (actionDefinitionDeltas.length == 0) {
467: return false;
468: }
469: }
470:
471: return true;
472: }
473:
474: /**
475: * Reads all of the commands and categories from the registry,
476: *
477: * @param commandService
478: * The command service which should be populated with the values
479: * from the registry; must not be <code>null</code>.
480: */
481: protected final void read() {
482: super .read();
483:
484: // Create the extension registry mementos.
485: final IExtensionRegistry registry = Platform
486: .getExtensionRegistry();
487: int commandDefinitionCount = 0;
488: int categoryDefinitionCount = 0;
489: int parameterTypeDefinitionCount = 0;
490: final IConfigurationElement[][] indexedConfigurationElements = new IConfigurationElement[3][];
491:
492: // Sort the commands extension point based on element name.
493: final IConfigurationElement[] commandsExtensionPoint = registry
494: .getConfigurationElementsFor(EXTENSION_COMMANDS);
495: for (int i = 0; i < commandsExtensionPoint.length; i++) {
496: final IConfigurationElement configurationElement = commandsExtensionPoint[i];
497: final String name = configurationElement.getName();
498:
499: // Check if it is a binding definition.
500: if (TAG_COMMAND.equals(name)) {
501: addElementToIndexedArray(configurationElement,
502: indexedConfigurationElements,
503: INDEX_COMMAND_DEFINITIONS,
504: commandDefinitionCount++);
505: } else if (TAG_CATEGORY.equals(name)) {
506: addElementToIndexedArray(configurationElement,
507: indexedConfigurationElements,
508: INDEX_CATEGORY_DEFINITIONS,
509: categoryDefinitionCount++);
510: } else if (TAG_COMMAND_PARAMETER_TYPE.equals(name)) {
511: addElementToIndexedArray(configurationElement,
512: indexedConfigurationElements,
513: INDEX_PARAMETER_TYPE_DEFINITIONS,
514: parameterTypeDefinitionCount++);
515: }
516: }
517:
518: final IConfigurationElement[] actionDefinitionsExtensionPoint = registry
519: .getConfigurationElementsFor(EXTENSION_ACTION_DEFINITIONS);
520: for (int i = 0; i < actionDefinitionsExtensionPoint.length; i++) {
521: final IConfigurationElement configurationElement = actionDefinitionsExtensionPoint[i];
522: final String name = configurationElement.getName();
523:
524: if (TAG_ACTION_DEFINITION.equals(name)) {
525: addElementToIndexedArray(configurationElement,
526: indexedConfigurationElements,
527: INDEX_COMMAND_DEFINITIONS,
528: commandDefinitionCount++);
529: }
530: }
531:
532: readCategoriesFromRegistry(
533: indexedConfigurationElements[INDEX_CATEGORY_DEFINITIONS],
534: categoryDefinitionCount, commandService);
535: readCommandsFromRegistry(
536: indexedConfigurationElements[INDEX_COMMAND_DEFINITIONS],
537: commandDefinitionCount, commandService);
538: readParameterTypesFromRegistry(
539: indexedConfigurationElements[INDEX_PARAMETER_TYPE_DEFINITIONS],
540: parameterTypeDefinitionCount, commandService);
541:
542: }
543: }
|