| /******************************************************************************* |
| * Copyright (c) 2005, 2015 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.ui.internal.handlers; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Iterator; |
| import java.util.List; |
| import org.eclipse.core.commands.IHandler; |
| import org.eclipse.core.expressions.Expression; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtensionDelta; |
| import org.eclipse.core.runtime.IExtensionRegistry; |
| import org.eclipse.core.runtime.IRegistryChangeEvent; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.handlers.IHandlerActivation; |
| import org.eclipse.ui.handlers.IHandlerService; |
| import org.eclipse.ui.internal.WorkbenchPlugin; |
| import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants; |
| import org.eclipse.ui.internal.services.RegistryPersistence; |
| import org.eclipse.ui.services.IEvaluationService; |
| |
| /** |
| * <p> |
| * A static class for accessing the registry. |
| * </p> |
| * |
| * @since 3.1 |
| */ |
| public final class HandlerPersistence extends RegistryPersistence { |
| |
| /** |
| * The index of the command elements in the indexed array. |
| * |
| * @see HandlerPersistence#read() |
| */ |
| private static final int INDEX_COMMAND_DEFINITIONS = 0; |
| |
| /** |
| * The index of the command elements in the indexed array. |
| * |
| * @see HandlerPersistence#read() |
| */ |
| private static final int INDEX_HANDLER_DEFINITIONS = 1; |
| |
| /** |
| * The index of the handler submissions in the indexed array. |
| * |
| * @see HandlerPersistence#read() |
| */ |
| private static final int INDEX_HANDLER_SUBMISSIONS = 2; |
| |
| /** |
| * The handler activations that have come from the registry. This is used to |
| * flush the activations when the registry is re-read. This value is never |
| * <code>null</code> |
| */ |
| private final Collection<IHandlerActivation> handlerActivations = new ArrayList<>(); |
| |
| /** |
| * The handler service with which this persistence class is associated. This |
| * value must not be <code>null</code>. |
| */ |
| private final IHandlerService handlerService; |
| |
| private IEvaluationService evaluationService; |
| |
| /** |
| * Constructs a new instance of <code>HandlerPersistence</code>. |
| * |
| * @param handlerService The handler service with which the handlers should |
| * be registered; must not be <code>null</code>. |
| * @param evaluationService The evaluation service used by handler proxies with |
| * enabled when expressions |
| */ |
| HandlerPersistence(final IHandlerService handlerService, IEvaluationService evaluationService) { |
| this.handlerService = handlerService; |
| this.evaluationService = evaluationService; |
| } |
| |
| /** |
| * Deactivates all of the activations made by this class, and then clears the |
| * collection. This should be called before every read. |
| * |
| * @param handlerService The service handling the activations; must not be |
| * <code>null</code>. |
| */ |
| private void clearActivations(final IHandlerService handlerService) { |
| handlerService.deactivateHandlers(handlerActivations); |
| Iterator<IHandlerActivation> i = handlerActivations.iterator(); |
| while (i.hasNext()) { |
| IHandlerActivation activation = i.next(); |
| if (activation.getHandler() != null) { |
| try { |
| activation.getHandler().dispose(); |
| } catch (Exception | LinkageError e) { |
| WorkbenchPlugin.log("Failed to dispose handler for " //$NON-NLS-1$ |
| + activation.getCommandId(), e); |
| } |
| } |
| } |
| handlerActivations.clear(); |
| } |
| |
| @Override |
| public void dispose() { |
| super.dispose(); |
| clearActivations(handlerService); |
| } |
| |
| @Override |
| protected boolean isChangeImportant(final IRegistryChangeEvent event) { |
| return false; |
| } |
| |
| public boolean handlersNeedUpdating(final IRegistryChangeEvent event) { |
| /* |
| * Handlers will need to be re-read (i.e., re-verified) if any of the handler |
| * extensions change (i.e., handlers, commands), or if any of the command |
| * extensions change (i.e., action definitions). |
| */ |
| final IExtensionDelta[] handlerDeltas = event.getExtensionDeltas(PlatformUI.PLUGIN_ID, |
| IWorkbenchRegistryConstants.PL_HANDLERS); |
| if (handlerDeltas.length == 0) { |
| final IExtensionDelta[] commandDeltas = event.getExtensionDeltas(PlatformUI.PLUGIN_ID, |
| IWorkbenchRegistryConstants.PL_COMMANDS); |
| if (commandDeltas.length == 0) { |
| final IExtensionDelta[] actionDefinitionDeltas = event.getExtensionDeltas(PlatformUI.PLUGIN_ID, |
| IWorkbenchRegistryConstants.PL_ACTION_DEFINITIONS); |
| if (actionDefinitionDeltas.length == 0) { |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Reads all of the handlers from the registry |
| * |
| * @param handlerService The handler service which should be populated with the |
| * values from the registry; must not be |
| * <code>null</code>. |
| */ |
| @Override |
| protected void read() { |
| super.read(); |
| reRead(); |
| } |
| |
| public void reRead() { |
| // Create the extension registry mementos. |
| final IExtensionRegistry registry = Platform.getExtensionRegistry(); |
| int commandDefinitionCount = 0; |
| int handlerDefinitionCount = 0; |
| int handlerSubmissionCount = 0; |
| final IConfigurationElement[][] indexedConfigurationElements = new IConfigurationElement[3][]; |
| |
| // Sort the commands extension point based on element name. |
| final IConfigurationElement[] commandsExtensionPoint = registry.getConfigurationElementsFor(EXTENSION_COMMANDS); |
| for (final IConfigurationElement configurationElement : commandsExtensionPoint) { |
| final String name = configurationElement.getName(); |
| |
| // Check if it is a handler submission or a command definition. |
| if (TAG_HANDLER_SUBMISSION.equals(name)) { |
| addElementToIndexedArray(configurationElement, indexedConfigurationElements, INDEX_HANDLER_SUBMISSIONS, |
| handlerSubmissionCount++); |
| } else if (TAG_COMMAND.equals(name)) { |
| addElementToIndexedArray(configurationElement, indexedConfigurationElements, INDEX_COMMAND_DEFINITIONS, |
| commandDefinitionCount++); |
| } |
| } |
| |
| // Sort the handler extension point based on element name. |
| final IConfigurationElement[] handlersExtensionPoint = registry.getConfigurationElementsFor(EXTENSION_HANDLERS); |
| for (final IConfigurationElement configurationElement : handlersExtensionPoint) { |
| final String name = configurationElement.getName(); |
| |
| // Check if it is a handler submission or a command definition. |
| if (TAG_HANDLER.equals(name)) { |
| addElementToIndexedArray(configurationElement, indexedConfigurationElements, INDEX_HANDLER_DEFINITIONS, |
| handlerDefinitionCount++); |
| } |
| } |
| |
| clearActivations(handlerService); |
| readDefaultHandlersFromRegistry(indexedConfigurationElements[INDEX_COMMAND_DEFINITIONS], |
| commandDefinitionCount); |
| readHandlerSubmissionsFromRegistry(indexedConfigurationElements[INDEX_HANDLER_SUBMISSIONS], |
| handlerSubmissionCount); |
| readHandlersFromRegistry(indexedConfigurationElements[INDEX_HANDLER_DEFINITIONS], handlerDefinitionCount); |
| } |
| |
| /** |
| * Reads the default handlers from an array of command elements from the |
| * commands extension point. |
| * |
| * @param configurationElements The configuration elements in the commands |
| * extension point; must not be |
| * <code>null</code>, but may be empty. |
| * @param configurationElementCount The number of configuration elements that |
| * are really in the array. |
| */ |
| private void readDefaultHandlersFromRegistry(final IConfigurationElement[] configurationElements, |
| final int configurationElementCount) { |
| for (int i = 0; i < configurationElementCount; i++) { |
| final IConfigurationElement configurationElement = configurationElements[i]; |
| |
| /* |
| * Read out the command identifier. This was already checked by |
| * <code>CommandPersistence</code>, so we'll just ignore any problems here. |
| */ |
| final String commandId = readOptional(configurationElement, ATT_ID); |
| if (commandId == null) { |
| continue; |
| } |
| |
| // Check to see if we have a default handler of any kind. |
| if ((configurationElement.getAttribute(ATT_DEFAULT_HANDLER) == null) |
| && (configurationElement.getChildren(TAG_DEFAULT_HANDLER).length == 0)) { |
| continue; |
| } |
| |
| handlerActivations.add(handlerService.activateHandler(commandId, |
| new HandlerProxy(commandId, configurationElement, ATT_DEFAULT_HANDLER))); |
| } |
| } |
| |
| /** |
| * Reads all of the handlers from the handlers extension point. |
| * |
| * @param configurationElements The configuration elements in the commands |
| * extension point; must not be |
| * <code>null</code>, but may be empty. |
| * @param configurationElementCount The number of configuration elements that |
| * are really in the array. |
| * @param handlerService The handler service to which the handlers |
| * should be added; must not be |
| * <code>null</code>. |
| */ |
| private void readHandlersFromRegistry(final IConfigurationElement[] configurationElements, |
| final int configurationElementCount) { |
| final List<IStatus> warningsToLog = new ArrayList<>(1); |
| |
| for (int i = 0; i < configurationElementCount; i++) { |
| final IConfigurationElement configurationElement = configurationElements[i]; |
| |
| // Read out the command identifier. |
| final String commandId = readRequired(configurationElement, ATT_COMMAND_ID, warningsToLog, |
| "Handlers need a command id"); //$NON-NLS-1$ |
| if (commandId == null) { |
| continue; |
| } |
| |
| // Check to see if we have a handler class. |
| if (!checkClass(configurationElement, warningsToLog, "Handlers need a class", commandId)) { //$NON-NLS-1$ |
| continue; |
| } |
| |
| // Get the activeWhen and enabledWhen expressions. |
| final Expression activeWhenExpression = readWhenElement(configurationElement, TAG_ACTIVE_WHEN, commandId, |
| warningsToLog); |
| if (activeWhenExpression == ERROR_EXPRESSION) { |
| continue; |
| } |
| final Expression enabledWhenExpression = readWhenElement(configurationElement, TAG_ENABLED_WHEN, commandId, |
| warningsToLog); |
| if (enabledWhenExpression == ERROR_EXPRESSION) { |
| continue; |
| } |
| |
| final IHandler proxy = new HandlerProxy(commandId, configurationElement, ATT_CLASS, enabledWhenExpression, |
| evaluationService); |
| handlerActivations.add(handlerService.activateHandler(commandId, proxy, activeWhenExpression)); |
| |
| // Read out the help context identifier. |
| final String helpContextId = readOptional(configurationElement, ATT_HELP_CONTEXT_ID); |
| handlerService.setHelpContextId(proxy, helpContextId); |
| } |
| |
| logWarnings(warningsToLog, |
| "Warnings while parsing the handlers from the 'org.eclipse.ui.handlers' extension point."); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Reads all of the handler submissions from the commands extension point. |
| * |
| * @param configurationElements The configuration elements in the commands |
| * extension point; must not be |
| * <code>null</code>, but may be empty. |
| * @param configurationElementCount The number of configuration elements that |
| * are really in the array. |
| * @param handlerService The handler service to which the handlers |
| * should be added; must not be |
| * <code>null</code>. |
| */ |
| private void readHandlerSubmissionsFromRegistry(final IConfigurationElement[] configurationElements, |
| final int configurationElementCount) { |
| final List<IStatus> warningsToLog = new ArrayList<>(1); |
| |
| for (int i = 0; i < configurationElementCount; i++) { |
| final IConfigurationElement configurationElement = configurationElements[i]; |
| |
| // Read out the command identifier. |
| final String commandId = readRequired(configurationElement, ATT_COMMAND_ID, warningsToLog, |
| "Handler submissions need a command id"); //$NON-NLS-1$ |
| if (commandId == null) { |
| continue; |
| } |
| |
| handlerActivations.add(handlerService.activateHandler(commandId, |
| new LegacyHandlerWrapper(new LegacyHandlerProxy(configurationElement)))); |
| } |
| |
| logWarnings(warningsToLog, |
| "Warnings while parsing the handler submissions from the 'org.eclipse.ui.commands' extension point."); //$NON-NLS-1$ |
| } |
| } |