/** * Copyright (c) 2015 by Brainwy Software Ltda. All Rights Reserved. * Licensed under1 the terms of the Eclipse Public License (EPL). * Please see the license.txt included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ package org.python.pydev.shared_ui.bindings; import java.util.HashSet; import java.util.Set; import org.eclipse.core.commands.CommandManager; import org.eclipse.core.commands.ParameterizedCommand; import org.eclipse.core.commands.common.NotDefinedException; import org.eclipse.core.commands.contexts.Context; import org.eclipse.core.commands.contexts.ContextManager; import org.eclipse.core.runtime.Assert; import org.eclipse.jface.bindings.Binding; import org.eclipse.jface.bindings.BindingManager; import org.eclipse.jface.bindings.Scheme; import org.eclipse.jface.bindings.keys.KeyBinding; import org.eclipse.jface.bindings.keys.KeySequence; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.contexts.IContextService; import org.eclipse.ui.keys.IBindingService; import org.python.pydev.shared_core.log.Log; /** * Eclipse has no real API to create a keybinding, so, what we're doing here is providing one * using the same approach that the KeysPreferencePage uses. */ public class BindKeysHelper { private final ContextManager contextManager = new ContextManager(); /** * A binding manager local to this helper. When it is * initialized, the current bindings are read out from the binding service * and placed in this manager. This manager is then updated as the user * makes changes. When the user has finished, the contents of this manager * are compared with the contents of the binding service. The changes are * then persisted. */ private final BindingManager localChangeManager = new BindingManager( contextManager, new CommandManager()); private final IBindingService bindingService; private final String contextId; private final Set<Object> initialState = new HashSet<>(); /** * @param contextId defines the keys context we'll work with... * * We'll only remove/add bindings to this context. */ public BindKeysHelper(String contextId) { Assert.isNotNull(contextId); this.contextId = contextId; // Set the context we're working with. Set<String> activeContextIds = new HashSet<>(); activeContextIds.add(contextId); contextManager.setActiveContextIds(activeContextIds); // Check that the context we're working with actually exists IWorkbench workbench = PlatformUI.getWorkbench(); bindingService = (IBindingService) workbench.getService(IBindingService.class); IContextService contextService = (IContextService) workbench.getService(IContextService.class); Context context = contextService.getContext(contextId); if (context == null || context.isDefined() == false) { throw new RuntimeException("The context: " + contextId + " does not exist."); } Scheme activeScheme = bindingService.getActiveScheme(); final Scheme[] definedSchemes = bindingService.getDefinedSchemes(); // Make a copy we can work with locally (we'll apply changes later based on this copy). try { for (int i = 0; i < definedSchemes.length; i++) { final Scheme scheme = definedSchemes[i]; final Scheme copy = localChangeManager.getScheme(scheme.getId()); copy.define(scheme.getName(), scheme.getDescription(), scheme.getParentId()); } localChangeManager.setActiveScheme(activeScheme); } catch (final NotDefinedException e) { throw new Error("There is a programmer error in the bind keys helper"); //$NON-NLS-1$ } localChangeManager.setLocale(bindingService.getLocale()); localChangeManager.setPlatform(bindingService.getPlatform()); Binding[] bindings = bindingService.getBindings(); for (Binding binding : bindings) { initialState.add(binding); } localChangeManager.setBindings(bindings); } /** * @param force if true, we'll create the user binding regardless of having some existing binding. Otherwise, * we'll not allow the creation if a binding already exists for it. * * Note: conflicting bindings should be removed before (through removeUserBindingsWithFilter). If they're * not removed, a conflict will be created in the bindings. */ public void addUserBindings(KeySequence keySequence, ParameterizedCommand command) throws Exception { Scheme activeScheme = bindingService.getActiveScheme(); String schemeId = activeScheme.getId(); localChangeManager.addBinding(new KeyBinding(keySequence, command, schemeId, contextId, null, null, null, Binding.USER)); } /** * Helper class to remove bindings. */ public static interface IFilter { boolean removeBinding(Binding binding); } /** * Removes any bindings which match the given filter. */ public void removeUserBindingsWithFilter(IFilter iFilter) { Binding[] bindings = localChangeManager.getBindings(); for (int i = 0; i < bindings.length; i++) { Binding binding = bindings[i]; // Note: we'll only work with the defined context! if (binding.getContextId().equals(this.contextId)) { if (iFilter.removeBinding(binding)) { localChangeManager.removeBinding(binding); } } } } /** * Saves the changes (if any change was done to the bindings). */ public void saveIfChanged() { try { Binding[] newBindings = localChangeManager.getBindings(); Set<Object> newState = new HashSet<>(); for (Binding binding : newBindings) { newState.add(binding); } if (newState.equals(initialState)) { return; } bindingService.savePreferences(localChangeManager.getActiveScheme(), newBindings); } catch (Exception e) { Log.log(e); } } }