diff options
author | Paul Webster | 2010-03-02 20:12:32 +0000 |
---|---|---|
committer | Paul Webster | 2010-03-02 20:12:32 +0000 |
commit | 37848358f0b5f81a9ae0bbe264c50357e788f2f5 (patch) | |
tree | 14bf8a1dc13f855d77af2276935f10de7403ace1 /bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/KeyBindingService.java | |
parent | 11d46d6c88e8383d7970bf26aff954047343bbb9 (diff) | |
download | eclipse.platform.ui-37848358f0b5f81a9ae0bbe264c50357e788f2f5.tar.gz eclipse.platform.ui-37848358f0b5f81a9ae0bbe264c50357e788f2f5.tar.xz eclipse.platform.ui-37848358f0b5f81a9ae0bbe264c50357e788f2f5.zip |
Bug 299385 - [UI] clean up errors in compatibility workbenchI20100406-2156
Changes to support the extended compat layer
Diffstat (limited to 'bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/KeyBindingService.java')
-rw-r--r-- | bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/KeyBindingService.java | 636 |
1 files changed, 636 insertions, 0 deletions
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/KeyBindingService.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/KeyBindingService.java new file mode 100644 index 00000000000..ff06d8aad82 --- /dev/null +++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/KeyBindingService.java @@ -0,0 +1,636 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.ui.internal; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jface.action.IAction; +import org.eclipse.ui.IKeyBindingService; +import org.eclipse.ui.INestableKeyBindingService; +import org.eclipse.ui.IWorkbenchPartSite; +import org.eclipse.ui.IWorkbenchSite; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ActionHandler; +import org.eclipse.ui.commands.HandlerSubmission; +import org.eclipse.ui.commands.IHandler; +import org.eclipse.ui.commands.Priority; +import org.eclipse.ui.contexts.EnabledSubmission; +import org.eclipse.ui.internal.actions.CommandAction; +import org.eclipse.ui.internal.handlers.CommandLegacyActionWrapper; + +/** + * This service provides a nestable implementation of a key binding service. + * This class is provided for backwards compatibility only, and might be removed + * in the future. All of the functionality is the class can be duplicated by + * using the commands and contexts API. + * + * @since 2.0 + */ +public final class KeyBindingService implements INestableKeyBindingService { + + /** + * The currently active nested service, if any. If there are no nested + * services or none of them are active, then this value is <code>null</code>. + */ + private IKeyBindingService activeService = null; + + /** + * Whether this key binding service has been disposed. A disposed key + * binding service should not be used again. + */ + private boolean disposed; + + /** + * The set of context identifiers enabled in this key binding service (not + * counting any nested services). This set may be empty, but it is never + * <code>null</code>. + */ + private Set enabledContextIds = Collections.EMPTY_SET; + + /** + * The list of context submissions indicating the enabled state of the + * context. This does not include those from nested services. This list may + * be empty, but it is never <code>null</code>. + */ + private List enabledSubmissions = new ArrayList(); + + /** + * The map of handler submissions, sorted by command identifiers. This does + * not include those from nested services. This map may be empty, but it is + * never <code>null</code>. + */ + private Map handlerSubmissionsByCommandId = new HashMap(); + + /** + * The context submissions from the currently active nested service. This + * value is <code>null</code> if there is no currently active nested + * service. + */ + private List nestedEnabledSubmissions = null; + + /** + * The handler submissions from the currently active nested service. This + * value is <code>null</code> if there is no currently active handler + * service. + */ + private List nestedHandlerSubmissions = null; + + /** + * The map of workbench part sites to nested key binding services. This map + * may be empty, but is never <code>null</code>. + */ + private final Map nestedServices = new HashMap(); + + /** + * The parent for this key binding service; <code>null</code> if there is + * no parent. If there is a parent, then this means that it should not do a + * "live" update of its contexts or handlers, but should make a call to the + * parent instead. + */ + private final KeyBindingService parent; + + /** + * The site within the workbench at which this service is provided. This + * value should not be <code>null</code>. + */ + private IWorkbenchPartSite workbenchPartSite; + + /** + * Constructs a new instance of <code>KeyBindingService</code> on a given + * workbench site. This instance is not nested. + * + * @param workbenchPartSite + * The site for which this service will be responsible; should + * not be <code>null</code>. + */ + public KeyBindingService(IWorkbenchPartSite workbenchPartSite) { + this(workbenchPartSite, null); + } + + /** + * Constructs a new instance of <code>KeyBindingService</code> on a given + * workbench site. + * + * @param workbenchPartSite + * The site for which this service will be responsible; should + * not be <code>null</code>. + * @param parent + * The parent key binding service, if any; <code>null</code> if + * none. + */ + KeyBindingService(IWorkbenchPartSite workbenchPartSite, + KeyBindingService parent) { + this.workbenchPartSite = workbenchPartSite; + this.parent = parent; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.INestableKeyBindingService#activateKeyBindingService(org.eclipse.ui.IWorkbenchSite) + */ + public boolean activateKeyBindingService(IWorkbenchSite nestedSite) { + if (disposed) { + return false; + } + + // Check if we should do a deactivation. + if (nestedSite == null) { + // We should do a deactivation, if there is one active. + if (activeService == null) { + // There is no active service. Do no work. + return false; + } + // Deactivate the currently active nested service. + deactivateNestedService(); + return true; + } + + // Attempt to activate a service. + final IKeyBindingService service = (IKeyBindingService) nestedServices + .get(nestedSite); + + if (service == activeService) { + // The service is already active, or already null + return false; + } + + deactivateNestedService(); + if (service!=null) { + activateNestedService(service); + } + return true; + } + + /** + * Activates the given service without worrying about the currently active + * service. This goes through the work of adding all of the nested context + * ids as enabled submissions. + * + * @param service + * The service to become active; if <code>null</code>, then + * the reference to the active service is set to + * <code>null</code> but nothing else happens. + */ + private final void activateNestedService(final IKeyBindingService service) { + if (disposed) { + return; + } + + /* + * If I have a parent, and I'm the active service, then deactivate so + * that I can make changes. + */ + boolean active = false; + boolean haveParent = (parent != null); + if (haveParent) { + active = (parent.activeService == this); + if (active) { + parent.deactivateNestedService(); + } + } + + // Update the active service. + activeService = service; + + // Check to see that the service isn't null. + if (service == null) { + return; + } + + if (haveParent) { + if (active) { + parent.activateNestedService(this); + } + + } else if (activeService instanceof KeyBindingService) { + // I have no parent, so I can make the changes myself. + final KeyBindingService nestedService = (KeyBindingService) activeService; + + // Update the contexts. + nestedEnabledSubmissions = nestedService.getEnabledSubmissions(); + normalizeSites(nestedEnabledSubmissions); + PlatformUI.getWorkbench().getContextSupport().addEnabledSubmissions( + nestedEnabledSubmissions); + + // Update the handlers. + nestedHandlerSubmissions = nestedService.getHandlerSubmissions(); + normalizeSites(nestedHandlerSubmissions); + PlatformUI.getWorkbench().getCommandSupport().addHandlerSubmissions( + nestedHandlerSubmissions); + } + } + + /** + * Deactives the currently active service. This nulls out the reference, and + * removes all the enabled submissions for the nested service. + */ + private final void deactivateNestedService() { + if (disposed) { + return; + } + + // Don't do anything if there is no active service. + if (activeService == null) { + return; + } + + // Check to see if there is a parent. + boolean active = false; + if (parent != null) { + // Check if I'm the active service. + if (parent.activeService == this) { + active = true; + // Deactivate myself so I can make changes. + parent.deactivateNestedService(); + } + + } else if (activeService instanceof KeyBindingService) { + // Remove all the nested context ids. + PlatformUI.getWorkbench().getContextSupport() + .removeEnabledSubmissions(nestedEnabledSubmissions); + + /* + * Remove all of the nested handler submissions. The handlers here + * weren't created by this instance (but by the nest instance), and + * hence can't be disposed here. + */ + PlatformUI.getWorkbench().getCommandSupport() + .removeHandlerSubmissions(nestedHandlerSubmissions); + + } + + // Clear our reference to the active service. + activeService = null; + + // If necessary, let my parent know that changes have occurred. + if (active) { + parent.activateNestedService(this); + } + } + + /** + * Disposes this key binding service. This clears out all of the submissions + * held by this service, and its nested services. + */ + public void dispose() { + if (!disposed) { + deactivateNestedService(); + disposed = true; + + PlatformUI.getWorkbench() + .getContextSupport() + .removeEnabledSubmissions(new ArrayList(enabledSubmissions)); + enabledSubmissions.clear(); + + /* + * Each removed handler submission, must dispose its corresponding + * handler -- as these handlers only exist inside of this class. + */ + final List submissions = new ArrayList( + handlerSubmissionsByCommandId.values()); + final Iterator submissionItr = submissions.iterator(); + while (submissionItr.hasNext()) { + ((HandlerSubmission) submissionItr.next()).getHandler() + .dispose(); + } + PlatformUI.getWorkbench().getCommandSupport() + .removeHandlerSubmissions(submissions); + handlerSubmissionsByCommandId.clear(); + + for (Iterator iterator = nestedServices.values().iterator(); iterator + .hasNext();) { + KeyBindingService keyBindingService = (KeyBindingService) iterator + .next(); + keyBindingService.dispose(); + } + + nestedEnabledSubmissions = null; + nestedHandlerSubmissions = null; + nestedServices.clear(); + } + } + + /** + * Gets a copy of all the enabled submissions in the nesting chain. + * + * @return All of the nested enabled submissions -- including the ones from + * this service. This list may be empty, but is never + * <code>null</code>. + */ + private final List getEnabledSubmissions() { + if (disposed) { + return null; + } + + final List submissions = new ArrayList(enabledSubmissions); + if (activeService instanceof KeyBindingService) { + final KeyBindingService nestedService = (KeyBindingService) activeService; + submissions.addAll(nestedService.getEnabledSubmissions()); + } + return submissions; + } + + /** + * Gets a copy of all the handler submissions in the nesting chain. + * + * @return All of the nested handler submissions -- including the ones from + * this service. This list may be empty, but is never + * <code>null</code>. + */ + private final List getHandlerSubmissions() { + if (disposed) { + return null; + } + + final List submissions = new ArrayList(handlerSubmissionsByCommandId + .values()); + if (activeService instanceof KeyBindingService) { + final KeyBindingService nestedService = (KeyBindingService) activeService; + submissions.addAll(nestedService.getHandlerSubmissions()); + } + return submissions; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.INestableKeyBindingService#getKeyBindingService(org.eclipse.ui.IWorkbenchSite) + */ + public IKeyBindingService getKeyBindingService(IWorkbenchSite nestedSite) { + if (disposed) { + return null; + } + + if (nestedSite == null) { + return null; + } + + IKeyBindingService service = (IKeyBindingService) nestedServices + .get(nestedSite); + if (service == null) { + // TODO the INestedKeyBindingService API should be based on + // IWorkbenchPartSite.. + if (nestedSite instanceof IWorkbenchPartSite) { + service = new KeyBindingService( + (IWorkbenchPartSite) nestedSite, this); + } else { + service = new KeyBindingService(null, this); + } + + nestedServices.put(nestedSite, service); + } + + return service; + } + + public String[] getScopes() { + if (disposed) { + return null; + } + + // Get the nested scopes, if any. + final String[] nestedScopes; + if (activeService == null) { + nestedScopes = null; + } else { + nestedScopes = activeService.getScopes(); + } + + // Build the list of active scopes + final Set activeScopes = new HashSet(); + activeScopes.addAll(enabledContextIds); + if (nestedScopes != null) { + for (int i = 0; i < nestedScopes.length; i++) { + activeScopes.add(nestedScopes[i]); + } + } + + return (String[]) activeScopes.toArray(new String[activeScopes.size()]); + } + + /** + * Replaces the active workbench site with this service's active workbench + * site. This ensures that the context manager will recognize the context as + * active. Note: this method modifies the list in place; it is + * <em>destructive</em>. + * + * @param submissionsToModify + * The submissions list to modify; must not be <code>null</code>, + * but may be empty. + */ + private final void normalizeSites(final List submissionsToModify) { + if (disposed) { + return; + } + + final int size = submissionsToModify.size(); + for (int i = 0; i < size; i++) { + final Object submission = submissionsToModify.get(i); + final Object replacementSubmission; + + if (submission instanceof EnabledSubmission) { + final EnabledSubmission enabledSubmission = (EnabledSubmission) submission; + if (!workbenchPartSite.equals(enabledSubmission + .getActiveWorkbenchPartSite())) { + replacementSubmission = new EnabledSubmission(null, + enabledSubmission.getActiveShell(), + workbenchPartSite, enabledSubmission.getContextId()); + } else { + replacementSubmission = enabledSubmission; + } + + } else if (submission instanceof HandlerSubmission) { + final HandlerSubmission handlerSubmission = (HandlerSubmission) submission; + if (!workbenchPartSite.equals(handlerSubmission + .getActiveWorkbenchPartSite())) { + replacementSubmission = new HandlerSubmission(null, + handlerSubmission.getActiveShell(), + workbenchPartSite, + handlerSubmission.getCommandId(), handlerSubmission + .getHandler(), handlerSubmission + .getPriority()); + } else { + replacementSubmission = handlerSubmission; + } + + } else { + replacementSubmission = submission; + } + + submissionsToModify.set(i, replacementSubmission); + } + + } + + public void registerAction(IAction action) { + if (disposed) { + return; + } + + if (action instanceof CommandLegacyActionWrapper) { + // this is a registration of a fake action for an already + // registered handler + WorkbenchPlugin + .log("Cannot register a CommandLegacyActionWrapper back into the system"); //$NON-NLS-1$ + return; + } + + if (action instanceof CommandAction) { + // we unfortunately had to allow these out into the wild, but they + // still must not feed back into the system + return; + } + + unregisterAction(action); + String commandId = action.getActionDefinitionId(); + if (commandId != null) { + /* + * If I have a parent and I'm active, de-activate myself while + * making changes. + */ + boolean active = false; + if ((parent != null) && (parent.activeService == this)) { + active = true; + parent.deactivateNestedService(); + } + + // Create the new submission + IHandler handler = new ActionHandler(action); + HandlerSubmission handlerSubmission = new HandlerSubmission(null, + workbenchPartSite.getShell(), workbenchPartSite, commandId, + handler, Priority.MEDIUM); + handlerSubmissionsByCommandId.put(commandId, handlerSubmission); + + // Either submit the new handler myself, or simply re-activate. + if (parent != null) { + if (active) { + parent.activateNestedService(this); + } + } else { + PlatformUI.getWorkbench().getCommandSupport() + .addHandlerSubmission(handlerSubmission); + } + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.INestableKeyBindingService#removeKeyBindingService(org.eclipse.ui.IWorkbenchSite) + */ + public boolean removeKeyBindingService(IWorkbenchSite nestedSite) { + if (disposed) { + return false; + } + + final IKeyBindingService service = (IKeyBindingService) nestedServices + .remove(nestedSite); + if (service == null) { + return false; + } + + if (service.equals(activeService)) { + deactivateNestedService(); + } + + return true; + } + + public void setScopes(String[] scopes) { + if (disposed) { + return; + } + + // Either deactivate myself, or remove the previous submissions myself. + boolean active = false; + if ((parent != null) && (parent.activeService == this)) { + active = true; + parent.deactivateNestedService(); + } else { + PlatformUI.getWorkbench().getContextSupport() + .removeEnabledSubmissions(enabledSubmissions); + } + enabledSubmissions.clear(); + + // Determine the new list of submissions. + enabledContextIds = new HashSet(Arrays.asList(scopes)); + for (Iterator iterator = enabledContextIds.iterator(); iterator + .hasNext();) { + String contextId = (String) iterator.next(); + enabledSubmissions.add(new EnabledSubmission(null, null, + workbenchPartSite, contextId)); + } + + // Submit the new contexts myself, or simply re-active myself. + if (parent != null) { + if (active) { + parent.activateNestedService(this); + } + } else { + PlatformUI.getWorkbench().getContextSupport().addEnabledSubmissions( + enabledSubmissions); + } + } + + public void unregisterAction(IAction action) { + if (disposed) { + return; + } + + if (action instanceof CommandLegacyActionWrapper) { + // this is a registration of a fake action for an already + // registered handler + WorkbenchPlugin + .log("Cannot unregister a CommandLegacyActionWrapper out of the system"); //$NON-NLS-1$ + return; + } + + String commandId = action.getActionDefinitionId(); + + if (commandId != null) { + // Deactivate this service while making changes. + boolean active = false; + if ((parent != null) && (parent.activeService == this)) { + active = true; + parent.deactivateNestedService(); + } + + // Remove the current submission, if any. + HandlerSubmission handlerSubmission = (HandlerSubmission) handlerSubmissionsByCommandId + .remove(commandId); + + /* + * Either activate this service again, or remove the submission + * myself. + */ + if (parent != null) { + if (active) { + parent.activateNestedService(this); + } + } else { + if (handlerSubmission != null) { + PlatformUI.getWorkbench().getCommandSupport() + .removeHandlerSubmission(handlerSubmission); + handlerSubmission.getHandler().dispose(); + } + } + } + } +} |