Bug 344181 - [Compatibility] Not all emacs keybindings override default keybindings
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/keys/BindingService.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/keys/BindingService.java
index 2b36cc7..a8a39c1 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/keys/BindingService.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/keys/BindingService.java
@@ -11,6 +11,7 @@
package org.eclipse.ui.internal.keys;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -78,6 +79,8 @@
private Map<String, MBindingContext> bindingContexts = new HashMap<String, MBindingContext>();
+ private String[] activeSchemeIds;
+
/*
* (non-Javadoc)
*
@@ -371,6 +374,7 @@
// save the active scheme to the model
writeSchemeToModel(activeScheme);
+ activeSchemeIds = getSchemeIds(activeScheme.getId());
// weeds out any of the deleted system bindings using the binding
// manager
@@ -409,16 +413,108 @@
// see if there are any bindings that we should add to the runtime
for (Binding binding : activeBindings) {
final MKeyBinding model = bindingToKey.get(binding);
- // if we found the binding but it's marked as deleted, then just
- // remove the deleted tag
- if (model != null) {
- if (model.getTags().contains(EBindingService.DELETED_BINDING_TAG)) {
- model.getTags().remove(EBindingService.DELETED_BINDING_TAG);
+ MKeyBinding toAddModel = model;
+ Binding toAddBinding = binding;
+
+ // if we've switched schemes then we need to check to see if we
+ // should override any of the old bindings
+ final Binding conflict = bindingService.getPerfectMatch(binding.getTriggerSequence());
+
+ if (conflict != null && conflict.getContextId().equals(binding.getContextId())) {
+ final int rc = compareTo(conflict, binding);
+ if (rc < 0) {
+ // we need to delete the existing binding
+ final MKeyBinding conflictModel = bindingToKey.get(conflict);
+ if (conflict.getType() == Binding.USER) {
+ removeBinding(conflict);
+ } else if (conflictModel != null) {
+ if (!conflictModel.getTags().contains(EBindingService.DELETED_BINDING_TAG)) {
+ conflictModel.getTags().add(EBindingService.DELETED_BINDING_TAG);
+ }
+ }
+ } else if (rc > 0) {
+ // the existing binding is correct
+ // we need to delete the new binding
+ if (binding.getType() == Binding.USER) {
+ removeBinding(binding);
+ } else if (model != null) {
+ if (!model.getTags().contains(EBindingService.DELETED_BINDING_TAG)) {
+ model.getTags().add(EBindingService.DELETED_BINDING_TAG);
+ }
+ }
+ // make sure we don't re-add them
+ toAddModel = null;
+ toAddBinding = null;
}
- } else {
- addBinding(binding);
+ }
+ if (toAddModel != null) {
+ if (toAddModel.getTags().contains(EBindingService.DELETED_BINDING_TAG)) {
+ toAddModel.getTags().remove(EBindingService.DELETED_BINDING_TAG);
+ }
+ } else if (toAddBinding != null) {
+ addBinding(toAddBinding);
+ }
+
+ }
+ }
+
+ private final String[] getSchemeIds(String schemeId) {
+ final List<String> strings = new ArrayList<String>();
+ while (schemeId != null) {
+ strings.add(schemeId);
+ try {
+ schemeId = getScheme(schemeId).getParentId();
+ } catch (final NotDefinedException e) {
+ return new String[0];
}
}
+
+ return strings.toArray(new String[strings.size()]);
+ }
+
+ /*
+ * Copied from
+ * org.eclipse.jface.bindings.BindingManager.compareSchemes(String, String)
+ *
+ * Returns an in based on scheme 1 < scheme 2
+ */
+ private final int compareSchemes(final String schemeId1, final String schemeId2) {
+ if (activeSchemeIds == null) {
+ return 0;
+ }
+ if (!schemeId2.equals(schemeId1)) {
+ for (int i = 0; i < activeSchemeIds.length; i++) {
+ final String schemePointer = activeSchemeIds[i];
+ if (schemeId2.equals(schemePointer)) {
+ return 1;
+ } else if (schemeId1.equals(schemePointer)) {
+ return -1;
+ }
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Compare 2 bindings, taking into account Scheme and type.
+ *
+ * @param current
+ * the existing binding
+ * @param addition
+ * the incoming binding
+ * @return an int indicating current > addition
+ */
+ private int compareTo(Binding current, Binding addition) {
+ final Scheme s1 = manager.getScheme(current.getSchemeId());
+ final Scheme s2 = manager.getScheme(addition.getSchemeId());
+ if (!s1.equals(s2)) {
+ int rc = compareSchemes(s1.getId(), s2.getId());
+ if (rc != 0) {
+ // this is because the compare is inverted
+ return rc > 0 ? -1 : 1;
+ }
+ }
+ return current.getType() - addition.getType();
}