| /******************************************************************************* |
| * Copyright (c) 2005, 2012 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.keys; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| 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 javax.inject.Inject; |
| import org.eclipse.core.commands.CommandManager; |
| import org.eclipse.core.commands.ParameterizedCommand; |
| import org.eclipse.core.commands.common.NotDefinedException; |
| import org.eclipse.e4.core.commands.ECommandService; |
| import org.eclipse.e4.core.contexts.IEclipseContext; |
| import org.eclipse.e4.core.di.annotations.Optional; |
| import org.eclipse.e4.ui.bindings.EBindingService; |
| import org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher; |
| import org.eclipse.e4.ui.model.application.MApplication; |
| import org.eclipse.e4.ui.model.application.commands.MBindingContext; |
| import org.eclipse.e4.ui.model.application.commands.MBindingTable; |
| import org.eclipse.e4.ui.model.application.commands.MCommand; |
| import org.eclipse.e4.ui.model.application.commands.MCommandsFactory; |
| import org.eclipse.e4.ui.model.application.commands.MKeyBinding; |
| import org.eclipse.e4.ui.model.application.commands.MParameter; |
| import org.eclipse.e4.ui.model.application.commands.impl.CommandsFactoryImpl; |
| import org.eclipse.jface.bindings.Binding; |
| import org.eclipse.jface.bindings.BindingManager; |
| import org.eclipse.jface.bindings.IBindingManagerListener; |
| import org.eclipse.jface.bindings.Scheme; |
| import org.eclipse.jface.bindings.TriggerSequence; |
| import org.eclipse.jface.bindings.keys.KeySequence; |
| import org.eclipse.jface.util.Util; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.ui.commands.ICommandService; |
| import org.eclipse.ui.internal.WorkbenchPlugin; |
| import org.eclipse.ui.keys.IBindingService; |
| |
| /** |
| * <p> |
| * Provides services related to the binding architecture (e.g., keyboard |
| * shortcuts) within the workbench. This service can be used to access the |
| * currently active bindings, as well as the current state of the binding |
| * architecture. |
| * </p> |
| * |
| * @since 3.1 |
| */ |
| public final class BindingService implements IBindingService { |
| |
| @Inject |
| private MApplication application; |
| |
| @Inject |
| private EBindingService bindingService; |
| |
| @Inject |
| private ECommandService commandService; |
| |
| @Inject |
| private CommandManager commandManager; |
| |
| @Inject |
| private BindingManager manager; |
| |
| @Inject |
| @Optional |
| private KeyBindingDispatcher dispatcher; |
| |
| private BindingPersistence bp; |
| |
| private Map<String, MBindingContext> bindingContexts = new HashMap<String, MBindingContext>(); |
| |
| private String[] activeSchemeIds; |
| |
| /** |
| * Key assist dialog for workbench key bindings, lazily created and cached |
| */ |
| private GlobalKeyAssistDialog keyAssistDialog; |
| |
| private IEclipseContext context; |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.services.IDisposable#dispose() |
| */ |
| public void dispose() { |
| bp.dispose(); |
| } |
| |
| @Inject |
| public void setContext(IEclipseContext context) { |
| this.context = context; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.ui.keys.IBindingService#addBindingManagerListener(org.eclipse |
| * .jface.bindings.IBindingManagerListener) |
| */ |
| public void addBindingManagerListener(IBindingManagerListener listener) { |
| manager.addBindingManagerListener(listener); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.ui.keys.IBindingService#removeBindingManagerListener(org. |
| * eclipse.jface.bindings.IBindingManagerListener) |
| */ |
| public void removeBindingManagerListener(IBindingManagerListener listener) { |
| manager.removeBindingManagerListener(listener); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.ui.keys.IBindingService#getActiveBindingsFor(org.eclipse. |
| * core.commands.ParameterizedCommand) |
| */ |
| public TriggerSequence[] getActiveBindingsFor(ParameterizedCommand parameterizedCommand) { |
| Collection<TriggerSequence> seq = bindingService.getSequencesFor(parameterizedCommand); |
| return seq.toArray(new TriggerSequence[seq.size()]); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.ui.keys.IBindingService#getActiveBindingsFor(java.lang.String |
| * ) |
| */ |
| public TriggerSequence[] getActiveBindingsFor(String commandId) { |
| return getActiveBindingsFor(commandService.createCommand(commandId, null)); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.keys.IBindingService#getActiveScheme() |
| */ |
| public Scheme getActiveScheme() { |
| return manager.getActiveScheme(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.ui.keys.IBindingService#getBestActiveBindingFor(org.eclipse |
| * .core.commands.ParameterizedCommand) |
| */ |
| public TriggerSequence getBestActiveBindingFor(ParameterizedCommand command) { |
| TriggerSequence seq = bindingService.getBestSequenceFor(command); |
| return seq; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.ui.keys.IBindingService#getBestActiveBindingFor(java.lang |
| * .String) |
| */ |
| public TriggerSequence getBestActiveBindingFor(String commandId) { |
| ParameterizedCommand cmd = commandService.createCommand(commandId, null); |
| return bindingService.getBestSequenceFor(cmd); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.ui.keys.IBindingService#getBestActiveBindingFormattedFor( |
| * java.lang.String) |
| */ |
| public String getBestActiveBindingFormattedFor(String commandId) { |
| TriggerSequence sequence = bindingService.getBestSequenceFor(commandService.createCommand( |
| commandId, null)); |
| return sequence == null ? null : sequence.format(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.keys.IBindingService#getBindings() |
| */ |
| public Binding[] getBindings() { |
| return manager.getBindings(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.keys.IBindingService#getBuffer() |
| */ |
| public TriggerSequence getBuffer() { |
| if (dispatcher == null) { |
| return KeySequence.getInstance(); |
| } |
| return dispatcher.getBuffer(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.keys.IBindingService#getDefaultSchemeId() |
| */ |
| public String getDefaultSchemeId() { |
| return BindingPersistence.getDefaultSchemeId(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.keys.IBindingService#getDefinedSchemes() |
| */ |
| public Scheme[] getDefinedSchemes() { |
| return manager.getDefinedSchemes(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.keys.IBindingService#getLocale() |
| */ |
| public String getLocale() { |
| return manager.getLocale(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.ui.keys.IBindingService#getPartialMatches(org.eclipse.jface |
| * .bindings.TriggerSequence) |
| */ |
| public Map getPartialMatches(TriggerSequence trigger) { |
| final TriggerSequence[] prefixes = trigger.getPrefixes(); |
| final int prefixesLength = prefixes.length; |
| if (prefixesLength == 0) { |
| return Collections.EMPTY_MAP; |
| } |
| |
| Collection<Binding> partialMatches = bindingService.getPartialMatches(trigger); |
| Map<TriggerSequence, Object> prefixTable = new HashMap<TriggerSequence, Object>(); |
| for (Binding binding : partialMatches) { |
| for (int i = 0; i < prefixesLength; i++) { |
| final TriggerSequence prefix = prefixes[i]; |
| final Object value = prefixTable.get(prefix); |
| if ((prefixTable.containsKey(prefix)) && (value instanceof Map)) { |
| ((Map) value).put(prefixTable, binding); |
| } else { |
| final Map map = new HashMap(); |
| prefixTable.put(prefix, map); |
| map.put(prefixTable, binding); |
| } |
| } |
| } |
| return prefixTable; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.ui.keys.IBindingService#getPerfectMatch(org.eclipse.jface |
| * .bindings.TriggerSequence) |
| */ |
| public Binding getPerfectMatch(TriggerSequence trigger) { |
| return bindingService.getPerfectMatch(trigger); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.keys.IBindingService#getPlatform() |
| */ |
| public String getPlatform() { |
| return Util.getWS(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.keys.IBindingService#getScheme(java.lang.String) |
| */ |
| public Scheme getScheme(String schemeId) { |
| return manager.getScheme(schemeId); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.keys.IBindingService#isKeyFilterEnabled() |
| */ |
| public boolean isKeyFilterEnabled() { |
| return dispatcher == null ? false : dispatcher.getKeyDownFilter().isEnabled(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.ui.keys.IBindingService#isPartialMatch(org.eclipse.jface. |
| * bindings.TriggerSequence) |
| */ |
| public boolean isPartialMatch(TriggerSequence trigger) { |
| return bindingService.isPartialMatch(trigger); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.ui.keys.IBindingService#isPerfectMatch(org.eclipse.jface. |
| * bindings.TriggerSequence) |
| */ |
| public boolean isPerfectMatch(TriggerSequence trigger) { |
| return bindingService.isPerfectMatch(trigger); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.keys.IBindingService#openKeyAssistDialog() |
| */ |
| public void openKeyAssistDialog() { |
| if (keyAssistDialog == null) { |
| Display.getCurrent(); |
| keyAssistDialog = new GlobalKeyAssistDialog(context, dispatcher); |
| } |
| if (keyAssistDialog.getShell() == null) { |
| keyAssistDialog.setParentShell(Display.getCurrent().getActiveShell()); |
| } |
| keyAssistDialog.open(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.ui.keys.IBindingService#readRegistryAndPreferences(org.eclipse |
| * .ui.commands.ICommandService) |
| */ |
| public void readRegistryAndPreferences(ICommandService commandService) { |
| if (bp == null) { |
| bp = new BindingPersistence(manager, commandManager) { |
| @Override |
| public void reRead() { |
| super.reRead(); |
| // after having read the registry and preferences, persist |
| // and update the model |
| persistToModel(manager.getActiveScheme()); |
| } |
| }; |
| } |
| bp.read(); |
| } |
| |
| private void saveLegacyPreferences(Scheme activeScheme, Binding[] bindings) throws IOException { |
| BindingPersistence.write(activeScheme, bindings); |
| try { |
| manager.setActiveScheme(activeScheme); |
| } catch (final NotDefinedException e) { |
| WorkbenchPlugin.log("The active scheme is not currently defined.", //$NON-NLS-1$ |
| WorkbenchPlugin.getStatus(e)); |
| } |
| manager.setBindings(bindings); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.ui.keys.IBindingService#savePreferences(org.eclipse.jface |
| * .bindings.Scheme, org.eclipse.jface.bindings.Binding[]) |
| */ |
| public void savePreferences(Scheme activeScheme, Binding[] bindings) throws IOException { |
| saveLegacyPreferences(activeScheme, bindings); |
| persistToModel(activeScheme); |
| } |
| |
| private void persistToModel(Scheme activeScheme) { |
| // save the active scheme to the model |
| writeSchemeToModel(activeScheme); |
| activeSchemeIds = getSchemeIds(activeScheme.getId()); |
| |
| // weeds out any of the deleted system bindings using the binding |
| // manager |
| HashSet<Binding> activeBindings = new HashSet<Binding>( |
| manager.getActiveBindingsDisregardingContextFlat()); |
| |
| // get all of the (active) model bindings that point to the actual runtime |
| // bindings |
| HashMap<Binding, MKeyBinding> bindingToKey = new HashMap<Binding, MKeyBinding>(); |
| for (MBindingTable table : application.getBindingTables()) { |
| for (MKeyBinding modelBinding : table.getBindings()) { |
| final Object obj = modelBinding.getTransientData().get( |
| EBindingService.MODEL_TO_BINDING_KEY); |
| if (obj instanceof Binding) { |
| bindingToKey.put((Binding) obj, modelBinding); |
| } |
| } |
| } |
| |
| // go through each of the (active) bindings in the model to see if there are any |
| // bindings that we should remove |
| final HashSet<Binding> deleted = new HashSet<Binding>(bindingToKey.keySet()); |
| deleted.removeAll(activeBindings); |
| for (Binding binding : deleted) { |
| if (binding.getType() == Binding.USER) { |
| removeBinding(binding); |
| } else { |
| final MKeyBinding model = bindingToKey.get(binding); |
| if (!model.getTags().contains(EBindingService.DELETED_BINDING_TAG)) { |
| model.getTags().add(EBindingService.DELETED_BINDING_TAG); |
| } |
| } |
| } |
| |
| // go through each of the active bindings (from the binding manager) to |
| // see if there are any bindings that we should add to the runtime |
| for (Binding binding : activeBindings) { |
| final MKeyBinding model = bindingToKey.get(binding); |
| MKeyBinding toAddModel = model; |
| Binding toAddBinding = binding; |
| |
| // if we've switched schemes then we need to check to see if we |
| // should override any of the old bindings |
| final Binding conflict = bindingService.getPerfectMatch(binding.getTriggerSequence()); |
| |
| if (conflict != null && conflict.getContextId().equals(binding.getContextId())) { |
| final int rc = compareTo(conflict, binding); |
| if (rc < 0) { |
| // we need to delete the existing binding |
| final MKeyBinding conflictModel = bindingToKey.get(conflict); |
| if (conflict.getType() == Binding.USER) { |
| removeBinding(conflict); |
| } else if (conflictModel != null) { |
| if (!conflictModel.getTags().contains(EBindingService.DELETED_BINDING_TAG)) { |
| conflictModel.getTags().add(EBindingService.DELETED_BINDING_TAG); |
| } |
| } |
| } else if (rc > 0) { |
| // the existing binding is correct |
| // we need to delete the new binding |
| if (binding.getType() == Binding.USER) { |
| removeBinding(binding); |
| } else if (model != null) { |
| if (!model.getTags().contains(EBindingService.DELETED_BINDING_TAG)) { |
| model.getTags().add(EBindingService.DELETED_BINDING_TAG); |
| } |
| } |
| // make sure we don't re-add them |
| toAddModel = null; |
| toAddBinding = null; |
| } |
| } |
| if (toAddModel != null) { |
| if (toAddModel.getTags().contains(EBindingService.DELETED_BINDING_TAG)) { |
| toAddModel.getTags().remove(EBindingService.DELETED_BINDING_TAG); |
| } |
| } else if (toAddBinding != null) { |
| addBinding(toAddBinding); |
| } |
| |
| } |
| } |
| |
| private final String[] getSchemeIds(String schemeId) { |
| final List<String> strings = new ArrayList<String>(); |
| while (schemeId != null) { |
| strings.add(schemeId); |
| try { |
| schemeId = getScheme(schemeId).getParentId(); |
| } catch (final NotDefinedException e) { |
| return new String[0]; |
| } |
| } |
| |
| return strings.toArray(new String[strings.size()]); |
| } |
| |
| /* |
| * Copied from |
| * org.eclipse.jface.bindings.BindingManager.compareSchemes(String, String) |
| * |
| * Returns an in based on scheme 1 < scheme 2 |
| */ |
| private final int compareSchemes(final String schemeId1, final String schemeId2) { |
| if (activeSchemeIds == null) { |
| return 0; |
| } |
| if (!schemeId2.equals(schemeId1)) { |
| for (int i = 0; i < activeSchemeIds.length; i++) { |
| final String schemePointer = activeSchemeIds[i]; |
| if (schemeId2.equals(schemePointer)) { |
| return 1; |
| } else if (schemeId1.equals(schemePointer)) { |
| return -1; |
| } |
| } |
| } |
| return 0; |
| } |
| |
| /** |
| * Compare 2 bindings, taking into account Scheme and type. |
| * |
| * @param current |
| * the existing binding |
| * @param addition |
| * the incoming binding |
| * @return an int indicating current > addition |
| */ |
| private int compareTo(Binding current, Binding addition) { |
| final Scheme s1 = manager.getScheme(current.getSchemeId()); |
| final Scheme s2 = manager.getScheme(addition.getSchemeId()); |
| if (!s1.equals(s2)) { |
| int rc = compareSchemes(s1.getId(), s2.getId()); |
| if (rc != 0) { |
| // this is because the compare is inverted |
| return rc > 0 ? -1 : 1; |
| } |
| } |
| return current.getType() - addition.getType(); |
| } |
| |
| |
| private void writeSchemeToModel(Scheme activeScheme) { |
| List<String> tags = application.getTags(); |
| boolean found = false; |
| // replace the old scheme id |
| Iterator<String> i = tags.iterator(); |
| while (i.hasNext() && !found) { |
| String tag = i.next(); |
| if (tag.startsWith(EBindingService.ACTIVE_SCHEME_TAG)) { |
| i.remove(); |
| found = true; |
| } |
| } |
| tags.add(EBindingService.ACTIVE_SCHEME_TAG + ":" + activeScheme.getId()); //$NON-NLS-1$ |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.keys.IBindingService#setKeyFilterEnabled(boolean) |
| */ |
| public void setKeyFilterEnabled(boolean enabled) { |
| if (dispatcher != null) { |
| dispatcher.getKeyDownFilter().setEnabled(enabled); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.ui.keys.IBindingService#getConflictsFor(org.eclipse.jface |
| * .bindings.TriggerSequence) |
| */ |
| public Collection<Binding> getConflictsFor(TriggerSequence sequence) { |
| return bindingService.getConflictsFor(sequence); |
| } |
| |
| public MBindingContext getBindingContext(String id) { |
| // cache |
| MBindingContext result = bindingContexts.get(id); |
| if (result == null) { |
| // search |
| result = searchContexts(id, application.getRootContext()); |
| if (result == null) { |
| // create |
| result = MCommandsFactory.INSTANCE.createBindingContext(); |
| result.setElementId(id); |
| result.setName("Auto::" + id); //$NON-NLS-1$ |
| application.getRootContext().add(result); |
| } |
| if (result != null) { |
| bindingContexts.put(id, result); |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * @param id |
| * @param rootContext |
| * @return |
| */ |
| private MBindingContext searchContexts(String id, List<MBindingContext> rootContext) { |
| for (MBindingContext context : rootContext) { |
| if (context.getElementId().equals(id)) { |
| return context; |
| } |
| MBindingContext result = searchContexts(id, context.getChildren()); |
| if (result != null) { |
| return result; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * TODO Promote this method to API. |
| * <p> |
| * Adds a single new binding to the existing array of bindings. If the array |
| * is currently <code>null</code>, then a new array is created and this |
| * binding is added to it. This method does not detect duplicates. |
| * </p> |
| * <p> |
| * This method completes in amortized <code>O(1)</code>. |
| * </p> |
| * |
| * @param binding |
| * The binding to be added; must not be <code>null</code>. |
| */ |
| public final void addBinding(final Binding binding) { |
| MBindingTable table = getMTable(binding.getContextId()); |
| createORupdateMKeyBinding(application, table, binding); |
| } |
| |
| /** |
| * @param contextId |
| * @return |
| */ |
| private MBindingTable getMTable(String contextId) { |
| for (MBindingTable bt : application.getBindingTables()) { |
| if (bt.getBindingContext().getElementId().equals(contextId)) { |
| return bt; |
| } |
| } |
| // create a new table if we couldn't find one |
| MBindingTable table = CommandsFactoryImpl.eINSTANCE.createBindingTable(); |
| table.setBindingContext(getBindingContext(contextId)); |
| table.setElementId(contextId); |
| application.getBindingTables().add(table); |
| return table; |
| |
| } |
| |
| static private boolean isSameBinding(MKeyBinding existingBinding, MCommand cmd, Binding binding) { |
| // see org.eclipse.jface.bindings.Binding#equals(final Object object) |
| if (!cmd.equals(existingBinding.getCommand())) |
| return false; |
| String existingKeySequence = existingBinding.getKeySequence(); |
| if (existingKeySequence == null) |
| return false; |
| if (!existingKeySequence.equals(binding.getTriggerSequence().format())) |
| return false; |
| |
| // tags to look for: |
| ArrayList<String> expectedTagList = new ArrayList<String>(4); |
| |
| String schemeId = binding.getSchemeId(); |
| if (schemeId != null && !schemeId.equals(BindingPersistence.getDefaultSchemeId())) { |
| expectedTagList.add(EBindingService.SCHEME_ID_ATTR_TAG + ":" + schemeId); //$NON-NLS-1$ |
| } |
| String locale = binding.getLocale(); |
| if (locale != null) { |
| expectedTagList.add(EBindingService.LOCALE_ATTR_TAG + ":" + locale); //$NON-NLS-1$ |
| } |
| String platform = binding.getPlatform(); |
| if (platform != null) { |
| expectedTagList.add(EBindingService.PLATFORM_ATTR_TAG + ":" + platform); //$NON-NLS-1$ |
| } |
| if (binding.getType() == Binding.USER) { |
| expectedTagList.add(EBindingService.TYPE_ATTR_TAG + ":user"); //$NON-NLS-1$ |
| } |
| return existingBinding.getTags().equals(expectedTagList); |
| } |
| |
| // TBD the "update" procedure should not typically be run. |
| // Add some sort of timestamp on the source files and update |
| // only when it changes |
| // TBD placement: this should be in the "3.x bridge" code |
| static public MKeyBinding createORupdateMKeyBinding(MApplication application, |
| MBindingTable table, |
| Binding binding) { |
| boolean addToTable = false; |
| |
| ParameterizedCommand parmCmd = binding.getParameterizedCommand(); |
| |
| String id = parmCmd.getId(); |
| MCommand cmd = null; |
| for (MCommand appCommand : application.getCommands()) { |
| if (id.equals(appCommand.getElementId())) { |
| cmd = appCommand; |
| break; |
| } |
| } |
| if (cmd == null) { |
| return null; |
| } |
| |
| MKeyBinding keyBinding = null; |
| for (MKeyBinding existingBinding : table.getBindings()) { |
| Binding b = (Binding) existingBinding.getTransientData().get( |
| EBindingService.MODEL_TO_BINDING_KEY); |
| if (binding.equals(b)) { |
| keyBinding = existingBinding; |
| break; |
| } |
| if (isSameBinding(existingBinding, cmd, binding)) { |
| keyBinding = existingBinding; |
| break; |
| } |
| } |
| |
| if (keyBinding == null) { |
| addToTable = true; |
| keyBinding = CommandsFactoryImpl.eINSTANCE.createKeyBinding(); |
| keyBinding.setCommand(cmd); |
| } |
| keyBinding.setKeySequence(binding.getTriggerSequence().format()); |
| |
| for (Object obj : parmCmd.getParameterMap().entrySet()) { |
| @SuppressWarnings({ "unchecked" }) |
| Map.Entry<String, String> entry = (Map.Entry<String, String>) obj; |
| |
| String paramID = entry.getKey(); |
| if (paramID == null) |
| continue; |
| List<MParameter> bindingParams = keyBinding.getParameters(); |
| MParameter p = null; |
| for (MParameter param : bindingParams) { |
| if (paramID.equals(param.getElementId())) { |
| p = param; |
| break; |
| } |
| } |
| if (p == null) { |
| p = CommandsFactoryImpl.eINSTANCE.createParameter(); |
| p.setElementId(entry.getKey()); |
| keyBinding.getParameters().add(p); |
| } |
| p.setName(entry.getKey()); |
| p.setValue(entry.getValue()); |
| } |
| |
| List<String> tags = keyBinding.getTags(); |
| // just add the 'schemeId' tag if the binding is for anything other than |
| // the default scheme |
| if (binding.getSchemeId() != null |
| && !binding.getSchemeId().equals(BindingPersistence.getDefaultSchemeId())) { |
| tags.add(EBindingService.SCHEME_ID_ATTR_TAG + ":" + binding.getSchemeId()); //$NON-NLS-1$ |
| } |
| if (binding.getLocale() != null) { |
| tags.add(EBindingService.LOCALE_ATTR_TAG + ":" + binding.getLocale()); //$NON-NLS-1$ |
| } |
| if (binding.getPlatform() != null) { |
| tags.add(EBindingService.PLATFORM_ATTR_TAG + ":" + binding.getPlatform()); //$NON-NLS-1$ |
| } |
| // just add the 'type' tag if it's a user binding |
| if (binding.getType() == Binding.USER) { |
| tags.add(EBindingService.TYPE_ATTR_TAG + ":user"); //$NON-NLS-1$ |
| } |
| keyBinding.getTransientData().put(EBindingService.MODEL_TO_BINDING_KEY, binding); |
| if (addToTable) { |
| table.getBindings().add(keyBinding); |
| } |
| return keyBinding; |
| } |
| |
| private MKeyBinding findMKeyBinding(MBindingTable table, Binding binding) { |
| List<MKeyBinding> mBindings = table.getBindings(); |
| |
| String bindingSchemeId = binding.getSchemeId() == null ? IBindingService.DEFAULT_DEFAULT_ACTIVE_SCHEME_ID |
| : binding.getSchemeId(); |
| |
| if (binding.getParameterizedCommand() != null) { |
| String commandId = binding.getParameterizedCommand().getId(); |
| |
| for (MKeyBinding curr : mBindings) { |
| Binding transientBinding = (Binding) curr.getTransientData().get( |
| EBindingService.MODEL_TO_BINDING_KEY); |
| if (transientBinding != null) { |
| if (binding.equals(transientBinding)) { |
| return curr; |
| } |
| continue; |
| } |
| // check equality |
| if (curr.getKeySequence().equals(binding.getTriggerSequence().format()) |
| && curr.getCommand() != null |
| && curr.getCommand().getElementId().equals(commandId)) { |
| |
| String schemeId = IBindingService.DEFAULT_DEFAULT_ACTIVE_SCHEME_ID; |
| List<String> tags = curr.getTags(); |
| // grab the scheme id from the tags |
| for (String tag : tags) { |
| if (tag.startsWith(EBindingService.SCHEME_ID_ATTR_TAG)) { |
| schemeId = tag.substring(9); |
| break; |
| } |
| } |
| // if the scheme ids are the same, then we found the |
| // MKeyBinding |
| if (schemeId.equals(bindingSchemeId)) { |
| return curr; |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Remove the specific binding by identity. Does nothing if the binding is |
| * not in the manager. |
| * |
| * @param binding |
| * The binding to be removed; must not be <code>null</code>. |
| */ |
| public final void removeBinding(final Binding binding) { |
| MKeyBinding mKeyBinding; |
| MBindingTable table = null; |
| for (MBindingTable bt : application.getBindingTables()) { |
| if (bt.getBindingContext().getElementId().equals(binding.getContextId())) { |
| table = bt; |
| break; |
| } |
| } |
| if (table == null) { |
| return; |
| } |
| |
| // if we're removing a user binding, just remove it from the model and |
| // the listeners will take care of removing the binding from the runtime |
| // system |
| if (binding.getType() == Binding.USER) { |
| mKeyBinding = this.findMKeyBinding(table, binding); |
| if (mKeyBinding != null) { |
| table.getBindings().remove(mKeyBinding); |
| } |
| } |
| // if we're removing a system binding, then find the model binding, add |
| // a 'deleted' tag, and explicitly remove the binding from the runtime |
| // system |
| else { |
| mKeyBinding = this.findMKeyBinding(table, binding); |
| if (mKeyBinding != null) { |
| mKeyBinding.getTags().add(EBindingService.DELETED_BINDING_TAG); |
| } |
| } |
| } |
| |
| public BindingManager getBindingManager() { |
| return manager; |
| } |
| |
| public Collection<Binding> getActiveBindings() { |
| return bindingService.getActiveBindings(); |
| } |
| |
| public WorkbenchKeyboard getKeyboard() { |
| return new WorkbenchKeyboard(dispatcher); |
| } |
| } |