org.eclipse.ui.internal.KeyBindingService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of workbench Show documentation
Show all versions of workbench Show documentation
This plug-in contains the bulk of the Workbench implementation, and depends on JFace, SWT, and Core Runtime. It cannot be used independently from org.eclipse.ui. Workbench client plug-ins should not depend directly on this plug-in.
The newest version!
/*******************************************************************************
* Copyright (c) 2000, 2007 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.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 null
.
*/
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
* null
.
*/
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 null
.
*/
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 null
.
*/
private Map handlerSubmissionsByCommandId = new HashMap();
/**
* The context submissions from the currently active nested service. This
* value is null
if there is no currently active nested
* service.
*/
private List nestedEnabledSubmissions = null;
/**
* The handler submissions from the currently active nested service. This
* value is null
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 null
.
*/
private final Map nestedServices = new HashMap();
/**
* The parent for this key binding service; null
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 null
.
*/
private IWorkbenchPartSite workbenchPartSite;
/**
* Constructs a new instance of KeyBindingService
on a given
* workbench site. This instance is not nested.
*
* @param workbenchPartSite
* The site for which this service will be responsible; should
* not be null
.
*/
public KeyBindingService(IWorkbenchPartSite workbenchPartSite) {
this(workbenchPartSite, null);
}
/**
* Constructs a new instance of KeyBindingService
on a given
* workbench site.
*
* @param workbenchPartSite
* The site for which this service will be responsible; should
* not be null
.
* @param parent
* The parent key binding service, if any; null
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;
} else {
// Deactivate the currently active nested service.
deactivateNestedService();
return true;
}
}
// Attempt to activate a service.
final IKeyBindingService service = (IKeyBindingService) nestedServices
.get(nestedSite);
if (service == null) {
return false;
}
if (service == activeService) {
// The service is already active.
return false;
}
deactivateNestedService();
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 null
, then
* the reference to the active service is set to
* null
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);
Workbench.getInstance().getContextSupport().addEnabledSubmissions(
nestedEnabledSubmissions);
// Update the handlers.
nestedHandlerSubmissions = nestedService.getHandlerSubmissions();
normalizeSites(nestedHandlerSubmissions);
Workbench.getInstance().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.
Workbench.getInstance().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.
*/
Workbench.getInstance().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;
Workbench
.getInstance()
.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();
}
Workbench.getInstance().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
* null
.
*/
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
* null
.
*/
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
* destructive.
*
* @param submissionsToModify
* The submissions list to modify; must not be null
,
* 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 {
Workbench.getInstance().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 {
Workbench.getInstance().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 {
Workbench.getInstance().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) {
Workbench.getInstance().getCommandSupport()
.removeHandlerSubmission(handlerSubmission);
handlerSubmission.getHandler().dispose();
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy