diff options
author | Tom Schindl | 2013-04-17 21:48:21 +0000 |
---|---|---|
committer | Tom Schindl | 2013-04-17 21:48:21 +0000 |
commit | 7532784c9261b274db2720cb165b9457dc7891a3 (patch) | |
tree | 251f649fe1d4c33a80823953e996c59320e8a798 | |
parent | 13eeec7ef2ef84813824bb20036d89e3dc3cbf0c (diff) | |
download | org.eclipse.efxclipse-7532784c9261b274db2720cb165b9457dc7891a3.tar.gz org.eclipse.efxclipse-7532784c9261b274db2720cb165b9457dc7891a3.tar.xz org.eclipse.efxclipse-7532784c9261b274db2720cb165b9457dc7891a3.zip |
initial check in
21 files changed, 1590 insertions, 0 deletions
diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.DS_Store b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.DS_Store Binary files differnew file mode 100644 index 000000000..9a874b576 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.DS_Store diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.classpath b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.classpath new file mode 100755 index 000000000..b1dabee38 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.gitignore b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.gitignore new file mode 100755 index 000000000..4dc009173 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.gitignore @@ -0,0 +1,2 @@ +/target +/bin diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.project b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.project new file mode 100755 index 000000000..716dff67e --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.project @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.fx.ui.keybindings.e4</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.pde.PluginNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.settings/org.eclipse.core.resources.prefs b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.settings/org.eclipse.core.resources.prefs new file mode 100755 index 000000000..99f26c020 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/<project>=UTF-8 diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.settings/org.eclipse.core.runtime.prefs b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.settings/org.eclipse.core.runtime.prefs new file mode 100755 index 000000000..deae05a97 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.settings/org.eclipse.core.runtime.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +line.separator=\r\n diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.settings/org.eclipse.jdt.core.prefs b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.settings/org.eclipse.jdt.core.prefs new file mode 100755 index 000000000..f42de363a --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/IP-TODO.txt b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/IP-TODO.txt new file mode 100755 index 000000000..42b873032 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/IP-TODO.txt @@ -0,0 +1 @@ +API extracted/ported/copied from from JFace & e4
\ No newline at end of file diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/META-INF/MANIFEST.MF b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/META-INF/MANIFEST.MF new file mode 100755 index 000000000..cecfbda9c --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/META-INF/MANIFEST.MF @@ -0,0 +1,20 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: E4 +Bundle-SymbolicName: org.eclipse.fx.ui.keybindings.e4 +Bundle-Version: 0.8.1.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.7 +Require-Bundle: org.eclipse.fx.ui.keybindings;bundle-version="0.8.1", + org.eclipse.e4.core.contexts;bundle-version="1.1.0", + org.eclipse.e4.core.di;bundle-version="1.1.0", + org.eclipse.core.commands;bundle-version="3.6.0", + org.eclipse.e4.ui.model.workbench;bundle-version="0.10.1", + org.eclipse.osgi.services;bundle-version="3.3.0", + org.eclipse.e4.core.commands;bundle-version="0.10.1", + org.eclipse.e4.core.services;bundle-version="1.0.0", + org.eclipse.e4.ui.services;bundle-version="0.10.1", + org.eclipse.e4.ui.workbench;bundle-version="0.10.2", + org.eclipse.fx.core;bundle-version="0.8.1" +Import-Package: javax.annotation;version="1.0.0", + javax.inject;version="1.0.0" +Export-Package: org.eclipse.fx.ui.keybindings.e4 diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/build.properties b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/build.properties new file mode 100755 index 000000000..34d2e4d2d --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/pom.xml b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/pom.xml new file mode 100755 index 000000000..b9a2528cc --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/pom.xml @@ -0,0 +1,34 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <name>e(fx)clipse - Runtime - e4 - e4 keybinding system</name> + <groupId>org.eclipse.fx</groupId> + <artifactId>org.eclipse.fx.ui.keybindings.e4</artifactId> + <packaging>eclipse-plugin</packaging> + + <parent> + <groupId>org.eclipse.fx</groupId> + <artifactId>releng</artifactId> + <relativePath>../../../releng/org.eclipse.fx.releng/pom.xml</relativePath> + <version>0.8.1-SNAPSHOT</version> + </parent> + + <build> + <resources> + <!-- to ensure that the feature lookup of the ui test works --> + <resource> + <directory>.</directory> + <includes> + <include>META-INF/</include> + </includes> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.eclipse.tycho</groupId> + <artifactId>tycho-source-plugin</artifactId> + </plugin> + </plugins> + </build> + +</project>
\ No newline at end of file diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/.DS_Store b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/.DS_Store Binary files differnew file mode 100644 index 000000000..5df2016a4 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/.DS_Store diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/BindingProcessingAddon.java b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/BindingProcessingAddon.java new file mode 100755 index 000000000..c8efd6f0b --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/BindingProcessingAddon.java @@ -0,0 +1,414 @@ +/******************************************************************************* + * Copyright (c) 2012 BestSolution.at 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: + * Tom Schindl<tom.schindl@bestsolution.at> - initial API and implementation + *******************************************************************************/ +package org.eclipse.fx.ui.keybindings.e4; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.inject.Inject; + +import org.eclipse.core.commands.ParameterizedCommand; +import org.eclipse.core.commands.contexts.Context; +import org.eclipse.core.commands.contexts.ContextManager; +import org.eclipse.e4.core.commands.ECommandService; +import org.eclipse.e4.core.contexts.IEclipseContext; +import org.eclipse.e4.core.services.events.IEventBroker; +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.MBindings; +import org.eclipse.e4.ui.model.application.commands.MCommand; +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.ui.MContext; +import org.eclipse.e4.ui.model.application.ui.MElementContainer; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.services.EContextService; +import org.eclipse.e4.ui.workbench.UIEvents; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.fx.core.log.Log; +import org.eclipse.fx.core.log.Logger; +import org.eclipse.fx.ui.keybindings.Binding; +import org.eclipse.fx.ui.keybindings.TriggerSequence; +import org.eclipse.fx.ui.keybindings.e4.internal.BindingTable; +import org.eclipse.fx.ui.keybindings.e4.internal.BindingTableManager; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; + +/** + * Process contexts in the model, feeding them into the command service. + */ +@SuppressWarnings("restriction") +public class BindingProcessingAddon { + + @Inject + private MApplication application; + + @Inject + private IEventBroker broker; + + @Inject + private ContextManager contextManager; + + @Inject + private BindingTableManager bindingTables; + + @Inject + private ECommandService commandService; + + @Inject + private EBindingService bindingService; + + @Inject + @Log + private Logger logger; + + private EventHandler additionHandler; + + private EventHandler contextHandler; + + @PostConstruct + public void init() { + defineBindingTables(); + activateContexts(application); + registerModelListeners(); + } + + private void activateContexts(Object me) { + if (me instanceof MBindings) { + MContext contextModel = (MContext) me; + MBindings container = (MBindings) me; + List<MBindingContext> bindingContexts = container + .getBindingContexts(); + IEclipseContext context = contextModel.getContext(); + if (context != null && !bindingContexts.isEmpty()) { + EContextService cs = context.get(EContextService.class); + for (MBindingContext element : bindingContexts) { + cs.activateContext(element.getElementId()); + } + } + } + if (me instanceof MElementContainer) { + List<MUIElement> children = ((MElementContainer) me).getChildren(); + Iterator<MUIElement> i = children.iterator(); + while (i.hasNext()) { + MUIElement e = i.next(); + activateContexts(e); + } + } + } + + private void defineBindingTables() { + for (MBindingTable bindingTable : application.getBindingTables()) { + defineBindingTable(bindingTable); + } + } + + /** + * @param bindingTable + */ + private void defineBindingTable(MBindingTable bindingTable) { + final Context bindingContext = contextManager.getContext(bindingTable + .getBindingContext().getElementId()); + BindingTable table = bindingTables.getTable(bindingTable + .getBindingContext().getElementId()); + if (table == null) { + table = new BindingTable(bindingContext); + bindingTables.addTable(table); + } + for (MKeyBinding binding : bindingTable.getBindings()) { + defineBinding(table, bindingContext, binding); + } + } + + /** + * @param bindingTable + * @param binding + */ + private void defineBinding(BindingTable bindingTable, + Context bindingContext, MKeyBinding binding) { + Binding keyBinding = createBinding(bindingContext, + binding.getCommand(), binding.getParameters(), + binding.getKeySequence(), binding); + if (keyBinding != null + && !binding.getTags().contains( + EBindingService.DELETED_BINDING_TAG)) { + bindingTable.addBinding(keyBinding); + } + } + + private Binding createBinding(Context bindingContext, MCommand cmdModel, + List<MParameter> modelParms, String keySequence, MKeyBinding binding) { + Binding keyBinding = null; + + if (binding.getTransientData() + .get(EBindingService.MODEL_TO_BINDING_KEY) != null) { + try { + keyBinding = (Binding) binding.getTransientData().get( + EBindingService.MODEL_TO_BINDING_KEY); + return keyBinding; + } catch (ClassCastException cce) { + System.err + .println("Invalid type stored in transient data with the key " + + EBindingService.MODEL_TO_BINDING_KEY); + return null; + } + } + + if (cmdModel == null) { + return null; + } + Map<String, Object> parameters = null; + if (modelParms != null && !modelParms.isEmpty()) { + parameters = new HashMap<String, Object>(); + for (MParameter mParm : modelParms) { + parameters.put(mParm.getName(), mParm.getValue()); + } + } + ParameterizedCommand cmd = commandService.createCommand( + cmdModel.getElementId(), parameters); + TriggerSequence sequence = null; + sequence = bindingService.createSequence(keySequence); + + if (cmd == null) { + logger.error("Failed to find command for binding: " + binding); //$NON-NLS-1$ + } else if (sequence == null) { + logger.error("Failed to map binding: " + binding); //$NON-NLS-1$ + } else { + try { + String schemeId = null; + String locale = null; + String platform = null; + + Map<String, String> attrs = new HashMap<String, String>(); + List<String> tags = binding.getTags(); + for (String tag : tags) { + // remember to skip the ':' in each tag! + if (tag.startsWith(EBindingService.SCHEME_ID_ATTR_TAG)) { + schemeId = tag.substring(9); + attrs.put(EBindingService.SCHEME_ID_ATTR_TAG, schemeId); + } else if (tag.startsWith(EBindingService.LOCALE_ATTR_TAG)) { + locale = tag.substring(7); + attrs.put(EBindingService.LOCALE_ATTR_TAG, locale); + } else if (tag + .startsWith(EBindingService.PLATFORM_ATTR_TAG)) { + platform = tag.substring(9); + attrs.put(EBindingService.PLATFORM_ATTR_TAG, platform); + } else if (tag.startsWith(EBindingService.TYPE_ATTR_TAG)) { + // system bindings won't pass this attr + attrs.put(EBindingService.TYPE_ATTR_TAG, "user"); + } + } + keyBinding = bindingService.createBinding(sequence, cmd, + bindingContext.getId(), attrs); + } catch (IllegalArgumentException e) { + logger.error("failed to create: " + binding, e); //$NON-NLS-1$ + return null; + } + + } + return keyBinding; + } + + private void updateBinding(MKeyBinding binding, boolean add, Object eObj) { + Object parentObj = ((EObject) binding).eContainer(); + if (!(parentObj instanceof MBindingTable)) { + // the link will already be broken for removes, so we'll try this + if (eObj instanceof MBindingTable) { + parentObj = eObj; + } + } + + if (parentObj == null) { + return; + } + + MBindingTable bt = (MBindingTable) parentObj; + final Context bindingContext = contextManager.getContext(bt + .getBindingContext().getElementId()); + BindingTable table = bindingTables.getTable(bindingContext.getId()); + if (table == null) { + logger.error("Trying to create \'" + binding //$NON-NLS-1$ + + "\' without binding table " + bindingContext.getId());//$NON-NLS-1$ + return; + } + Binding keyBinding = createBinding(bindingContext, + binding.getCommand(), binding.getParameters(), + binding.getKeySequence(), binding); + if (keyBinding != null) { + if (add) { + table.addBinding(keyBinding); + } else { + table.removeBinding(keyBinding); + } + } + } + + @PreDestroy + public void dispose() { + unregsiterModelListeners(); + } + + private void registerModelListeners() { + additionHandler = new EventHandler() { + public void handleEvent(Event event) { + Object elementObj = event + .getProperty(UIEvents.EventTags.ELEMENT); + if (elementObj instanceof MApplication) { + Object newObj = event + .getProperty(UIEvents.EventTags.NEW_VALUE); + if (UIEvents.EventTypes.ADD.equals(event + .getProperty(UIEvents.EventTags.TYPE)) + && newObj instanceof MBindingTable) { + MBindingTable bt = (MBindingTable) newObj; + final Context bindingContext = contextManager + .getContext(bt.getBindingContext() + .getElementId()); + final BindingTable table = new BindingTable( + bindingContext); + bindingTables.addTable(table); + List<MKeyBinding> bindings = bt.getBindings(); + for (MKeyBinding binding : bindings) { + Binding keyBinding = createBinding(bindingContext, + binding.getCommand(), + binding.getParameters(), + binding.getKeySequence(), binding); + if (keyBinding != null) { + table.addBinding(keyBinding); + } + } + } + } else if (elementObj instanceof MBindingTable) { + Object newObj = event + .getProperty(UIEvents.EventTags.NEW_VALUE); + Object oldObj = event + .getProperty(UIEvents.EventTags.OLD_VALUE); + + // adding a binding + if (UIEvents.EventTypes.ADD.equals(event + .getProperty(UIEvents.EventTags.TYPE)) + && newObj instanceof MKeyBinding) { + + MKeyBinding binding = (MKeyBinding) newObj; + updateBinding(binding, true, elementObj); + } + // removing a binding + else if (UIEvents.EventTypes.REMOVE.equals(event + .getProperty(UIEvents.EventTags.TYPE)) + && oldObj instanceof MKeyBinding) { + + MKeyBinding binding = (MKeyBinding) oldObj; + updateBinding(binding, false, elementObj); + } + } else if (elementObj instanceof MKeyBinding) { + MKeyBinding binding = (MKeyBinding) elementObj; + + String attrName = (String) event + .getProperty(UIEvents.EventTags.ATTNAME); + + if (UIEvents.EventTypes.SET.equals(event + .getProperty(UIEvents.EventTags.TYPE))) { + Object oldObj = event + .getProperty(UIEvents.EventTags.OLD_VALUE); + if (UIEvents.KeyBinding.COMMAND.equals(attrName)) { + MKeyBinding oldBinding = (MKeyBinding) EcoreUtil + .copy((EObject) binding); + oldBinding.setCommand((MCommand) oldObj); + updateBinding(oldBinding, false, + ((EObject) binding).eContainer()); + updateBinding(binding, true, null); + } else if (UIEvents.KeySequence.KEYSEQUENCE + .equals(attrName)) { + MKeyBinding oldBinding = (MKeyBinding) EcoreUtil + .copy((EObject) binding); + oldBinding.setKeySequence((String) oldObj); + updateBinding(oldBinding, false, + ((EObject) binding).eContainer()); + updateBinding(binding, true, null); + } + } else if (UIEvents.KeyBinding.PARAMETERS.equals(attrName)) { + if (UIEvents.EventTypes.ADD.equals(event + .getProperty(UIEvents.EventTags.TYPE))) { + Object newObj = event + .getProperty(UIEvents.EventTags.NEW_VALUE); + MKeyBinding oldBinding = (MKeyBinding) EcoreUtil + .copy((EObject) binding); + oldBinding.getParameters().remove(newObj); + updateBinding(oldBinding, false, + ((EObject) binding).eContainer()); + updateBinding(binding, true, null); + } else if (UIEvents.EventTypes.REMOVE.equals(event + .getProperty(UIEvents.EventTags.TYPE))) { + Object oldObj = event + .getProperty(UIEvents.EventTags.OLD_VALUE); + MKeyBinding oldBinding = (MKeyBinding) EcoreUtil + .copy((EObject) binding); + oldBinding.getParameters().add((MParameter) oldObj); + updateBinding(oldBinding, false, + ((EObject) binding).eContainer()); + updateBinding(binding, true, null); + } + } + // if we've updated the tags for an MKeyBinding + else if (UIEvents.ApplicationElement.TAGS.equals(attrName)) { + List<String> tags = binding.getTags(); + // if we added a deleted tag to the MKeyBinding, then + // remove it from the runtime binding tables + if (tags.contains(EBindingService.DELETED_BINDING_TAG)) { + updateBinding(binding, false, elementObj); + } + // else we're adding the binding to the runtime tables + else { + updateBinding(binding, true, elementObj); + } + } + } + } + }; + broker.subscribe(UIEvents.BindingTableContainer.TOPIC_BINDINGTABLES, + additionHandler); + broker.subscribe(UIEvents.BindingTable.TOPIC_BINDINGS, additionHandler); + broker.subscribe(UIEvents.KeyBinding.TOPIC_COMMAND, additionHandler); + broker.subscribe(UIEvents.KeyBinding.TOPIC_PARAMETERS, additionHandler); + broker.subscribe(UIEvents.KeySequence.TOPIC_KEYSEQUENCE, + additionHandler); + broker.subscribe(UIEvents.ApplicationElement.TOPIC_TAGS, + additionHandler); + + contextHandler = new EventHandler() { + public void handleEvent(Event event) { + Object elementObj = event + .getProperty(UIEvents.EventTags.ELEMENT); + Object newObj = event.getProperty(UIEvents.EventTags.NEW_VALUE); + if (UIEvents.EventTypes.SET.equals(event + .getProperty(UIEvents.EventTags.TYPE)) + && newObj instanceof IEclipseContext) { + activateContexts(elementObj); + } + } + }; + broker.subscribe(UIEvents.Context.TOPIC_CONTEXT, contextHandler); + } + + private void unregsiterModelListeners() { + broker.unsubscribe(additionHandler); + broker.unsubscribe(additionHandler); + broker.unsubscribe(additionHandler); + broker.unsubscribe(additionHandler); + broker.unsubscribe(additionHandler); + broker.unsubscribe(contextHandler); + } +} diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/BindingServiceAddon.java b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/BindingServiceAddon.java new file mode 100755 index 000000000..0822ed20f --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/BindingServiceAddon.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2010 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.fx.ui.keybindings.e4; + +import javax.annotation.PostConstruct; +import org.eclipse.core.commands.contexts.ContextManager; +import org.eclipse.e4.core.contexts.ContextInjectionFactory; +import org.eclipse.e4.core.contexts.IEclipseContext; +import org.eclipse.fx.ui.keybindings.e4.internal.BindingServiceCreationFunction; +import org.eclipse.fx.ui.keybindings.e4.internal.BindingTableManager; +import org.eclipse.fx.ui.keybindings.e4.internal.ContextSet; + + + +/** + * Provide the binding and context id services as an add-on. Must be instantiated against the + * application level context. + */ +@SuppressWarnings("restriction") +public class BindingServiceAddon { + @PostConstruct + public void init(IEclipseContext context) { + ContextManager contextManager = context.get(ContextManager.class); + ContextSet.setComparator(new ContextSet.CComp(contextManager)); + + context.set(BindingTableManager.class, + ContextInjectionFactory.make(BindingTableManager.class, context)); + + context.set(EBindingService.class.getName(), new BindingServiceCreationFunction()); + } +} diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/EBindingService.java b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/EBindingService.java new file mode 100755 index 000000000..380ce3f57 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/EBindingService.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 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.fx.ui.keybindings.e4; + +import java.util.Collection; +import java.util.Map; + +import org.eclipse.core.commands.ParameterizedCommand; +import org.eclipse.fx.ui.keybindings.Binding; +import org.eclipse.fx.ui.keybindings.TriggerSequence; + +public interface EBindingService { + + public static final String DIALOG_CONTEXT_ID = "org.eclipse.ui.contexts.dialog"; //$NON-NLS-1$ + public static final String DEFAULT_SCHEME_ID = "org.eclipse.ui.defaultAcceleratorConfiguration"; //$NON-NLS-1$ + public static final String MODEL_TO_BINDING_KEY = "binding"; //$NON-NLS-1$ + public static final String ACTIVE_SCHEME_TAG = "activeSchemeId"; //$NON-NLS-1$ + public static final String SCHEME_ID_ATTR_TAG = "schemeId"; //$NON-NLS-1$ + public static final String LOCALE_ATTR_TAG = "locale"; //$NON-NLS-1$ + public static final String PLATFORM_ATTR_TAG = "platform"; //$NON-NLS-1$ + public static final String TYPE_ATTR_TAG = "type"; //$NON-NLS-1$ + public static final String DELETED_BINDING_TAG = "deleted"; //$NON-NLS-1$ + + Binding createBinding(TriggerSequence sequence, ParameterizedCommand command, String contextId, + Map<String, String> attributes); + + void activateBinding(Binding binding); + + void deactivateBinding(Binding binding); + + TriggerSequence createSequence(String sequence); + + Collection<Binding> getConflictsFor(TriggerSequence sequence); + + Collection<Binding> getAllConflicts(); + + Binding getPerfectMatch(TriggerSequence trigger); + + boolean isPartialMatch(TriggerSequence keySequence); + + boolean isPerfectMatch(TriggerSequence sequence); + + TriggerSequence getBestSequenceFor(ParameterizedCommand command); + + Collection<TriggerSequence> getSequencesFor(ParameterizedCommand command); + + Collection<Binding> getPartialMatches(TriggerSequence sequence); + + Collection<Binding> getActiveBindings(); + + Collection<Binding> getBindingsFor(ParameterizedCommand cmd); +} diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/internal/BindingServiceCreationFunction.java b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/internal/BindingServiceCreationFunction.java new file mode 100755 index 000000000..4eec74f6b --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/internal/BindingServiceCreationFunction.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 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.fx.ui.keybindings.e4.internal; + +import org.eclipse.e4.core.contexts.ContextFunction; +import org.eclipse.e4.core.contexts.ContextInjectionFactory; +import org.eclipse.e4.core.contexts.IEclipseContext; + +/** + * + */ +@SuppressWarnings("restriction") +public class BindingServiceCreationFunction extends ContextFunction { + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.e4.core.services.context.spi.ContextFunction#compute(org.eclipse.e4.core.services + * .context.IEclipseContext, java.lang.Object[]) + */ + @Override + public Object compute(IEclipseContext context) { + return ContextInjectionFactory.make(BindingServiceImpl.class, context); + } + +} diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/internal/BindingServiceImpl.java b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/internal/BindingServiceImpl.java new file mode 100755 index 000000000..7fa82f525 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/internal/BindingServiceImpl.java @@ -0,0 +1,263 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 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.fx.ui.keybindings.e4.internal; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.eclipse.core.commands.ParameterizedCommand; +import org.eclipse.core.commands.contexts.Context; +import org.eclipse.core.commands.contexts.ContextManager; +import org.eclipse.e4.core.contexts.IEclipseContext; +import org.eclipse.e4.core.di.annotations.Optional; +import org.eclipse.fx.ui.keybindings.Binding; +import org.eclipse.fx.ui.keybindings.KeyLookup; +import org.eclipse.fx.ui.keybindings.ParseException; +import org.eclipse.fx.ui.keybindings.TriggerSequence; +import org.eclipse.fx.ui.keybindings.e4.EBindingService; +import org.eclipse.fx.ui.keybindings.service.BindingFactory; + +/** + * + */ +@SuppressWarnings("restriction") +public class BindingServiceImpl implements EBindingService { + + final static String ACTIVE_CONTEXTS = "activeContexts"; //$NON-NLS-1$ + final static String USER_TYPE = "user"; //$NON-NLS-1$ + + @Inject + private IEclipseContext context; + + @Inject + private BindingTableManager manager; + + @Inject + private ContextManager contextManager; + + @Inject + private KeyLookup keylookup; + + @Inject + private BindingFactory factory; + + private ContextSet contextSet = ContextSet.EMPTY; + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.e4.ui.bindings.EBindingService#createBinding(org.eclipse. + * jface.bindings. TriggerSequence, + * org.eclipse.core.commands.ParameterizedCommand, java.lang.String, + * java.lang.String, java.util.Map) + */ + public Binding createBinding(TriggerSequence sequence, + ParameterizedCommand command, String contextId, + Map<String, String> attributes) { + + String schemeId = DEFAULT_SCHEME_ID; + // String locale = null; + // String platform = null; + // int bindingType = Binding.SYSTEM; + + if (sequence != null && !sequence.isEmpty() && contextId != null) { + if (attributes != null) { + String tmp = attributes.get(SCHEME_ID_ATTR_TAG); + if (tmp != null && tmp.length() > 0) { + schemeId = tmp; + } + // locale = attributes.get(LOCALE_ATTR_TAG); + // platform = attributes.get(PLATFORM_ATTR_TAG); + // if (USER_TYPE.equals(attributes.get(TYPE_ATTR_TAG))) { + // bindingType = Binding.USER; + // } + } + return factory.createKeyBinding(sequence, command, schemeId, + contextId); + // return factory.createKeyBinding((EKeySequence) sequence, command, + // schemeId, contextId, locale, + // platform, null, bindingType); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.e4.ui.bindings.EBindingService#activateBinding(org.eclipse + * .jface.bindings.Binding ) + */ + public void activateBinding(Binding binding) { + String contextId = binding.getContextId(); + BindingTable table = manager.getTable(contextId); + if (table == null) { + return; + } + table.addBinding(binding); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.e4.ui.bindings.EBindingService#deactivateBinding(org.eclipse + * .jface.bindings.Binding ) + */ + public void deactivateBinding(Binding binding) { + String contextId = binding.getContextId(); + BindingTable table = manager.getTable(contextId); + if (table == null) { + return; + } + table.removeBinding(binding); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.e4.ui.bindings.EBindingService#createSequence(java.lang.String + * ) + */ + public TriggerSequence createSequence(String sequence) { + try { + return factory.getKeySequenceInstance(keylookup, sequence); + } catch (ParseException e) { + // should probably log + } + return null; + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.e4.ui.bindings.EBindingService#getConflictsFor(org.eclipse + * .e4.ui.bindings. TriggerSequence) + */ + public Collection<Binding> getConflictsFor(TriggerSequence sequence) { + return manager.getConflictsFor(contextSet, sequence); + } + + public Collection<Binding> getAllConflicts() { + return manager.getAllConflicts(); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.e4.ui.bindings.EBindingService#getPerfectMatch(org.eclipse + * .e4.ui.bindings. TriggerSequence) + */ + public Binding getPerfectMatch(TriggerSequence trigger) { + return manager.getPerfectMatch(contextSet, trigger); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.e4.ui.bindings.EBindingService#isPartialMatch(org.eclipse. + * e4.ui.bindings. TriggerSequence) + */ + public boolean isPartialMatch(TriggerSequence keySequence) { + return manager.isPartialMatch(contextSet, keySequence); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.e4.ui.bindings.EBindingService#getBestSequenceFor(org.eclipse + * .core.commands. ParameterizedCommand) + */ + public TriggerSequence getBestSequenceFor(ParameterizedCommand command) { + Binding binding = manager.getBestSequenceFor(contextSet, command); + return binding == null ? null : binding.getTriggerSequence(); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.e4.ui.bindings.EBindingService#getSequencesFor(org.eclipse + * .core.commands. ParameterizedCommand) + */ + public Collection<TriggerSequence> getSequencesFor( + ParameterizedCommand command) { + Collection<Binding> bindings = manager.getSequencesFor(contextSet, + command); + ArrayList<TriggerSequence> sequences = new ArrayList<TriggerSequence>( + bindings.size()); + for (Binding binding : bindings) { + sequences.add(binding.getTriggerSequence()); + } + return sequences; + } + + public Collection<Binding> getBindingsFor(ParameterizedCommand command) { + return manager.getBindingsFor(contextSet, command); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.e4.ui.bindings.EBindingService#isPerfectMatch(org.eclipse. + * e4.ui.bindings. TriggerSequence) + */ + public boolean isPerfectMatch(TriggerSequence sequence) { + return getPerfectMatch(sequence) != null; + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.e4.ui.bindings.EBindingService#getPartialMatches(org.eclipse + * .e4.ui.bindings. TriggerSequence) + */ + public Collection<Binding> getPartialMatches(TriggerSequence sequence) { + return manager.getPartialMatches(contextSet, sequence); + } + + /** + * @return the context for this service. + */ + public IEclipseContext getContext() { + return context; + } + + @Inject + public void setContextIds(@Named(ACTIVE_CONTEXTS) @Optional Set<String> set) { + if (set == null || set.isEmpty() || contextManager == null) { + contextSet = ContextSet.EMPTY; + if (contextManager != null) { + contextManager.setActiveContextIds(Collections.EMPTY_SET); + } + return; + } + ArrayList<Context> contexts = new ArrayList<Context>(); + for (String id : set) { + contexts.add(contextManager.getContext(id)); + } + contextSet = manager.createContextSet(contexts); + contextManager.setActiveContextIds(set); + } + + public Collection<Binding> getActiveBindings() { + return manager.getActiveBindings(); + } + +} diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/internal/BindingTable.java b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/internal/BindingTable.java new file mode 100755 index 000000000..35081483b --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/internal/BindingTable.java @@ -0,0 +1,291 @@ +/******************************************************************************* + * Copyright (c) 2010 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.fx.ui.keybindings.e4.internal; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.commands.ParameterizedCommand; +import org.eclipse.core.commands.contexts.Context; +import org.eclipse.fx.ui.keybindings.Binding; +import org.eclipse.fx.ui.keybindings.KeyStroke; +import org.eclipse.fx.ui.keybindings.Trigger; +import org.eclipse.fx.ui.keybindings.TriggerSequence; + +/** + * manage tables of bindings that can be used to look up commands from keys. + */ +public class BindingTable { + static class BindingComparator implements Comparator<Binding> { + private String[] activeSchemeIds; + + private final int compareSchemes(final String schemeId1, final String schemeId2) { + if (activeSchemeIds == null || activeSchemeIds.length == 0) { + 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; + } + + public void setActiveSchemes(String[] activeSchemeIds) { + this.activeSchemeIds = activeSchemeIds; + } + + public int compare(Binding o1, Binding o2) { + int rc = compareSchemes(o1.getSchemeId(), o2.getSchemeId()); + if (rc != 0) { + return rc; + } + + /* + * Check to see which has the least number of triggers in the trigger sequence. + */ + final Trigger[] bestTriggers = o1.getTriggerSequence().getTriggers(); + final Trigger[] currentTriggers = o2.getTriggerSequence().getTriggers(); + int compareTo = bestTriggers.length - currentTriggers.length; + if (compareTo != 0) { + return compareTo; + } + + /* + * Compare the number of keys pressed in each trigger sequence. Some types of keys count + * less than others (i.e., some types of modifiers keys are less likely to be chosen). + */ + compareTo = countStrokes(bestTriggers) - countStrokes(currentTriggers); + if (compareTo != 0) { + return compareTo; + } + + // If this is still a tie, then just chose the shortest text. + return o1.getTriggerSequence().format().length() + - o2.getTriggerSequence().format().length(); + } + + private final int countStrokes(final Trigger[] triggers) { + int strokeCount = triggers.length; + for (int i = 0; i < triggers.length; i++) { + final Trigger trigger = triggers[i]; + if (trigger instanceof KeyStroke) { + final KeyStroke keyStroke = (KeyStroke) trigger; + if( keyStroke.hasAltModifier() ) { + strokeCount += 8; + } + if( keyStroke.hasCtrlModifier() ) { + strokeCount += 2; + } + if( keyStroke.hasShiftModifier() ) { + strokeCount += 4; + } + if( keyStroke.hasCommandModifier() ) { + strokeCount += 2; + } + + +// final int modifierKeys = keyStroke.getModifierKeys(); +// final IKeyLookup lookup = KeyLookupFactory.getDefault(); +// if ((modifierKeys & lookup.getAlt()) != 0) { +// strokeCount += 8; +// } +// if ((modifierKeys & lookup.getCtrl()) != 0) { +// strokeCount += 2; +// } +// if ((modifierKeys & lookup.getShift()) != 0) { +// strokeCount += 4; +// } +// if ((modifierKeys & lookup.getCommand()) != 0) { +// strokeCount += 2; +// } + } else { + strokeCount += 99; + } + } + + return strokeCount; + } + } + + public static final BindingComparator BEST_SEQUENCE = new BindingComparator(); + + private Context tableId; + private ArrayList<Binding> bindings = new ArrayList<Binding>(); + private Map<TriggerSequence, Binding> bindingsByTrigger = new HashMap<TriggerSequence, Binding>(); + private Map<ParameterizedCommand, ArrayList<Binding>> bindingsByCommand = new HashMap<ParameterizedCommand, ArrayList<Binding>>(); + private Map<TriggerSequence, ArrayList<Binding>> bindingsByPrefix = new HashMap<TriggerSequence, ArrayList<Binding>>(); + private Map<TriggerSequence, ArrayList<Binding>> conflicts = new HashMap<TriggerSequence, ArrayList<Binding>>(); + + /** + * @param context + */ + public BindingTable(Context context) { + tableId = context; + } + + public Context getTableId() { + return tableId; + } + + public String getId() { + return tableId.getId(); + } + + public Collection<Binding> getConflicts() { + Collection<Binding> conflictsList = new ArrayList<Binding>(); + for (TriggerSequence key : conflicts.keySet()) { + ArrayList<Binding> conflictsForTrigger = conflicts.get(key); + if (conflictsForTrigger != null) { + conflictsList.addAll(conflictsForTrigger); + } + } + return conflictsList; + } + + // checks both the active bindings and conflicts list + public Collection<Binding> getConflictsFor(TriggerSequence triggerSequence) { + return conflicts.get(triggerSequence); + } + + public void addBinding(Binding binding) { + if (!getId().equals(binding.getContextId())) { + throw new IllegalArgumentException("Binding context " + binding.getContextId() //$NON-NLS-1$ + + " does not match " + getId()); //$NON-NLS-1$ + } + + Binding conflict; + ArrayList<Binding> conflictsList; + boolean isConflict = false; + + // if this binding conflicts with one other active binding + if (bindingsByTrigger.containsKey(binding.getTriggerSequence())) { + // remove the active binding and put it in the conflicts map + conflict = bindingsByTrigger.get(binding.getTriggerSequence()); + removeBinding(conflict); + conflictsList = new ArrayList<Binding>(); + conflictsList.add(conflict); + conflicts.put(binding.getTriggerSequence(), conflictsList); + isConflict = true; + } + // if this trigger is already in the conflicts map + if (conflicts.containsKey(binding.getTriggerSequence()) + && conflicts.get(binding.getTriggerSequence()).size() > 0) { + + // add this binding to the conflicts map + conflictsList = conflicts.get(binding.getTriggerSequence()); + if (!conflictsList.contains(binding)) { + conflictsList.add(binding); + } + isConflict = true; + } + + // if there are no conflicts, then add to the table + if (!isConflict) { + bindings.add(binding); + bindingsByTrigger.put(binding.getTriggerSequence(), binding); + + ArrayList<Binding> sequences = bindingsByCommand.get(binding.getParameterizedCommand()); + if (sequences == null) { + sequences = new ArrayList<Binding>(); + bindingsByCommand.put(binding.getParameterizedCommand(), sequences); + } + sequences.add(binding); + Collections.sort(sequences, BEST_SEQUENCE); + + TriggerSequence[] prefs = binding.getTriggerSequence().getPrefixes(); + for (int i = 1; i < prefs.length; i++) { + ArrayList<Binding> bindings = bindingsByPrefix.get(prefs[i]); + if (bindings == null) { + bindings = new ArrayList<Binding>(); + bindingsByPrefix.put(prefs[i], bindings); + } + bindings.add(binding); + } + } + } + + public void removeBinding(Binding binding) { + if (!getId().equals(binding.getContextId())) { + throw new IllegalArgumentException("Binding context " + binding.getContextId() //$NON-NLS-1$ + + " does not match " + getId()); //$NON-NLS-1$ + } + ArrayList<Binding> conflictBindings = conflicts.get(binding.getTriggerSequence()); + + // if this binding is in the conflicts map, then remove it + if (!bindingsByTrigger.containsKey(binding.getTriggerSequence()) + && conflictBindings != null) { + + conflictBindings.remove(binding); + + // if there is only one binding left in the list, then it's not really a conflict + // binding anymore and can be re-added to the binding table + if (conflictBindings.size() == 1) { + Binding bindingToReAdd = conflictBindings.remove(0); + addBinding(bindingToReAdd); + } + + } else { + bindings.remove(binding); + bindingsByTrigger.remove(binding.getTriggerSequence()); + ArrayList<Binding> sequences = bindingsByCommand.get(binding.getParameterizedCommand()); + + if (sequences != null) { + sequences.remove(binding); + } + TriggerSequence[] prefs = binding.getTriggerSequence().getPrefixes(); + for (int i = 1; i < prefs.length; i++) { + ArrayList<Binding> bindings = bindingsByPrefix.get(prefs[i]); + bindings.remove(binding); + } + } + } + + public Binding getPerfectMatch(TriggerSequence trigger) { + return bindingsByTrigger.get(trigger); + } + + public Binding getBestSequenceFor(ParameterizedCommand command) { + ArrayList<Binding> sequences = bindingsByCommand.get(command); + if (sequences != null && sequences.size() > 0) { + return sequences.get(0); + } + return null; + } + + public Collection<Binding> getSequencesFor(ParameterizedCommand command) { + ArrayList<Binding> triggers = bindingsByCommand.get(command); + return (Collection<Binding>) (triggers == null ? Collections.EMPTY_LIST : triggers.clone()); + } + + public Collection<Binding> getPartialMatches(TriggerSequence sequence) { + return bindingsByPrefix.get(sequence); + } + + public boolean isPartialMatch(TriggerSequence seq) { + return bindingsByPrefix.get(seq) != null; + } + + public Collection<Binding> getBindings() { + return Collections.unmodifiableCollection(bindings); + } + +} diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/internal/BindingTableManager.java b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/internal/BindingTableManager.java new file mode 100755 index 000000000..809ee61f3 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/internal/BindingTableManager.java @@ -0,0 +1,270 @@ +/******************************************************************************* + * Copyright (c) 2010 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.fx.ui.keybindings.e4.internal; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.ListIterator; + +import javax.inject.Inject; + +import org.eclipse.core.commands.ParameterizedCommand; +import org.eclipse.core.commands.contexts.Context; +import org.eclipse.e4.core.contexts.IEclipseContext; +import org.eclipse.fx.ui.keybindings.Binding; +import org.eclipse.fx.ui.keybindings.TriggerSequence; + + +/** + * manage tables of bindings that can be used to look up commands from keys. + */ +@SuppressWarnings("restriction") +public class BindingTableManager { + private static final String BINDING_TABLE_PREFIX = "bindingTable:"; //$NON-NLS-1$ + + @Inject + private IEclipseContext eclipseContext; + + private ContextSet definedTables = ContextSet.EMPTY; + + private String[] activeSchemeIds; + + public void addTable(BindingTable table) { + String contextId = getTableId(table.getId()); + if (eclipseContext.containsKey(contextId)) { + return; // it's already there + // throw new IllegalArgumentException("Already contains table " + contextId); //$NON-NLS-1$ + } + eclipseContext.set(contextId, table); + final List<Context> contexts = definedTables.getContexts(); + if (!contexts.contains(table.getTableId())) { + // this is only valid because I'm throwing away the old definedTables contextSet + contexts.add(table.getTableId()); + definedTables = createContextSet(contexts); + } + } + + private String getTableId(String id) { + return BINDING_TABLE_PREFIX + id; + } + + public void removeTable(BindingTable table) { + String contextId = getTableId(table.getId()); + if (!eclipseContext.containsKey(contextId)) { + throw new IllegalArgumentException("Does not contains table " + contextId); //$NON-NLS-1$ + } + eclipseContext.remove(contextId); + final List<Context> contexts = definedTables.getContexts(); + if (contexts.contains(table.getTableId())) { + // this is only valid because I'm throwing away the old definedTables contextSet + contexts.remove(table.getTableId()); + definedTables = createContextSet(contexts); + } + } + + public BindingTable getTable(String id) { + return (BindingTable) eclipseContext.get(getTableId(id)); + } + + // we're just going through each binding table, and returning a + // flat list of bindings here + public Collection<Binding> getActiveBindings() { + ArrayList<Binding> bindings = new ArrayList<Binding>(); + for (Context ctx : definedTables.getContexts()) { + BindingTable table = getTable(ctx.getId()); + if (table != null) { + bindings.addAll(table.getBindings()); + } + } + return bindings; + } + + public ContextSet createContextSet(Collection<Context> contexts) { + return new ContextSet(contexts); + } + + public Collection<Binding> getConflictsFor(ContextSet contextSet, + TriggerSequence triggerSequence) { + Collection<Binding> matches = new ArrayList<Binding>(); + for (Context ctx : contextSet.getContexts()) { + BindingTable table = getTable(ctx.getId()); + if (table != null) { + final Collection<Binding> matchesFor = table.getConflictsFor(triggerSequence); + if (matchesFor != null) { + matches.addAll(matchesFor); + } + } + } + return matches.size() == 0 ? null : matches; + } + + public Collection<Binding> getAllConflicts() { + Collection<Binding> conflictsList = new ArrayList<Binding>(); + for (Context ctx : definedTables.getContexts()) { + BindingTable table = getTable(ctx.getId()); + if (table != null) { + Collection<Binding> conflictsInTable = table.getConflicts(); + if (conflictsInTable != null) { + conflictsList.addAll(conflictsInTable); + } + } + } + return conflictsList; + } + + public Binding getPerfectMatch(ContextSet contextSet, TriggerSequence triggerSequence) { + Binding result = null; + Binding currentResult = null; + List<Context> contexts = contextSet.getContexts(); + ListIterator<Context> it = contexts.listIterator(contexts.size()); + while (it.hasPrevious()) { + Context c = it.previous(); + BindingTable table = getTable(c.getId()); + if (table != null) { + currentResult = table.getPerfectMatch(triggerSequence); + } + if (currentResult != null) { + if (isMostActiveScheme(currentResult)) { + return currentResult; + } + if (result == null) { + result = currentResult; + } else { + int rc = compareSchemes(result.getSchemeId(), currentResult.getSchemeId()); + if (rc < 0) { + result = currentResult; + } + } + } + } + return result; + } + + /** + * @param currentResult + * @return + */ + private boolean isMostActiveScheme(Binding currentResult) { + if (activeSchemeIds == null || activeSchemeIds.length < 2) { + return true; + } + final String mostActive = activeSchemeIds[0]; + return mostActive == null ? false : mostActive.equals(currentResult.getSchemeId()); + } + + public Binding getBestSequenceFor(ContextSet contextSet, + ParameterizedCommand parameterizedCommand) { + ArrayList<Binding> bindings = (ArrayList<Binding>) getSequencesFor(contextSet, + parameterizedCommand); + if (bindings.size() == 0) { + return null; + } + return bindings.get(0); + } + + public Collection<Binding> getSequencesFor(ContextSet contextSet, + ParameterizedCommand parameterizedCommand) { + ArrayList<Binding> bindings = new ArrayList<Binding>(); + List<Context> contexts = contextSet.getContexts(); + ListIterator<Context> it = contexts.listIterator(contexts.size()); + while (it.hasPrevious()) { + Context c = it.previous(); + BindingTable table = getTable(c.getId()); + if (table != null) { + Collection<Binding> sequences = table.getSequencesFor(parameterizedCommand); + if (sequences != null) { + bindings.addAll(sequences); + } + } + } + Collections.sort(bindings, BindingTable.BEST_SEQUENCE); + return bindings; + } + + public Collection<Binding> getBindingsFor(ContextSet contextSet, ParameterizedCommand cmd) { + Collection<Binding> bindings = new ArrayList<Binding>(); + for (Context ctx : contextSet.getContexts()) { + BindingTable table = getTable(ctx.getId()); + if (table != null) { + Collection<Binding> matches = table.getSequencesFor(cmd); + if (matches != null) { + bindings.addAll(matches); + } + } + } + return bindings; + } + + public boolean isPartialMatch(ContextSet contextSet, TriggerSequence sequence) { + List<Context> contexts = contextSet.getContexts(); + ListIterator<Context> it = contexts.listIterator(contexts.size()); + while (it.hasPrevious()) { + Context c = it.previous(); + BindingTable table = getTable(c.getId()); + if (table != null) { + if (table.isPartialMatch(sequence)) { + return true; + } + } + } + return false; + } + + public Collection<Binding> getPartialMatches(ContextSet contextSet, TriggerSequence sequence) { + ArrayList<Binding> bindings = new ArrayList<Binding>(); + List<Context> contexts = contextSet.getContexts(); + ListIterator<Context> it = contexts.listIterator(contexts.size()); + while (it.hasPrevious()) { + Context c = it.previous(); + BindingTable table = getTable(c.getId()); + if (table != null) { + Collection<Binding> partialMatches = table.getPartialMatches(sequence); + if (partialMatches != null) { + bindings.addAll(partialMatches); + } + } + } + return bindings; + } + + /** + * @param activeSchemeIds + */ + public void setActiveSchemes(String[] activeSchemeIds) { + this.activeSchemeIds = activeSchemeIds; + BindingTable.BEST_SEQUENCE.setActiveSchemes(activeSchemeIds); + } + + /* + * 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; + } +} diff --git a/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/internal/ContextSet.java b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/internal/ContextSet.java new file mode 100755 index 000000000..63c2ce316 --- /dev/null +++ b/bundles/runtime/org.eclipse.fx.ui.keybindings.e4/src/org/eclipse/fx/ui/keybindings/e4/internal/ContextSet.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2010 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.fx.ui.keybindings.e4.internal; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import org.eclipse.core.commands.common.NotDefinedException; +import org.eclipse.core.commands.contexts.Context; +import org.eclipse.core.commands.contexts.ContextManager; + +public class ContextSet { + public static ContextSet EMPTY = new ContextSet(Collections.EMPTY_LIST); + + public static class CComp implements Comparator<Context> { + private ContextManager manager; + + public CComp(ContextManager manager) { + this.manager = manager; + } + + public int compare(Context o1, Context o2) { + if (o1.equals(o2)) { + return 0; + } + int l1 = getLevel(o1); + int l2 = getLevel(o2); + if (l1 != l2) { + return l1 - l2; + } + return o1.getId().compareTo(o2.getId()); + } + + private int getLevel(Context c) { + int l = 0; + try { + String parentId = c.getParentId(); + while (parentId != null) { + l++; + Context context = manager.getContext(parentId); + parentId = context.getParentId(); + } + } catch (NotDefinedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return l; + } + } + + private static Comparator<Context> CONTEXT_COMP = null; + + public static void setComparator(Comparator<Context> comp) { + CONTEXT_COMP = comp; + } + + public static Comparator<Context> getComparator() { + return CONTEXT_COMP; + } + + private List<Context> contexts; + + public ContextSet(Collection<Context> c) { + contexts = new ArrayList<Context>(c); + Collections.sort(contexts, CONTEXT_COMP); + } + + public List<Context> getContexts() { + return contexts; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof ContextSet)) { + return false; + } + return contexts.equals(((ContextSet) o).contexts); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return contexts.hashCode(); + } +} diff --git a/releng/org.eclipse.fx.releng/pom.xml b/releng/org.eclipse.fx.releng/pom.xml index 5841b14b0..09ed1b15d 100755 --- a/releng/org.eclipse.fx.releng/pom.xml +++ b/releng/org.eclipse.fx.releng/pom.xml @@ -46,6 +46,7 @@ <!-- e4 --> <module>../../bundles/runtime/org.eclipse.fx.ui.keybindings</module> <module>../../bundles/runtime/org.eclipse.fx.ui.keybindings.generic</module> + <module>../../bundles/runtime/org.eclipse.fx.ui.keybindings.e4</module> <!-- Format Conversion --> <module>../../bundles/runtime/org.eclipse.fx.formats.svg</module> |