| /******************************************************************************* |
| * Copyright (c) 2007, 2009 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.ui.internal.keys.model; |
| |
| import java.io.BufferedWriter; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.OutputStreamWriter; |
| import java.io.Writer; |
| import java.util.Collection; |
| import java.util.Map; |
| import java.util.ResourceBundle; |
| 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.ContextManager; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.ListenerList; |
| import org.eclipse.core.runtime.SafeRunner; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.e4.ui.bindings.internal.BindingCopies; |
| 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.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.jface.util.SafeRunnable; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.widgets.FileDialog; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.ui.contexts.IContextService; |
| import org.eclipse.ui.internal.WorkbenchPlugin; |
| import org.eclipse.ui.internal.keys.KeysPreferencePage; |
| import org.eclipse.ui.internal.keys.NewKeysPreferenceMessages; |
| import org.eclipse.ui.internal.misc.StatusUtil; |
| import org.eclipse.ui.internal.util.Util; |
| import org.eclipse.ui.keys.IBindingService; |
| import org.eclipse.ui.services.IServiceLocator; |
| import org.eclipse.ui.statushandlers.StatusManager; |
| |
| /** |
| * @since 3.4 |
| * |
| */ |
| public class KeyController { |
| private static final String DELIMITER = ","; //$NON-NLS-1$ |
| private static final String ESCAPED_QUOTE = "\""; //$NON-NLS-1$ |
| private static final String REPLACEMENT = "\"\""; //$NON-NLS-1$ |
| /** |
| * The resource bundle from which translations can be retrieved. |
| */ |
| private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle |
| .getBundle(KeysPreferencePage.class.getName()); |
| private ListenerList eventManager = null; |
| private BindingManager fBindingManager; |
| private ContextModel contextModel; |
| private SchemeModel fSchemeModel; |
| private BindingModel bindingModel; |
| private boolean notifying = true; |
| private ConflictModel conflictModel; |
| private IServiceLocator serviceLocator; |
| |
| private ListenerList getEventManager() { |
| if (eventManager == null) { |
| eventManager = new ListenerList(ListenerList.IDENTITY); |
| } |
| return eventManager; |
| } |
| |
| public void setNotifying(boolean b) { |
| notifying = b; |
| } |
| |
| public boolean isNotifying() { |
| return notifying; |
| } |
| |
| public void firePropertyChange(Object source, String propId, Object oldVal, |
| Object newVal) { |
| if (!isNotifying()) { |
| return; |
| } |
| if (Util.equals(oldVal, newVal)) { |
| return; |
| } |
| |
| Object[] listeners = getEventManager().getListeners(); |
| PropertyChangeEvent event = new PropertyChangeEvent(source, propId, |
| oldVal, newVal); |
| for (int i = 0; i < listeners.length; i++) { |
| ((IPropertyChangeListener) listeners[i]).propertyChange(event); |
| } |
| } |
| |
| public void addPropertyChangeListener(IPropertyChangeListener listener) { |
| getEventManager().add(listener); |
| } |
| |
| public void removePropertyChangeListener(IPropertyChangeListener listener) { |
| getEventManager().remove(listener); |
| } |
| |
| public void init(IServiceLocator locator) { |
| getEventManager().clear(); |
| this.serviceLocator = locator; |
| fBindingManager = loadModelBackend(serviceLocator); |
| contextModel = new ContextModel(this); |
| contextModel.init(serviceLocator); |
| fSchemeModel = new SchemeModel(this); |
| fSchemeModel.init(fBindingManager); |
| bindingModel = new BindingModel(this); |
| bindingModel.init(serviceLocator, fBindingManager, contextModel); |
| conflictModel = new ConflictModel(this); |
| conflictModel.init(fBindingManager, bindingModel); |
| addSetContextListener(); |
| addSetBindingListener(); |
| addSetConflictListener(); |
| addSetKeySequenceListener(); |
| addSetSchemeListener(); |
| addSetModelObjectListener(); |
| } |
| |
| private static BindingManager loadModelBackend(IServiceLocator locator) { |
| IBindingService bindingService = (IBindingService) locator |
| .getService(IBindingService.class); |
| BindingManager bindingManager = new BindingManager( |
| new ContextManager(), new CommandManager()); |
| final Scheme[] definedSchemes = bindingService.getDefinedSchemes(); |
| try { |
| Scheme modelActiveScheme = null; |
| for (int i = 0; i < definedSchemes.length; i++) { |
| final Scheme scheme = definedSchemes[i]; |
| final Scheme copy = bindingManager.getScheme(scheme.getId()); |
| copy.define(scheme.getName(), scheme.getDescription(), scheme |
| .getParentId()); |
| if (definedSchemes[i] == bindingService.getActiveScheme()) { |
| modelActiveScheme = copy; |
| } |
| } |
| bindingManager.setActiveScheme(modelActiveScheme); |
| } catch (final NotDefinedException e) { |
| StatusManager.getManager().handle( |
| new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH, |
| "Keys page found an undefined scheme", e)); //$NON-NLS-1$ |
| } |
| bindingManager.setLocale(bindingService.getLocale()); |
| bindingManager.setPlatform(bindingService.getPlatform()); |
| bindingManager.setBindings(bindingService.getBindings()); |
| return bindingManager; |
| } |
| |
| public ContextModel getContextModel() { |
| return contextModel; |
| } |
| |
| public SchemeModel getSchemeModel() { |
| return fSchemeModel; |
| } |
| |
| public BindingModel getBindingModel() { |
| return bindingModel; |
| } |
| |
| public ConflictModel getConflictModel() { |
| return conflictModel; |
| } |
| |
| private void addSetContextListener() { |
| addPropertyChangeListener(new IPropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent event) { |
| if (event.getSource() == contextModel |
| && CommonModel.PROP_SELECTED_ELEMENT.equals(event |
| .getProperty())) { |
| updateBindingContext((ContextElement) event.getNewValue()); |
| } |
| } |
| }); |
| } |
| |
| private void addSetBindingListener() { |
| addPropertyChangeListener(new IPropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent event) { |
| if (event.getSource() == bindingModel |
| && CommonModel.PROP_SELECTED_ELEMENT.equals(event |
| .getProperty())) { |
| BindingElement binding = (BindingElement) event |
| .getNewValue(); |
| if (binding == null) { |
| conflictModel.setSelectedElement(null); |
| return; |
| } |
| conflictModel.setSelectedElement(binding); |
| ContextElement context = binding.getContext(); |
| if (context != null) { |
| contextModel.setSelectedElement(context); |
| } |
| } |
| } |
| }); |
| } |
| |
| private void addSetConflictListener() { |
| addPropertyChangeListener(new IPropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent event) { |
| if (event.getSource() == conflictModel |
| && CommonModel.PROP_SELECTED_ELEMENT.equals(event |
| .getProperty())) { |
| if (event.getNewValue() != null) { |
| bindingModel.setSelectedElement((ModelElement) event |
| .getNewValue()); |
| } |
| } |
| } |
| }); |
| } |
| |
| private void addSetKeySequenceListener() { |
| addPropertyChangeListener(new IPropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent event) { |
| if (BindingElement.PROP_TRIGGER.equals(event.getProperty())) { |
| updateTrigger((BindingElement) event.getSource(), |
| (KeySequence) event.getOldValue(), |
| (KeySequence) event.getNewValue()); |
| } |
| } |
| }); |
| } |
| |
| private void addSetModelObjectListener() { |
| addPropertyChangeListener(new IPropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent event) { |
| if (event.getSource() instanceof BindingElement |
| && ModelElement.PROP_MODEL_OBJECT.equals(event |
| .getProperty())) { |
| if (event.getNewValue() != null) { |
| BindingElement element = (BindingElement) event |
| .getSource(); |
| Object oldValue = event.getOldValue(); |
| Object newValue = event.getNewValue(); |
| if (oldValue instanceof Binding |
| && newValue instanceof Binding) { |
| conflictModel.updateConflictsFor(element, |
| ((Binding) oldValue).getTriggerSequence(), |
| ((Binding) newValue).getTriggerSequence(), |
| false); |
| } else { |
| conflictModel.updateConflictsFor(element, false); |
| } |
| |
| ContextElement context = element.getContext(); |
| if (context != null) { |
| contextModel.setSelectedElement(context); |
| } |
| } |
| } |
| } |
| }); |
| } |
| |
| private void addSetSchemeListener() { |
| addPropertyChangeListener(new IPropertyChangeListener() { |
| public void propertyChange(PropertyChangeEvent event) { |
| if (event.getSource() == fSchemeModel |
| && CommonModel.PROP_SELECTED_ELEMENT.equals(event |
| .getProperty())) { |
| changeScheme((SchemeElement) event.getOldValue(), |
| (SchemeElement) event.getNewValue()); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * @param oldScheme |
| * @param newScheme |
| */ |
| protected void changeScheme(SchemeElement oldScheme, SchemeElement newScheme) { |
| if (newScheme == null |
| || newScheme.getModelObject() == fBindingManager |
| .getActiveScheme()) { |
| return; |
| } |
| try { |
| fBindingManager |
| .setActiveScheme((Scheme) newScheme.getModelObject()); |
| bindingModel.refresh(contextModel); |
| bindingModel.setSelectedElement(null); |
| } catch (NotDefinedException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } |
| |
| } |
| |
| private void updateBindingContext(ContextElement context) { |
| if (context == null) { |
| return; |
| } |
| BindingElement activeBinding = (BindingElement) bindingModel |
| .getSelectedElement(); |
| if (activeBinding == null) { |
| return; |
| } |
| String activeSchemeId = fSchemeModel.getSelectedElement().getId(); |
| Object obj = activeBinding.getModelObject(); |
| if (obj instanceof KeyBinding) { |
| KeyBinding keyBinding = (KeyBinding) obj; |
| if (!keyBinding.getContextId().equals(context.getId())) { |
| final KeyBinding binding = new KeyBinding(keyBinding |
| .getKeySequence(), |
| keyBinding.getParameterizedCommand(), activeSchemeId, |
| context.getId(), null, null, null, Binding.USER); |
| if (keyBinding.getType() == Binding.USER) { |
| fBindingManager.removeBinding(keyBinding); |
| } else { |
| fBindingManager.addBinding(new KeyBinding(keyBinding |
| .getKeySequence(), null, keyBinding.getSchemeId(), |
| keyBinding.getContextId(), null, null, null, |
| Binding.USER)); |
| } |
| bindingModel.getBindingToElement().remove( |
| activeBinding.getModelObject()); |
| |
| fBindingManager.addBinding(binding); |
| activeBinding.fill(binding, contextModel); |
| bindingModel.getBindingToElement().put(binding, activeBinding); |
| } |
| } |
| } |
| |
| /** |
| * @param activeBinding |
| * @param oldSequence |
| * @param keySequence |
| */ |
| public void updateTrigger(BindingElement activeBinding, |
| KeySequence oldSequence, KeySequence keySequence) { |
| if (activeBinding == null) { |
| return; |
| } |
| Object obj = activeBinding.getModelObject(); |
| if (obj instanceof KeyBinding) { |
| KeyBinding keyBinding = (KeyBinding) obj; |
| if (!keyBinding.getKeySequence().equals(keySequence)) { |
| if (keySequence != null && !keySequence.isEmpty()) { |
| String activeSchemeId = fSchemeModel.getSelectedElement() |
| .getId(); |
| ModelElement selectedElement = contextModel |
| .getSelectedElement(); |
| String activeContextId = selectedElement == null ? IContextService.CONTEXT_ID_WINDOW |
| : selectedElement.getId(); |
| final KeyBinding binding = new KeyBinding(keySequence, |
| keyBinding.getParameterizedCommand(), |
| activeSchemeId, activeContextId, null, null, null, |
| Binding.USER); |
| Map bindingToElement = bindingModel.getBindingToElement(); |
| bindingToElement.remove(keyBinding); |
| if (keyBinding.getType() == Binding.USER) { |
| fBindingManager.removeBinding(keyBinding); |
| } else { |
| fBindingManager.addBinding(new KeyBinding(keyBinding |
| .getKeySequence(), null, keyBinding |
| .getSchemeId(), keyBinding.getContextId(), |
| null, null, null, Binding.USER)); |
| } |
| |
| fBindingManager.addBinding(binding); |
| activeBinding.fill(binding, contextModel); |
| bindingModel.getBindingToElement().put(binding, |
| activeBinding); |
| |
| // Remove binding for any system conflicts |
| |
| bindingModel.setSelectedElement(activeBinding); |
| } else { |
| bindingModel.getBindingToElement().remove(keyBinding); |
| if (keyBinding.getType() == Binding.USER) { |
| fBindingManager.removeBinding(keyBinding); |
| } else { |
| fBindingManager.addBinding(new KeyBinding(keyBinding |
| .getKeySequence(), null, keyBinding |
| .getSchemeId(), keyBinding.getContextId(), |
| null, null, null, Binding.USER)); |
| } |
| activeBinding.fill(keyBinding.getParameterizedCommand()); |
| } |
| } |
| } else if (obj instanceof ParameterizedCommand) { |
| ParameterizedCommand cmd = (ParameterizedCommand) obj; |
| if (keySequence != null && !keySequence.isEmpty()) { |
| String activeSchemeId = fSchemeModel.getSelectedElement() |
| .getId(); |
| ModelElement selectedElement = contextModel |
| .getSelectedElement(); |
| String activeContextId = selectedElement == null ? IContextService.CONTEXT_ID_WINDOW |
| : selectedElement.getId(); |
| final KeyBinding binding = new KeyBinding(keySequence, cmd, |
| activeSchemeId, activeContextId, null, null, null, |
| Binding.USER); |
| fBindingManager.addBinding(binding); |
| activeBinding.fill(binding, contextModel); |
| bindingModel.getBindingToElement().put(binding, activeBinding); |
| } |
| } |
| } |
| |
| /** |
| * Replaces all the current bindings with the bindings in the local copy of |
| * the binding manager. |
| * |
| * @param bindingService |
| * The binding service that saves the changes made to the local |
| * copy of the binding manager |
| */ |
| public void saveBindings(IBindingService bindingService) { |
| try { |
| |
| Collection<Binding> activeBindingsCollection = fBindingManager |
| .getActiveBindingsDisregardingContextFlat(); |
| Binding[] activeBindingsArray = activeBindingsCollection |
| .toArray(new Binding[activeBindingsCollection.size()]); |
| |
| bindingService.savePreferences(fBindingManager.getActiveScheme(), activeBindingsArray); |
| // bindingService.savePreferences(fBindingManager.getActiveScheme(),fBindingManager.getBindings()); |
| |
| } catch (IOException e) { |
| logPreferenceStoreException(e); |
| } |
| } |
| |
| /** |
| * Logs the given exception, and opens an error dialog saying that something |
| * went wrong. The exception is assumed to have something to do with the |
| * preference store. |
| * |
| * @param exception |
| * The exception to be logged; must not be <code>null</code>. |
| */ |
| private final void logPreferenceStoreException(final Throwable exception) { |
| final String message = NewKeysPreferenceMessages.PreferenceStoreError_Message; |
| String exceptionMessage = exception.getMessage(); |
| if (exceptionMessage == null) { |
| exceptionMessage = message; |
| } |
| final IStatus status = new Status(IStatus.ERROR, |
| WorkbenchPlugin.PI_WORKBENCH, 0, exceptionMessage, exception); |
| WorkbenchPlugin.log(message, status); |
| StatusUtil.handleStatus(message, exception, StatusManager.SHOW); |
| } |
| |
| /** |
| * Filters contexts for the When Combo. |
| * |
| * @param actionSets |
| * <code>true</code> to filter action set contexts |
| * @param internal |
| * <code>false</code> to filter internal contexts |
| * |
| */ |
| public void filterContexts(boolean actionSets, boolean internal) { |
| contextModel.filterContexts(actionSets, internal); |
| } |
| |
| /** |
| * Sets the bindings to default. |
| * |
| * @param bindingService |
| */ |
| public void setDefaultBindings(IBindingService bindingService) { |
| // Fix the scheme in the local changes. |
| final String defaultSchemeId = bindingService.getDefaultSchemeId(); |
| final Scheme defaultScheme = fBindingManager.getScheme(defaultSchemeId); |
| try { |
| fBindingManager.setActiveScheme(defaultScheme); |
| } catch (final NotDefinedException e) { |
| // At least we tried.... |
| e.printStackTrace(); |
| } |
| |
| // Restore any User defined bindings |
| Binding[] bindings = fBindingManager.getBindings(); |
| for (int i = 0; i < bindings.length; i++) { |
| if (bindings[i].getType() == Binding.USER) { |
| fBindingManager.removeBinding(bindings[i]); |
| } |
| } |
| // Re-add the deactivated SYSTEM bindings |
| bindings = BindingCopies.getInactiveSysBindings(); |
| for (int i = 0; i < bindings.length; i++) { |
| fBindingManager.addBinding(bindings[i]); |
| } |
| // reset the binding copies |
| BindingCopies.init(); |
| |
| // set the binding manager's bindings array our copy of the system |
| // bindings |
| // fBindingManager.setBindings(BindingCopies.getSystemBindings().toArray( |
| // new Binding[BindingCopies.getSystemBindings().size()])); |
| |
| bindingModel.refresh(contextModel); |
| saveBindings(bindingService); |
| } |
| |
| public void exportCSV(Shell shell) { |
| final FileDialog fileDialog = new FileDialog(shell, SWT.SAVE |
| | SWT.SHEET); |
| fileDialog.setFilterExtensions(new String[] { "*.csv" }); //$NON-NLS-1$ |
| fileDialog.setFilterNames(new String[] { Util.translateString( |
| RESOURCE_BUNDLE, "csvFilterName") }); //$NON-NLS-1$ |
| fileDialog.setOverwrite(true); |
| final String filePath = fileDialog.open(); |
| if (filePath == null) { |
| return; |
| } |
| |
| final SafeRunnable runnable = new SafeRunnable() { |
| public final void run() throws IOException { |
| Writer fileWriter = null; |
| try { |
| fileWriter = new BufferedWriter(new OutputStreamWriter( |
| new FileOutputStream(filePath), "UTF-8")); //$NON-NLS-1$ |
| final Object[] bindingElements = bindingModel.getBindings() |
| .toArray(); |
| for (int i = 0; i < bindingElements.length; i++) { |
| final BindingElement be = (BindingElement) bindingElements[i]; |
| if (be.getTrigger() == null |
| || be.getTrigger().isEmpty()) { |
| continue; |
| } |
| StringBuffer buffer = new StringBuffer(); |
| buffer.append(ESCAPED_QUOTE |
| + Util.replaceAll(be.getCategory(), |
| ESCAPED_QUOTE, REPLACEMENT) |
| + ESCAPED_QUOTE + DELIMITER); |
| buffer.append(ESCAPED_QUOTE + be.getName() |
| + ESCAPED_QUOTE + DELIMITER); |
| buffer.append(ESCAPED_QUOTE + be.getTrigger().format() |
| + ESCAPED_QUOTE + DELIMITER); |
| buffer.append(ESCAPED_QUOTE + be.getContext().getName() |
| + ESCAPED_QUOTE); |
| buffer.append(System.getProperty("line.separator")); //$NON-NLS-1$ |
| fileWriter.write(buffer.toString()); |
| } |
| |
| } finally { |
| if (fileWriter != null) { |
| try { |
| fileWriter.close(); |
| } catch (final IOException e) { |
| // At least I tried. |
| } |
| } |
| |
| } |
| } |
| }; |
| SafeRunner.run(runnable); |
| } |
| } |