| /******************************************************************************* |
| * 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.keys; |
| |
| import java.io.IOException; |
| import java.io.Reader; |
| import java.io.StringReader; |
| import java.io.StringWriter; |
| import java.io.Writer; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.StringTokenizer; |
| import org.eclipse.core.commands.Command; |
| import org.eclipse.core.commands.CommandManager; |
| import org.eclipse.core.commands.ParameterizedCommand; |
| import org.eclipse.core.commands.common.HandleObject; |
| import org.eclipse.core.commands.common.NotDefinedException; |
| import org.eclipse.core.commands.util.Tracing; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtension; |
| 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.jface.bindings.Binding; |
| import org.eclipse.jface.bindings.BindingManager; |
| import org.eclipse.jface.bindings.Scheme; |
| import org.eclipse.jface.bindings.keys.IKeyLookup; |
| import org.eclipse.jface.bindings.keys.KeyBinding; |
| import org.eclipse.jface.bindings.keys.KeyLookupFactory; |
| import org.eclipse.jface.bindings.keys.KeySequence; |
| import org.eclipse.jface.bindings.keys.KeyStroke; |
| import org.eclipse.jface.bindings.keys.ParseException; |
| import org.eclipse.jface.bindings.keys.SWTKeySupport; |
| import org.eclipse.jface.contexts.IContextIds; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.jface.util.Util; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.ui.IMemento; |
| import org.eclipse.ui.IWorkbenchPreferenceConstants; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.WorkbenchException; |
| import org.eclipse.ui.XMLMemento; |
| import org.eclipse.ui.internal.ShowViewMenu; |
| import org.eclipse.ui.internal.WorkbenchPlugin; |
| import org.eclipse.ui.internal.misc.Policy; |
| import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants; |
| import org.eclipse.ui.internal.services.PreferencePersistence; |
| import org.eclipse.ui.keys.IBindingService; |
| |
| /** |
| * <p> |
| * A static class for accessing the registry and the preference store. |
| * </p> |
| * |
| * @since 3.1 |
| */ |
| public class BindingPersistence extends PreferencePersistence { |
| |
| /** |
| * Whether this class should print out debugging information when it reads in |
| * data, or writes to the preference store. |
| */ |
| private static final boolean DEBUG = Policy.DEBUG_KEY_BINDINGS; |
| |
| /** |
| * The index of the active scheme configuration elements in the indexed array. |
| * |
| * @see BindingPersistence#read() |
| */ |
| private static final int INDEX_ACTIVE_SCHEME = 0; |
| |
| /** |
| * The index of the binding definition configuration elements in the indexed |
| * array. |
| * |
| * @see BindingPersistence#read() |
| */ |
| private static final int INDEX_BINDING_DEFINITIONS = 1; |
| |
| /** |
| * The index of the scheme definition configuration elements in the indexed |
| * array. |
| * |
| * @see BindingPersistence#read() |
| */ |
| private static final int INDEX_SCHEME_DEFINITIONS = 2; |
| |
| /** |
| * The name of the default scope in 2.1.x. |
| */ |
| private static final String LEGACY_DEFAULT_SCOPE = "org.eclipse.ui.globalScope"; //$NON-NLS-1$ |
| |
| /** |
| * A look-up map for 2.1.x style <code>string</code> keys on a |
| * <code>keyBinding</code> element. |
| */ |
| private static final Map<String, Integer> r2_1KeysByName = new HashMap<>(); |
| |
| static { |
| final IKeyLookup lookup = KeyLookupFactory.getDefault(); |
| r2_1KeysByName.put(IKeyLookup.BACKSPACE_NAME, lookup.formalKeyLookupInteger(IKeyLookup.BACKSPACE_NAME)); |
| r2_1KeysByName.put(IKeyLookup.TAB_NAME, lookup.formalKeyLookupInteger(IKeyLookup.TAB_NAME)); |
| r2_1KeysByName.put(IKeyLookup.RETURN_NAME, lookup.formalKeyLookupInteger(IKeyLookup.RETURN_NAME)); |
| r2_1KeysByName.put(IKeyLookup.ENTER_NAME, lookup.formalKeyLookupInteger(IKeyLookup.ENTER_NAME)); |
| r2_1KeysByName.put(IKeyLookup.ESCAPE_NAME, lookup.formalKeyLookupInteger(IKeyLookup.ESCAPE_NAME)); |
| r2_1KeysByName.put(IKeyLookup.ESC_NAME, lookup.formalKeyLookupInteger(IKeyLookup.ESC_NAME)); |
| r2_1KeysByName.put(IKeyLookup.DELETE_NAME, lookup.formalKeyLookupInteger(IKeyLookup.DELETE_NAME)); |
| r2_1KeysByName.put(IKeyLookup.SPACE_NAME, lookup.formalKeyLookupInteger(IKeyLookup.SPACE_NAME)); |
| r2_1KeysByName.put(IKeyLookup.ARROW_UP_NAME, lookup.formalKeyLookupInteger(IKeyLookup.ARROW_UP_NAME)); |
| r2_1KeysByName.put(IKeyLookup.ARROW_DOWN_NAME, lookup.formalKeyLookupInteger(IKeyLookup.ARROW_DOWN_NAME)); |
| r2_1KeysByName.put(IKeyLookup.ARROW_LEFT_NAME, lookup.formalKeyLookupInteger(IKeyLookup.ARROW_LEFT_NAME)); |
| r2_1KeysByName.put(IKeyLookup.ARROW_RIGHT_NAME, lookup.formalKeyLookupInteger(IKeyLookup.ARROW_RIGHT_NAME)); |
| r2_1KeysByName.put(IKeyLookup.PAGE_UP_NAME, lookup.formalKeyLookupInteger(IKeyLookup.PAGE_UP_NAME)); |
| r2_1KeysByName.put(IKeyLookup.PAGE_DOWN_NAME, lookup.formalKeyLookupInteger(IKeyLookup.PAGE_DOWN_NAME)); |
| r2_1KeysByName.put(IKeyLookup.HOME_NAME, lookup.formalKeyLookupInteger(IKeyLookup.HOME_NAME)); |
| r2_1KeysByName.put(IKeyLookup.END_NAME, lookup.formalKeyLookupInteger(IKeyLookup.END_NAME)); |
| r2_1KeysByName.put(IKeyLookup.INSERT_NAME, lookup.formalKeyLookupInteger(IKeyLookup.INSERT_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F1_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F1_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F2_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F2_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F3_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F3_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F4_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F4_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F5_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F5_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F6_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F6_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F7_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F7_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F8_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F8_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F9_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F9_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F10_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F10_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F11_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F11_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F12_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F12_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F13_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F13_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F14_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F14_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F15_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F15_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F16_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F16_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F17_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F17_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F18_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F18_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F19_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F19_NAME)); |
| r2_1KeysByName.put(IKeyLookup.F20_NAME, lookup.formalKeyLookupInteger(IKeyLookup.F20_NAME)); |
| } |
| |
| /** |
| * Converts a 2.1.x style key sequence (as parsed from the <code>string</code> |
| * attribute of the <code>keyBinding</code>) to a 3.1 key sequence. |
| * |
| * @param r21KeySequence The sequence of 2.1.x key strokes that should be |
| * converted into a 3.1 key sequence; never |
| * <code>null</code>. |
| * @return A 3.1 key sequence; never <code>null</code>. |
| */ |
| private static final KeySequence convert2_1Sequence(int[] r21KeySequence) { |
| final int r21KeySequenceLength = r21KeySequence.length; |
| final KeyStroke[] keyStrokes = new KeyStroke[r21KeySequenceLength]; |
| for (int i = 0; i < r21KeySequenceLength; i++) { |
| keyStrokes[i] = convert2_1Stroke(r21KeySequence[i]); |
| } |
| |
| return KeySequence.getInstance(keyStrokes); |
| } |
| |
| /** |
| * Converts a 2.1.x style key stroke (as parsed from the <code>string</code> |
| * attribute of the <code>keyBinding</code> to a 3.1 key stroke. |
| * |
| * @param r21Stroke The 2.1.x stroke to convert; must never be |
| * <code>null</code>. |
| * @return A 3.1 key stroke; never <code>null</code>. |
| */ |
| private static final KeyStroke convert2_1Stroke(final int r21Stroke) { |
| return SWTKeySupport.convertAcceleratorToKeyStroke(r21Stroke); |
| } |
| |
| /** |
| * Returns the default scheme identifier for the currently running application. |
| * |
| * @return The default scheme identifier (<code>String</code>); never |
| * <code>null</code>, but may be empty or point to an undefined scheme. |
| */ |
| public static final String getDefaultSchemeId() { |
| final IPreferenceStore store = PlatformUI.getPreferenceStore(); |
| return store.getDefaultString(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID); |
| } |
| |
| /** |
| * Parses a 2.1.x <code>string</code> attribute of the <code>keyBinding</code> |
| * element. |
| * |
| * @param string The string to parse; must not be <code>null</code>. |
| * @return An array of integer values -- each integer representing a single key |
| * stroke. This array may be empty, but it is never <code>null</code>. |
| */ |
| private static final int[] parse2_1Sequence(final String string) { |
| final StringTokenizer stringTokenizer = new StringTokenizer(string); |
| final int length = stringTokenizer.countTokens(); |
| final int[] strokes = new int[length]; |
| |
| for (int i = 0; i < length; i++) { |
| strokes[i] = parse2_1Stroke(stringTokenizer.nextToken()); |
| } |
| |
| return strokes; |
| } |
| |
| /** |
| * Parses a single 2.1.x key stroke string, as provided by |
| * <code>parse2_1Sequence</code>. |
| * |
| * @param string The string to parse; must not be <code>null</code>. |
| * @return An single integer value representing this key stroke. |
| */ |
| private static final int parse2_1Stroke(final String string) { |
| final StringTokenizer stringTokenizer = new StringTokenizer(string, KeyStroke.KEY_DELIMITER, true); |
| |
| // Copy out the tokens so we have random access. |
| final int size = stringTokenizer.countTokens(); |
| final String[] tokens = new String[size]; |
| for (int i = 0; stringTokenizer.hasMoreTokens(); i++) { |
| tokens[i] = stringTokenizer.nextToken(); |
| } |
| |
| int value = 0; |
| if (size % 2 == 1) { |
| String token = tokens[size - 1]; |
| final Integer integer = r2_1KeysByName.get(token.toUpperCase(Locale.ENGLISH)); |
| |
| if (integer != null) { |
| value = integer.intValue(); |
| } else if (token.length() == 1) { |
| value = token.toUpperCase().charAt(0); |
| } |
| |
| if (value != 0) { |
| for (int i = 0; i < size - 1; i++) { |
| token = tokens[i]; |
| |
| if (i % 2 == 0) { |
| if (token.equalsIgnoreCase(IKeyLookup.CTRL_NAME)) { |
| if ((value & SWT.CTRL) != 0) { |
| return 0; |
| } |
| |
| value |= SWT.CTRL; |
| |
| } else if (token.equalsIgnoreCase(IKeyLookup.ALT_NAME)) { |
| if ((value & SWT.ALT) != 0) { |
| return 0; |
| } |
| |
| value |= SWT.ALT; |
| |
| } else if (token.equalsIgnoreCase(IKeyLookup.SHIFT_NAME)) { |
| if ((value & SWT.SHIFT) != 0) { |
| return 0; |
| } |
| |
| value |= SWT.SHIFT; |
| |
| } else if (token.equalsIgnoreCase(IKeyLookup.COMMAND_NAME)) { |
| if ((value & SWT.COMMAND) != 0) { |
| return 0; |
| } |
| |
| value |= SWT.COMMAND; |
| |
| } else { |
| return 0; |
| |
| } |
| |
| } else if (!KeyStroke.KEY_DELIMITER.equals(token)) { |
| return 0; |
| } |
| } |
| } |
| } |
| |
| return value; |
| } |
| |
| /** |
| * <p> |
| * Reads the registry and the preference store, and determines the identifier |
| * for the scheme that should be active. There is a complicated order of |
| * priorities for this. The registry will only be read if there is no user |
| * preference, and the default active scheme id is different than the default |
| * default active scheme id. |
| * </p> |
| * <ol> |
| * <li>A non-default preference.</li> |
| * <li>The legacy preference XML memento.</li> |
| * <li>A default preference value that is different than the default default |
| * active scheme id.</li> |
| * <li>The registry.</li> |
| * <li>The default default active scheme id.</li> |
| * </ol> |
| * |
| * @param configurationElements The configuration elements from the commands |
| * extension point; must not be |
| * <code>null</code>. |
| * @param configurationElementCount The number of configuration elements that |
| * are really in the array. |
| * @param preferences The memento wrapping the commands preference |
| * key; may be <code>null</code>. |
| * @param bindingManager The binding manager that should be updated |
| * with the active scheme. This binding manager |
| * must already have its schemes defined. This |
| * value must not be <code>null</code>. |
| */ |
| private static final void readActiveScheme(final IConfigurationElement[] configurationElements, |
| final int configurationElementCount, final IMemento preferences, final BindingManager bindingManager) { |
| // A non-default preference. |
| final IPreferenceStore store = PlatformUI.getPreferenceStore(); |
| final String defaultActiveSchemeId = store.getDefaultString(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID); |
| final String preferenceActiveSchemeId = store.getString(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID); |
| if ((preferenceActiveSchemeId != null) && (!preferenceActiveSchemeId.equals(defaultActiveSchemeId))) { |
| try { |
| bindingManager.setActiveScheme(bindingManager.getScheme(preferenceActiveSchemeId)); |
| return; |
| } catch (final NotDefinedException e) { |
| // Let's keep looking.... |
| } |
| } |
| |
| // A legacy preference XML memento. |
| if (preferences != null) { |
| final IMemento[] preferenceMementos = preferences.getChildren(TAG_ACTIVE_KEY_CONFIGURATION); |
| int preferenceMementoCount = preferenceMementos.length; |
| for (int i = preferenceMementoCount - 1; i >= 0; i--) { |
| final IMemento memento = preferenceMementos[i]; |
| String id = memento.getString(ATT_KEY_CONFIGURATION_ID); |
| if (id != null) { |
| try { |
| bindingManager.setActiveScheme(bindingManager.getScheme(id)); |
| return; |
| } catch (final NotDefinedException e) { |
| // Let's keep looking.... |
| } |
| } |
| } |
| } |
| |
| // A default preference value that is different than the default. |
| if ((defaultActiveSchemeId != null && defaultActiveSchemeId.length() > 0) |
| && (!defaultActiveSchemeId.equals(IBindingService.DEFAULT_DEFAULT_ACTIVE_SCHEME_ID))) { |
| try { |
| bindingManager.setActiveScheme(bindingManager.getScheme(defaultActiveSchemeId)); |
| return; |
| } catch (final NotDefinedException e) { |
| // Let's keep looking.... |
| } |
| } |
| |
| // The registry. |
| for (int i = configurationElementCount - 1; i >= 0; i--) { |
| final IConfigurationElement configurationElement = configurationElements[i]; |
| |
| String id = configurationElement.getAttribute(ATT_KEY_CONFIGURATION_ID); |
| if (id != null) { |
| try { |
| bindingManager.setActiveScheme(bindingManager.getScheme(id)); |
| return; |
| } catch (final NotDefinedException e) { |
| // Let's keep looking.... |
| } |
| } |
| |
| id = configurationElement.getAttribute(ATT_VALUE); |
| if (id != null) { |
| try { |
| bindingManager.setActiveScheme(bindingManager.getScheme(id)); |
| return; |
| } catch (final NotDefinedException e) { |
| // Let's keep looking.... |
| } |
| } |
| } |
| |
| // The default default active scheme id. |
| try { |
| bindingManager.setActiveScheme(bindingManager.getScheme(IBindingService.DEFAULT_DEFAULT_ACTIVE_SCHEME_ID)); |
| } catch (final NotDefinedException e) { |
| // this is bad - the default default scheme should always exist |
| throw new Error("The default default active scheme id is not defined."); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * Reads all of the binding definitions from the preferences. |
| * |
| * @param preferences The memento for the commands preferences key. |
| * @param bindingManager The binding manager to which the bindings should be |
| * added; must not be <code>null</code>. |
| * @param commandService The command service for the workbench; must not be |
| * <code>null</code>. |
| */ |
| private static final void readBindingsFromPreferences(final IMemento preferences, |
| final BindingManager bindingManager, final CommandManager commandService) { |
| List<IStatus> warningsToLog = new ArrayList<>(1); |
| |
| if (preferences != null) { |
| final IMemento[] preferenceMementos = preferences.getChildren(TAG_KEY_BINDING); |
| int preferenceMementoCount = preferenceMementos.length; |
| for (int i = preferenceMementoCount - 1; i >= 0; i--) { |
| final IMemento memento = preferenceMementos[i]; |
| |
| // Read out the command id. |
| String commandId = readOptional(memento, ATT_COMMAND_ID); |
| if (commandId == null) { |
| commandId = readOptional(memento, ATT_COMMAND); |
| } |
| final Command command; |
| if (commandId != null) { |
| command = commandService.getCommand(commandId); |
| } else { |
| command = null; |
| } |
| |
| // Read out the scheme id. |
| String schemeId = readOptional(memento, ATT_KEY_CONFIGURATION_ID); |
| if (schemeId == null) { |
| schemeId = readRequired(memento, ATT_CONFIGURATION, warningsToLog, |
| "Key bindings need a scheme or key configuration"); //$NON-NLS-1$ |
| if (schemeId == null) { |
| continue; |
| } |
| } |
| |
| // Read out the context id. |
| String contextId = readOptional(memento, ATT_CONTEXT_ID); |
| if (contextId == null) { |
| contextId = readOptional(memento, ATT_SCOPE); |
| } |
| if (LEGACY_DEFAULT_SCOPE.equals(contextId)) { |
| contextId = null; |
| } |
| if (contextId == null) { |
| contextId = IContextIds.CONTEXT_ID_WINDOW; |
| } |
| |
| // Read out the key sequence. |
| String keySequenceText = readOptional(memento, ATT_KEY_SEQUENCE); |
| KeySequence keySequence = null; |
| if (keySequenceText == null) { |
| keySequenceText = readRequired(memento, ATT_STRING, warningsToLog, |
| "Key bindings need a key sequence or string"); //$NON-NLS-1$ |
| if (keySequenceText == null) { |
| continue; |
| } |
| |
| // The key sequence is in the old-style format. |
| keySequence = convert2_1Sequence(parse2_1Sequence(keySequenceText)); |
| |
| } else { |
| // The key sequence is in the new-style format. |
| try { |
| keySequence = KeySequence.getInstance(keySequenceText); |
| } catch (final ParseException e) { |
| addWarning(warningsToLog, "Could not parse", null, //$NON-NLS-1$ |
| commandId, "keySequence", keySequenceText); //$NON-NLS-1$ |
| continue; |
| } |
| if (keySequence.isEmpty() || !keySequence.isComplete()) { |
| addWarning(warningsToLog, "Key bindings cannot use an empty or incomplete key sequence", //$NON-NLS-1$ |
| null, commandId, "keySequence", keySequence //$NON-NLS-1$ |
| .toString()); |
| continue; |
| } |
| |
| } |
| |
| // Read out the locale and platform. |
| final String locale = readOptional(memento, ATT_LOCALE); |
| final String platform = readOptional(memento, ATT_PLATFORM); |
| |
| // Read out the parameters |
| final ParameterizedCommand parameterizedCommand = command != null |
| ? readParameters(memento, warningsToLog, command) |
| : null; |
| |
| final Binding binding = new KeyBinding(keySequence, parameterizedCommand, schemeId, contextId, locale, |
| platform, null, Binding.USER); |
| bindingManager.addBinding(binding); |
| } |
| } |
| |
| // If there were any warnings, then log them now. |
| logWarnings(warningsToLog, "Warnings while parsing the key bindings from the preference store"); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Reads all of the binding definitions 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 bindingManager The binding manager to which the bindings |
| * should be added; must not be |
| * <code>null</code>. |
| * @param commandService The command service for the workbench; must |
| * not be <code>null</code>. |
| */ |
| private static final void readBindingsFromRegistry(final IConfigurationElement[] configurationElements, |
| final int configurationElementCount, final BindingManager bindingManager, |
| final CommandManager commandService) { |
| final Collection<KeyBinding> bindings = new ArrayList<>(configurationElementCount); |
| final List<IStatus> warningsToLog = new ArrayList<>(1); |
| |
| HashSet<KeyBinding> cocoaTempList = new HashSet<>(); |
| // IViewRegistry viewRegistry = |
| // PlatformUI.getWorkbench().getViewRegistry(); |
| |
| // the local cache for the sequence modifiers |
| IConfigurationElement[] sequenceModifiers = new IConfigurationElement[0]; |
| if (configurationElementCount > 0) |
| sequenceModifiers = getSequenceModifierElements(configurationElements[0]); |
| |
| for (int i = 0; i < configurationElementCount; i++) { |
| final IConfigurationElement configurationElement = configurationElements[i]; |
| |
| // different extension. update the cache ... |
| if (i > 0 && !configurationElement.getDeclaringExtension() |
| .equals(configurationElements[i - 1].getDeclaringExtension())) |
| sequenceModifiers = getSequenceModifierElements(configurationElement); |
| |
| /* |
| * Read out the command id. Doing this before determining if the key binding is |
| * actually valid is a bit wasteful. However, it is helpful to have the command |
| * identifier when logging syntax errors. |
| */ |
| String commandId = readCommandId(configurationElement); |
| |
| String viewParameter = null; |
| final Command command; |
| if (commandId != null) { |
| // TODO should we still try processing keybindings to viewIds? |
| // if (viewRegistry.find(commandId) == null) { |
| command = commandService.getCommand(commandId); |
| if (!command.isDefined()) { |
| // Reference to an undefined command. This is invalid. |
| addWarning(warningsToLog, "Cannot bind to an undefined command", //$NON-NLS-1$ |
| configurationElement, commandId); |
| continue; |
| } |
| } else { |
| command = null; |
| } |
| |
| // Read out the scheme id. |
| String schemeId = readSchemeId(configurationElement, warningsToLog, commandId); |
| if (isEmpty(schemeId)) |
| continue; |
| |
| // Read out the context id. |
| String contextId = readContextId(configurationElement); |
| |
| String keySequenceText = readKeySequenceText(configurationElement); |
| if (isEmpty(keySequenceText)) { |
| // The key sequence should never be null. This is pointless |
| addWarning(warningsToLog, "Defining a key binding with no key sequence has no effect", //$NON-NLS-1$ |
| configurationElement, commandId); |
| continue; |
| } |
| |
| // Read out the key sequence. |
| KeySequence keySequence = readKeySequence(configurationElement, warningsToLog, commandId, keySequenceText); |
| if (keySequence == null) |
| continue; |
| |
| // Read out the locale and platform. |
| |
| String locale = readNonEmptyAttribute(configurationElement, ATT_LOCALE); |
| String platform = readNonEmptyAttribute(configurationElement, ATT_PLATFORM); |
| |
| // Read out the parameters, if any. |
| ParameterizedCommand parameterizedCommand = readParameterizedCommand(warningsToLog, configurationElement, |
| viewParameter, command); |
| |
| List<KeyBinding> modifiedBindings = applyModifiers(keySequence, keySequenceText, platform, |
| sequenceModifiers, parameterizedCommand, schemeId, contextId, locale, warningsToLog); |
| |
| KeyBinding binding = modifiedBindings.get(0); |
| if (modifiedBindings.size() > 1) { |
| for (int j = 1; j < modifiedBindings.size(); j++) { |
| bindings.add(modifiedBindings.get(j)); |
| } |
| } |
| |
| if (Util.WS_COCOA.equals(platform)) { |
| cocoaTempList.add(binding); |
| } else if (Util.WS_CARBON.equals(platform)) { |
| bindings.add(binding); |
| // temp work around ... simply honour the carbon |
| // bindings for cocoa. |
| cocoaTempList.add(new KeyBinding(keySequence, parameterizedCommand, schemeId, contextId, locale, |
| Util.WS_COCOA, null, Binding.SYSTEM)); |
| } else { |
| bindings.add(binding); |
| } |
| } |
| if (cocoaTempList.size() > 0) { |
| bindings.addAll(cocoaTempList); |
| } |
| |
| final Binding[] bindingArray = bindings.toArray(new Binding[bindings.size()]); |
| bindingManager.setBindings(bindingArray); |
| |
| logWarnings(warningsToLog, |
| "Warnings while parsing the key bindings from the 'org.eclipse.ui.commands' and 'org.eclipse.ui.bindings' extension point"); //$NON-NLS-1$ |
| } |
| |
| private static List<KeyBinding> applyModifiers(KeySequence keySequence, String keySequenceText, String platform, |
| IConfigurationElement[] sequenceModifiers, ParameterizedCommand parameterizedCommand, String schemeId, |
| String contextId, String locale, List<IStatus> warningsToLog) { |
| |
| List<KeyBinding> bindings = new ArrayList<>(); |
| |
| for (IConfigurationElement sequenceModifier : sequenceModifiers) { |
| |
| String findSequence = sequenceModifier.getAttribute(ATT_FIND); |
| |
| if (keySequenceText.startsWith(findSequence)) { |
| String replaceSequence = sequenceModifier.getAttribute(ATT_REPLACE); |
| String modifiedSequence = replaceSequence + keySequenceText.substring(findSequence.length()); |
| String platformsString = sequenceModifier.getAttribute(ATT_PLATFORMS); |
| |
| String[] platforms = parseCommaSeparatedString(platformsString); |
| |
| try { |
| if (platform == null) { |
| addGenericBindings(keySequence, parameterizedCommand, schemeId, contextId, locale, bindings, |
| modifiedSequence, platforms); |
| |
| } else { |
| getBindingForPlatform(keySequence, platform, parameterizedCommand, schemeId, contextId, locale, |
| bindings, modifiedSequence, platforms); |
| } |
| } catch (ParseException e) { |
| bindings.clear(); |
| addWarning(warningsToLog, "Cannot create modified sequence for key binding", //$NON-NLS-1$ |
| sequenceModifier, parameterizedCommand.getId(), ATT_REPLACE, replaceSequence); |
| |
| } |
| break; |
| } |
| } |
| |
| if (bindings.isEmpty()) { |
| // no modifier was applied/error occurred ... |
| KeyBinding binding = new KeyBinding(keySequence, parameterizedCommand, schemeId, contextId, locale, |
| platform, null, Binding.SYSTEM); |
| bindings.add(binding); |
| } |
| |
| return bindings; |
| } |
| |
| private static void getBindingForPlatform(KeySequence keySequence, String platform, |
| ParameterizedCommand parameterizedCommand, String schemeId, String contextId, String locale, |
| List<KeyBinding> bindings, String modifiedSequence, String[] platforms) throws ParseException { |
| |
| int j = 0; |
| for (; j < platforms.length; j++) { |
| if (platforms[j].equals(platform)) { |
| KeyBinding newBinding = new KeyBinding(KeySequence.getInstance(modifiedSequence), parameterizedCommand, |
| schemeId, contextId, locale, platforms[j], null, Binding.SYSTEM); |
| bindings.add(newBinding); |
| break; |
| } |
| } |
| if (j == platforms.length) { |
| // platform doesn't match. use the unmodified sequence |
| KeyBinding newBinding = new KeyBinding(keySequence, parameterizedCommand, schemeId, contextId, locale, |
| platform, null, Binding.SYSTEM); |
| bindings.add(newBinding); |
| } |
| } |
| |
| private static void addGenericBindings(KeySequence keySequence, ParameterizedCommand parameterizedCommand, |
| String schemeId, String contextId, String locale, List<KeyBinding> bindings, String modifiedSequence, |
| String[] platforms) throws ParseException { |
| |
| KeyBinding originalBinding = new KeyBinding(keySequence, parameterizedCommand, schemeId, contextId, locale, |
| null, null, Binding.SYSTEM); |
| bindings.add(originalBinding); |
| |
| String platform = SWT.getPlatform(); |
| boolean modifierExists = false; |
| for (String currentPlatform : platforms) { |
| if (currentPlatform.equals(platform)) { |
| modifierExists = true; |
| break; |
| } |
| } |
| |
| if (modifierExists) { |
| KeyBinding newBinding = new KeyBinding(KeySequence.getInstance(modifiedSequence), parameterizedCommand, |
| schemeId, contextId, locale, SWT.getPlatform(), null, Binding.SYSTEM); |
| |
| KeyBinding deleteBinding = new KeyBinding(keySequence, null, schemeId, contextId, locale, SWT.getPlatform(), |
| null, Binding.SYSTEM); |
| |
| bindings.add(newBinding); |
| bindings.add(deleteBinding); |
| } |
| |
| } |
| |
| private static IConfigurationElement[] getSequenceModifierElements(IConfigurationElement configurationElement) { |
| |
| IExtension extension = configurationElement.getDeclaringExtension(); |
| List<IConfigurationElement> modifierElements = new ArrayList<>(); |
| for (final IConfigurationElement configElement : extension.getConfigurationElements()) { |
| if (TAG_SEQUENCE_MODIFIER.equals(configElement.getName())) |
| modifierElements.add(configElement); |
| } |
| return modifierElements.toArray(new IConfigurationElement[modifierElements.size()]); |
| } |
| |
| public static String[] parseCommaSeparatedString(String commaSeparatedString) { |
| StringTokenizer tokenizer = new StringTokenizer(commaSeparatedString, ", "); //$NON-NLS-1$ |
| int count = tokenizer.countTokens(); |
| String[] tokens = new String[count]; |
| for (int i = 0; i < tokens.length; i++) { |
| tokens[i] = tokenizer.nextToken(); |
| } |
| return tokens; |
| } |
| |
| private static String readKeySequenceText(IConfigurationElement configurationElement) { |
| |
| String keySequenceText = configurationElement.getAttribute(ATT_SEQUENCE); |
| if (isEmpty(keySequenceText)) { |
| keySequenceText = configurationElement.getAttribute(ATT_KEY_SEQUENCE); |
| } |
| if (isEmpty(keySequenceText)) |
| keySequenceText = configurationElement.getAttribute(ATT_STRING); |
| |
| return keySequenceText; |
| |
| } |
| |
| private static KeySequence readKeySequence(IConfigurationElement configurationElement, List<IStatus> warningsToLog, |
| String commandId, String keySequenceText) { |
| |
| KeySequence keySequence = null; |
| if (keySequenceText.equals(configurationElement.getAttribute(ATT_STRING))) { |
| // The key sequence is in the old-style format. |
| try { |
| keySequence = convert2_1Sequence(parse2_1Sequence(keySequenceText)); |
| } catch (final IllegalArgumentException e) { |
| addWarning(warningsToLog, "Could not parse key sequence", //$NON-NLS-1$ |
| configurationElement, commandId, "keySequence", //$NON-NLS-1$ |
| keySequenceText); |
| return null; |
| } |
| } else { |
| // The key sequence is in the new-style format. |
| try { |
| keySequence = KeySequence.getInstance(keySequenceText); |
| } catch (final ParseException e) { |
| addWarning(warningsToLog, "Could not parse key sequence", //$NON-NLS-1$ |
| configurationElement, commandId, "keySequence", //$NON-NLS-1$ |
| keySequenceText); |
| return null; |
| } |
| if (keySequence.isEmpty() || !keySequence.isComplete()) { |
| addWarning(warningsToLog, "Key bindings should not have an empty or incomplete key sequence", //$NON-NLS-1$ |
| configurationElement, commandId, "keySequence", //$NON-NLS-1$ |
| keySequence.toString()); |
| return null; |
| } |
| |
| } |
| return keySequence; |
| } |
| |
| private static ParameterizedCommand readParameterizedCommand(final List<IStatus> warningsToLog, |
| final IConfigurationElement configurationElement, String viewParameter, final Command command) { |
| final ParameterizedCommand parameterizedCommand; |
| if (command == null) { |
| parameterizedCommand = null; |
| } else if (viewParameter != null) { |
| HashMap<String, String> parms = new HashMap<>(); |
| parms.put(ShowViewMenu.VIEW_ID_PARM, viewParameter); |
| parameterizedCommand = ParameterizedCommand.generateCommand(command, parms); |
| } else { |
| parameterizedCommand = readParameters(configurationElement, warningsToLog, command); |
| } |
| return parameterizedCommand; |
| } |
| |
| /** |
| * Reads the specified attribute from the configuration element. If the value is |
| * an empty string, will return null. |
| * |
| * @param configurationElement |
| * @return the attribute value |
| */ |
| private static String readNonEmptyAttribute(IConfigurationElement configurationElement, String attribute) { |
| String attributeValue = configurationElement.getAttribute(attribute); |
| if ((attributeValue != null) && (attributeValue.isEmpty())) { |
| attributeValue = null; |
| } |
| return attributeValue; |
| } |
| |
| private static String readContextId(final IConfigurationElement configurationElement) { |
| String contextId = configurationElement.getAttribute(ATT_CONTEXT_ID); |
| if (LEGACY_DEFAULT_SCOPE.equals(contextId)) { |
| contextId = null; |
| } else if ((contextId == null) || (contextId.isEmpty())) { |
| contextId = configurationElement.getAttribute(ATT_SCOPE); |
| if (LEGACY_DEFAULT_SCOPE.equals(contextId)) { |
| contextId = null; |
| } |
| } |
| if ((contextId == null) || (contextId.isEmpty())) { |
| contextId = IContextIds.CONTEXT_ID_WINDOW; |
| } |
| return contextId; |
| } |
| |
| private static String readSchemeId(IConfigurationElement configurationElement, List<IStatus> warningsToLog, |
| String commandId) { |
| |
| String schemeId = configurationElement.getAttribute(ATT_SCHEME_ID); |
| if ((schemeId == null) || (schemeId.isEmpty())) { |
| schemeId = configurationElement.getAttribute(ATT_KEY_CONFIGURATION_ID); |
| if ((schemeId == null) || (schemeId.isEmpty())) { |
| schemeId = configurationElement.getAttribute(ATT_CONFIGURATION); |
| if ((schemeId == null) || (schemeId.isEmpty())) { |
| // The scheme id should never be null. This is invalid. |
| addWarning(warningsToLog, "Key bindings need a scheme", //$NON-NLS-1$ |
| configurationElement, commandId); |
| } |
| } |
| } |
| return schemeId; |
| } |
| |
| private static String readCommandId(final IConfigurationElement configurationElement) { |
| String commandId = configurationElement.getAttribute(ATT_COMMAND_ID); |
| if ((commandId == null) || (commandId.isEmpty())) { |
| commandId = configurationElement.getAttribute(ATT_COMMAND); |
| } |
| if ((commandId != null) && (commandId.isEmpty())) { |
| commandId = null; |
| } |
| return commandId; |
| } |
| |
| private static boolean isEmpty(String string) { |
| return string == null || string.isEmpty(); |
| } |
| |
| /** |
| * Reads all of the scheme definitions from the registry. |
| * |
| * @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 bindingManager The binding manager to which the schemes |
| * should be added; must not be |
| * <code>null</code>. |
| */ |
| private static final void readSchemesFromRegistry(final IConfigurationElement[] configurationElements, |
| final int configurationElementCount, final BindingManager bindingManager) { |
| // Undefine all the previous handle objects. |
| final HandleObject[] handleObjects = bindingManager.getDefinedSchemes(); |
| if (handleObjects != null) { |
| for (HandleObject handleObject : handleObjects) { |
| handleObject.undefine(); |
| } |
| } |
| |
| final List<IStatus> warningsToLog = new ArrayList<>(1); |
| |
| for (int i = 0; i < configurationElementCount; i++) { |
| final IConfigurationElement configurationElement = configurationElements[i]; |
| |
| // Read out the attributes. |
| final String id = readRequired(configurationElement, ATT_ID, warningsToLog, "Schemes need an id"); //$NON-NLS-1$ |
| if (id == null) { |
| continue; |
| } |
| final String name = readRequired(configurationElement, ATT_NAME, warningsToLog, "A scheme needs a name", //$NON-NLS-1$ |
| id); |
| if (name == null) { |
| continue; |
| } |
| final String description = readOptional(configurationElement, ATT_DESCRIPTION); |
| |
| String parentId = configurationElement.getAttribute(ATT_PARENT_ID); |
| if ((parentId != null) && (parentId.isEmpty())) { |
| parentId = configurationElement.getAttribute(ATT_PARENT); |
| if ((parentId != null) && (parentId.isEmpty())) { |
| parentId = null; |
| } |
| } |
| |
| // Define the scheme. |
| final Scheme scheme = bindingManager.getScheme(id); |
| scheme.define(name, description, parentId); |
| } |
| |
| logWarnings(warningsToLog, |
| "Warnings while parsing the key bindings from the 'org.eclipse.ui.bindings', 'org.eclipse.ui.acceleratorConfigurations' and 'org.eclipse.ui.commands' extension point"); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Writes the given active scheme and bindings to the preference store. Only |
| * bindings that are of the <code>Binding.USER</code> type will be written; the |
| * others will be ignored. |
| * |
| * @param activeScheme The scheme which should be persisted; may be |
| * <code>null</code>. |
| * @param bindings The bindings which should be persisted; may be |
| * <code>null</code> |
| * @throws IOException If something happens while trying to write to the |
| * workbench preference store. |
| */ |
| static final void write(final Scheme activeScheme, final Binding[] bindings) throws IOException { |
| // Print out debugging information, if requested. |
| if (DEBUG) { |
| Tracing.printTrace("BINDINGS", "Persisting active scheme '" //$NON-NLS-1$ //$NON-NLS-2$ |
| + activeScheme.getId() + '\''); |
| Tracing.printTrace("BINDINGS", "Persisting bindings"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| // Write the simple preference key to the UI preference store. |
| writeActiveScheme(activeScheme); |
| |
| // Build the XML block for writing the bindings and active scheme. |
| final XMLMemento xmlMemento = XMLMemento.createWriteRoot(EXTENSION_COMMANDS); |
| if (activeScheme != null) { |
| writeActiveSchemeToPreferences(xmlMemento, activeScheme); |
| } |
| if (bindings != null) { |
| final int bindingsLength = bindings.length; |
| for (int i = 0; i < bindingsLength; i++) { |
| final Binding binding = bindings[i]; |
| if (binding.getType() == Binding.USER) { |
| writeBindingToPreferences(xmlMemento, binding); |
| } |
| } |
| } |
| |
| // Write the XML block to the workbench preference store. |
| final IPreferenceStore preferenceStore = WorkbenchPlugin.getDefault().getPreferenceStore(); |
| try (Writer writer = new StringWriter()) { |
| xmlMemento.save(writer); |
| preferenceStore.setValue(EXTENSION_COMMANDS, writer.toString()); |
| } |
| } |
| |
| /** |
| * Writes the active scheme to its own preference key. This key is used by RCP |
| * applications as part of their plug-in customization. |
| * |
| * @param scheme The scheme to write to the preference store. If the scheme is |
| * <code>null</code>, then it is removed. |
| */ |
| private static final void writeActiveScheme(final Scheme scheme) { |
| final IPreferenceStore store = PlatformUI.getPreferenceStore(); |
| final String schemeId = (scheme == null) ? null : scheme.getId(); |
| final String defaultSchemeId = store.getDefaultString(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID); |
| if ((defaultSchemeId == null) ? (scheme != null) : (!defaultSchemeId.equals(schemeId))) { |
| store.setValue(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID, scheme.getId()); |
| } else { |
| store.setToDefault(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID); |
| } |
| } |
| |
| /** |
| * Writes the active scheme to the memento. If the scheme is <code>null</code>, |
| * then all schemes in the memento are removed. |
| * |
| * @param memento The memento to which the scheme should be written; must not be |
| * <code>null</code>. |
| * @param scheme The scheme that should be written; must not be |
| * <code>null</code>. |
| */ |
| private static final void writeActiveSchemeToPreferences(final IMemento memento, final Scheme scheme) { |
| // Add this active scheme, if it is not the default. |
| final IPreferenceStore store = PlatformUI.getPreferenceStore(); |
| final String schemeId = scheme.getId(); |
| final String defaultSchemeId = store.getDefaultString(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID); |
| if ((defaultSchemeId == null) ? (schemeId != null) : (!defaultSchemeId.equals(schemeId))) { |
| final IMemento child = memento.createChild(TAG_ACTIVE_KEY_CONFIGURATION); |
| child.putString(ATT_KEY_CONFIGURATION_ID, schemeId); |
| } |
| } |
| |
| /** |
| * Writes the binding to the memento. This creates a new child element on the |
| * memento, and places the properties of the binding as its attributes. |
| * |
| * @param parent The parent memento for the binding element; must not be |
| * <code>null</code>. |
| * @param binding The binding to write; must not be <code>null</code>. |
| */ |
| private static final void writeBindingToPreferences(final IMemento parent, final Binding binding) { |
| final IMemento element = parent.createChild(TAG_KEY_BINDING); |
| element.putString(ATT_CONTEXT_ID, binding.getContextId()); |
| final ParameterizedCommand parameterizedCommand = binding.getParameterizedCommand(); |
| final String commandId = (parameterizedCommand == null) ? null : parameterizedCommand.getId(); |
| element.putString(ATT_COMMAND_ID, commandId); |
| element.putString(ATT_KEY_CONFIGURATION_ID, binding.getSchemeId()); |
| element.putString(ATT_KEY_SEQUENCE, binding.getTriggerSequence().toString()); |
| element.putString(ATT_LOCALE, binding.getLocale()); |
| element.putString(ATT_PLATFORM, binding.getPlatform()); |
| if (parameterizedCommand != null) { |
| final Map<String, String> parameterizations = parameterizedCommand.getParameterMap(); |
| final Iterator<Map.Entry<String, String>> parameterizationItr = parameterizations.entrySet().iterator(); |
| while (parameterizationItr.hasNext()) { |
| final Map.Entry<String, String> entry = parameterizationItr.next(); |
| final String id = entry.getKey(); |
| final String value = entry.getValue(); |
| final IMemento parameterElement = element.createChild(TAG_PARAMETER); |
| parameterElement.putString(ATT_ID, id); |
| parameterElement.putString(ATT_VALUE, value); |
| } |
| } |
| } |
| |
| /** |
| * The binding manager which should be populated with the values from the |
| * registry and preference store; must not be <code>null</code>. |
| */ |
| private final BindingManager bindingManager; |
| |
| /** |
| * The command service for the workbench; must not be <code>null</code>. |
| */ |
| private final CommandManager commandManager; |
| |
| /** |
| * Constructs a new instance of <code>BindingPersistence</code>. |
| * |
| * @param bindingManager The binding manager which should be populated with the |
| * values from the registry and preference store; must not |
| * be <code>null</code>. |
| * @param commandService The command service for the workbench; must not be |
| * <code>null</code>. |
| */ |
| public BindingPersistence(final BindingManager bindingManager, final CommandManager commandManager) { |
| this.bindingManager = bindingManager; |
| this.commandManager = commandManager; |
| // HACK. Calling super.read() installs a required preferences change listener. |
| // See bug 266604. |
| super.read(); |
| } |
| |
| @Override |
| protected final boolean isChangeImportant(final IRegistryChangeEvent event) { |
| return false; |
| } |
| |
| public boolean bindingsNeedUpdating(final IRegistryChangeEvent event) { |
| final IExtensionDelta[] acceleratorConfigurationDeltas = event.getExtensionDeltas(PlatformUI.PLUGIN_ID, |
| IWorkbenchRegistryConstants.PL_ACCELERATOR_CONFIGURATIONS); |
| if (acceleratorConfigurationDeltas.length == 0) { |
| final IExtensionDelta[] bindingDeltas = event.getExtensionDeltas(PlatformUI.PLUGIN_ID, |
| IWorkbenchRegistryConstants.PL_BINDINGS); |
| if (bindingDeltas.length == 0) { |
| final IExtensionDelta[] commandDeltas = event.getExtensionDeltas(PlatformUI.PLUGIN_ID, |
| IWorkbenchRegistryConstants.PL_COMMANDS); |
| if (commandDeltas.length == 0) { |
| final IExtensionDelta[] acceleratorScopeDeltas = event.getExtensionDeltas(PlatformUI.PLUGIN_ID, |
| IWorkbenchRegistryConstants.PL_ACCELERATOR_SCOPES); |
| if (acceleratorScopeDeltas.length == 0) { |
| final IExtensionDelta[] contextDeltas = event.getExtensionDeltas(PlatformUI.PLUGIN_ID, |
| IWorkbenchRegistryConstants.PL_CONTEXTS); |
| if (contextDeltas.length == 0) { |
| final IExtensionDelta[] actionDefinitionDeltas = event.getExtensionDeltas( |
| PlatformUI.PLUGIN_ID, IWorkbenchRegistryConstants.PL_ACTION_DEFINITIONS); |
| if (actionDefinitionDeltas.length == 0) { |
| return false; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| @Override |
| protected final boolean isChangeImportant(final PropertyChangeEvent event) { |
| return EXTENSION_COMMANDS.equals(event.getProperty()); |
| } |
| |
| /** |
| * Reads all of the binding information from the registry and from the |
| * preference store. |
| */ |
| @Override |
| public final void read() { |
| super.read(); |
| reRead(); |
| } |
| |
| public void reRead() { |
| // Create the extension registry mementos. |
| final IExtensionRegistry registry = Platform.getExtensionRegistry(); |
| int activeSchemeElementCount = 0; |
| int bindingDefinitionCount = 0; |
| int schemeDefinitionCount = 0; |
| final IConfigurationElement[][] indexedConfigurationElements = new IConfigurationElement[3][]; |
| |
| // Sort the bindings extension point based on element name. |
| final IConfigurationElement[] bindingsExtensionPoint = registry.getConfigurationElementsFor(EXTENSION_BINDINGS); |
| for (final IConfigurationElement configurationElement : bindingsExtensionPoint) { |
| final String name = configurationElement.getName(); |
| |
| // Check if it is a binding definition. |
| if (TAG_KEY.equals(name)) { |
| addElementToIndexedArray(configurationElement, indexedConfigurationElements, INDEX_BINDING_DEFINITIONS, |
| bindingDefinitionCount++); |
| } else |
| // Check to see if it is a scheme definition. |
| if (TAG_SCHEME.equals(name)) { |
| addElementToIndexedArray(configurationElement, indexedConfigurationElements, INDEX_SCHEME_DEFINITIONS, |
| schemeDefinitionCount++); |
| } |
| |
| } |
| |
| // 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 binding definition. |
| if (TAG_KEY_BINDING.equals(name)) { |
| addElementToIndexedArray(configurationElement, indexedConfigurationElements, INDEX_BINDING_DEFINITIONS, |
| bindingDefinitionCount++); |
| |
| // Check if it is a scheme defintion. |
| } else if (TAG_KEY_CONFIGURATION.equals(name)) { |
| addElementToIndexedArray(configurationElement, indexedConfigurationElements, INDEX_SCHEME_DEFINITIONS, |
| schemeDefinitionCount++); |
| |
| // Check if it is an active scheme identifier. |
| } else if (TAG_ACTIVE_KEY_CONFIGURATION.equals(name)) { |
| addElementToIndexedArray(configurationElement, indexedConfigurationElements, INDEX_ACTIVE_SCHEME, |
| activeSchemeElementCount++); |
| } |
| } |
| |
| /* |
| * Sort the accelerator configuration extension point into the scheme |
| * definitions. |
| */ |
| final IConfigurationElement[] acceleratorConfigurationsExtensionPoint = registry |
| .getConfigurationElementsFor(EXTENSION_ACCELERATOR_CONFIGURATIONS); |
| for (final IConfigurationElement configurationElement : acceleratorConfigurationsExtensionPoint) { |
| final String name = configurationElement.getName(); |
| |
| // Check if the name matches the accelerator configuration element |
| if (TAG_ACCELERATOR_CONFIGURATION.equals(name)) { |
| addElementToIndexedArray(configurationElement, indexedConfigurationElements, INDEX_SCHEME_DEFINITIONS, |
| schemeDefinitionCount++); |
| } |
| } |
| |
| // Create the preference memento. |
| final IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore(); |
| final String preferenceString = store.getString(EXTENSION_COMMANDS); |
| IMemento preferenceMemento = null; |
| if ((preferenceString != null) && (preferenceString.length() > 0)) { |
| final Reader reader = new StringReader(preferenceString); |
| try { |
| preferenceMemento = XMLMemento.createReadRoot(reader); |
| } catch (final WorkbenchException e) { |
| // Could not initialize the preference memento. |
| } |
| } |
| |
| // Read the scheme definitions. |
| readSchemesFromRegistry(indexedConfigurationElements[INDEX_SCHEME_DEFINITIONS], schemeDefinitionCount, |
| bindingManager); |
| readActiveScheme(indexedConfigurationElements[INDEX_ACTIVE_SCHEME], activeSchemeElementCount, preferenceMemento, |
| bindingManager); |
| readBindingsFromRegistry(indexedConfigurationElements[INDEX_BINDING_DEFINITIONS], bindingDefinitionCount, |
| bindingManager, commandManager); |
| readBindingsFromPreferences(preferenceMemento, bindingManager, commandManager); |
| } |
| } |