Bug 335985 - Adapt the KeyController model to the e4 model
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/BindingToModelProcessor.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/BindingToModelProcessor.java
index 3e5fa44..d587832 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/BindingToModelProcessor.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/BindingToModelProcessor.java
@@ -11,15 +11,15 @@
 
 package org.eclipse.ui.internal;
 
+import java.util.Collection;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import org.eclipse.core.commands.CommandManager;
 import org.eclipse.core.commands.ParameterizedCommand;
 import org.eclipse.core.commands.contexts.ContextManager;
 import org.eclipse.e4.core.di.annotations.Execute;
-import org.eclipse.e4.ui.bindings.internal.BindingCopies;
+import org.eclipse.e4.ui.bindings.EBindingService;
 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;
@@ -44,8 +44,6 @@
 	private Map<String, MCommand> commands = new HashMap<String, MCommand>();
 	private Map<String, MBindingTable> tables = new HashMap<String, MBindingTable>();
 
-
-
 	@Execute
 	void process(final MApplication application) {
 		gatherContexts(application.getRootContext());
@@ -61,11 +59,19 @@
 		BindingManager bindingManager = new BindingManager(contextManager, commandManager);
 		BindingPersistence persistence = new BindingPersistence(bindingManager, commandManager);
 		persistence.read();
-		Iterator i = bindingManager.getActiveBindingsDisregardingContextFlat().iterator();
-		while (i.hasNext()) {
-			Binding binding = (Binding) i.next();
+
+		// we'll make this available, although I doubt we have a use for it
+		application.getTags().add(
+				EBindingService.ACTIVE_SCHEME_TAG + ':' + bindingManager.getActiveScheme().getId());
+
+		Collection activeBindingsForScheme = bindingManager
+				.getActiveBindingsDisregardingContextFlat();
+
+		for (Object obj : activeBindingsForScheme) {
+			Binding binding = (Binding) obj;
 			addBinding(application, binding);
 		}
+
 		persistence.dispose();
 	}
 
@@ -80,14 +86,9 @@
 
 	public final void addBinding(final MApplication application, final Binding binding) {
 
-		if (binding.getType() == Binding.USER) {
-			BindingCopies.addUserBinding(binding);
-		}
-
 		MBindingTable table = tables.get(binding.getContextId());
 		if (table == null) {
 			table = createTable(application, binding.getContextId());
-
 		}
 		final MKeyBinding keyBinding = CommandsFactoryImpl.eINSTANCE.createKeyBinding();
 		ParameterizedCommand parmCmd = binding.getParameterizedCommand();
@@ -106,6 +107,27 @@
 			p.setValue((String) entry.getValue());
 			keyBinding.getParameters().add(p);
 		}
+
+		List<String> tags = keyBinding.getTags();
+		// just add the 'schemeId' tag if it's anything other than the default
+		// scheme id
+		if (binding.getSchemeId() != null
+				&& !binding.getSchemeId().equals(
+						org.eclipse.ui.keys.IBindingService.DEFAULT_DEFAULT_ACTIVE_SCHEME_ID)) {
+			tags.add(EBindingService.SCHEME_ID_ATTR_TAG + ":" + binding.getSchemeId()); //$NON-NLS-1$
+		}
+		if (binding.getLocale() != null) {
+			tags.add(EBindingService.LOCALE_ATTR_TAG + ":" + binding.getLocale()); //$NON-NLS-1$
+		}
+		if (binding.getPlatform() != null) {
+			tags.add(EBindingService.PLATFORM_ATTR_TAG + ":" + binding.getPlatform()); //$NON-NLS-1$
+		}
+		// just add the 'type' tag if it's a user binding
+		if (binding.getType() == Binding.USER) {
+			tags.add(EBindingService.TYPE_ATTR_TAG + ":user"); //$NON-NLS-1$
+		}
+
+		keyBinding.getTransientData().put(EBindingService.MODEL_TO_BINDING_KEY, binding);
 		table.getBindings().add(keyBinding);
 	}
 
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/keys/BindingPersistence.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/keys/BindingPersistence.java
index 64475e7..149bf65 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/keys/BindingPersistence.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/keys/BindingPersistence.java
@@ -35,7 +35,6 @@
 import org.eclipse.core.runtime.IExtensionRegistry;
 import org.eclipse.core.runtime.IRegistryChangeEvent;
 import org.eclipse.core.runtime.Platform;
-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;
@@ -481,10 +480,6 @@
 			final BindingManager bindingManager, final CommandManager commandService) {
 		List warningsToLog = new ArrayList(1);
 
-		// flag to deactivate a SYSTEM binding
-		boolean flagDeactivate = false;
-		int bindingType = Binding.USER;
-
 		if (preferences != null) {
 			final IMemento[] preferenceMementos = preferences
 					.getChildren(TAG_KEY_BINDING);
@@ -580,42 +575,13 @@
 							warningsToLog, command);
 				}
 
-				// see if this is actually a USER binding or a default SYSTEM
-				// binding that the user deactivated
-				String isDeactivatedSystemBinding = readOptional(memento, ATT_DELETED);
-				if (isDeactivatedSystemBinding != null && isDeactivatedSystemBinding.equals("true")) { //$NON-NLS-1$
-					flagDeactivate = true;
-				}
-
-				if (flagDeactivate) {
-					bindingType = Binding.SYSTEM;
-				} else {
-					bindingType = Binding.USER;
-				}
-
 				final Binding binding = new KeyBinding(keySequence,
-						parameterizedCommand, schemeId, contextId, locale, platform, null, bindingType);
-
-				if (flagDeactivate) {
-					BindingCopies.addInactiveSysBinding(binding);
-				} else {
-					bindingManager.addBinding(binding);
-				}
-
-				// reset flag
-				flagDeactivate = false;
+						parameterizedCommand, schemeId, contextId, locale,
+						platform, null, Binding.USER);
+				bindingManager.addBinding(binding);
 			}
 		}
 
-		Binding[] sysBindingsToRemove = BindingCopies.getInactiveSysBindings();
-		for (int i = 0; i < sysBindingsToRemove.length; i++) {
-			// bindingManager.removeBinding(sysBindingsToRemove[i]);
-			bindingManager.removeBindings(sysBindingsToRemove[i].getTriggerSequence(),
-					sysBindingsToRemove[i].getSchemeId(), sysBindingsToRemove[i].getContextId(),
-					sysBindingsToRemove[i].getLocale(), sysBindingsToRemove[i].getPlatform(), null,
-					sysBindingsToRemove[i].getType());
-		}
-
 		// If there were any warnings, then log them now.
 		logWarnings(warningsToLog,
 				"Warnings while parsing the key bindings from the preference store"); //$NON-NLS-1$
@@ -1097,15 +1063,14 @@
 	 * 
 	 * @param activeScheme
 	 *            The scheme which should be persisted; may be <code>null</code>.
-	 * @param activeUserBindings
+	 * @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[] activeUserBindings,
-			Binding[] inactiveSystemBindings)
+	static final void write(final Scheme activeScheme, final Binding[] bindings)
 			throws IOException {
 		// Print out debugging information, if requested.
 		if (DEBUG) {
@@ -1123,23 +1088,12 @@
 		if (activeScheme != null) {
 			writeActiveSchemeToPreferences(xmlMemento, activeScheme);
 		}
-		// write all active USER Bindings
-		if (activeUserBindings != null) {
-			final int bindingsLength = activeUserBindings.length;
+		if (bindings != null) {
+			final int bindingsLength = bindings.length;
 			for (int i = 0; i < bindingsLength; i++) {
-				final Binding binding = activeUserBindings[i];
-				if (binding.getParameterizedCommand() != null && binding.getType() == Binding.USER) {
-					writeBindingToPreferences(xmlMemento, binding, false);
-				}
-			}
-		}
-		// write all deactivated SYSTEM bindings so that we know which default
-		// bindings to disable on the next startup
-		if (inactiveSystemBindings != null) {
-			for (int i = 0; i < inactiveSystemBindings.length; i++) {
-				final Binding inactiveSystemBinding = inactiveSystemBindings[i];
-				if (inactiveSystemBinding.getType() == Binding.SYSTEM) {
-					writeBindingToPreferences(xmlMemento, inactiveSystemBinding, true);
+				final Binding binding = bindings[i];
+				if (binding.getType() == Binding.USER) {
+					writeBindingToPreferences(xmlMemento, binding);
 				}
 			}
 		}
@@ -1216,7 +1170,7 @@
 	 *            The binding to write; must not be <code>null</code>.
 	 */
 	private static final void writeBindingToPreferences(final IMemento parent,
-			final Binding binding, boolean inactiveSystemBinding) {
+			final Binding binding) {
 		final IMemento element = parent.createChild(TAG_KEY_BINDING);
 		element.putString(ATT_CONTEXT_ID, binding.getContextId());
 		final ParameterizedCommand parameterizedCommand = binding
@@ -1229,11 +1183,6 @@
 				.toString());
 		element.putString(ATT_LOCALE, binding.getLocale());
 		element.putString(ATT_PLATFORM, binding.getPlatform());
-		if (inactiveSystemBinding) {
-			element.putString(ATT_DELETED, "true"); //$NON-NLS-1$
-		} else {
-			element.putString(ATT_DELETED, "false"); //$NON-NLS-1$
-		}
 		if (parameterizedCommand != null) {
 			final Map parameterizations = parameterizedCommand
 					.getParameterMap();
@@ -1277,7 +1226,6 @@
 			final CommandManager commandManager) {
 		this.bindingManager = bindingManager;
 		this.commandManager = commandManager;
-		BindingCopies.init();
 	}
 
 	protected final boolean isChangeImportant(final IRegistryChangeEvent event) {
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 82fb3f0..2b36cc7 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,20 +11,20 @@
 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;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import javax.inject.Inject;
 import org.eclipse.core.commands.CommandManager;
 import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
 import org.eclipse.e4.core.commands.ECommandService;
 import org.eclipse.e4.core.di.annotations.Optional;
 import org.eclipse.e4.ui.bindings.EBindingService;
-import org.eclipse.e4.ui.bindings.internal.BindingCopies;
-import org.eclipse.e4.ui.bindings.internal.BindingTableManager;
 import org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher;
 import org.eclipse.e4.ui.model.application.MApplication;
 import org.eclipse.e4.ui.model.application.commands.MBindingContext;
@@ -42,7 +42,7 @@
 import org.eclipse.jface.bindings.keys.KeySequence;
 import org.eclipse.jface.util.Util;
 import org.eclipse.ui.commands.ICommandService;
-import org.eclipse.ui.internal.e4.compatibility.E4Util;
+import org.eclipse.ui.internal.WorkbenchPlugin;
 import org.eclipse.ui.keys.IBindingService;
 
 /**
@@ -67,15 +67,12 @@
 	private ECommandService commandService;
 
 	@Inject
+	private CommandManager commandManager;
+
+	@Inject
 	private BindingManager manager;
 
 	@Inject
-	private CommandManager cmdManager;
-
-	@Inject
-	private BindingTableManager bindingTableManager;
-
-	@Inject
 	@Optional
 	private KeyBindingDispatcher dispatcher;
 
@@ -87,12 +84,7 @@
 	 * @see org.eclipse.ui.services.IDisposable#dispose()
 	 */
 	public void dispose() {
-		for (Runnable r : bindingsToRemove) {
-			r.run();
-		}
-		for (MBindingTable table : tablesToRemove) {
-			application.getBindingTables().remove(table);
-		}
+
 	}
 
 	/*
@@ -247,9 +239,9 @@
 		if (prefixesLength == 0) {
 			return Collections.EMPTY_MAP;
 		}
-		
+
 		Collection<Binding> partialMatches = bindingService.getPartialMatches(trigger);
-		Map<TriggerSequence,Object> prefixTable = new HashMap<TriggerSequence, Object>();
+		Map<TriggerSequence, Object> prefixTable = new HashMap<TriggerSequence, Object>();
 		for (Binding binding : partialMatches) {
 			for (int i = 0; i < prefixesLength; i++) {
 				final TriggerSequence prefix = prefixes[i];
@@ -332,13 +324,9 @@
 	 * @see org.eclipse.ui.keys.IBindingService#openKeyAssistDialog()
 	 */
 	public void openKeyAssistDialog() {
-		// TODO compat openKeyAssistDialog
-		E4Util.unsupported("openKeyAssistDialog"); //$NON-NLS-1$
+		dispatcher.openMultiKeyAssistShell();
 	}
 
-	private ArrayList<MBindingTable> tablesToRemove = new ArrayList<MBindingTable>();
-	private ArrayList<Runnable> bindingsToRemove = new ArrayList<Runnable>();
-
 	/*
 	 * (non-Javadoc)
 	 * 
@@ -347,27 +335,8 @@
 	 * .ui.commands.ICommandService)
 	 */
 	public void readRegistryAndPreferences(ICommandService commandService) {
-
-
-		// TODO: shouldn't be using BindingPersistence here, but if we don't,
-		// then the keys pref page will crash when loading!
-		BindingPersistence bindingPersistence = new BindingPersistence(manager, cmdManager);
-		bindingPersistence.reRead();
-
-		Collection<Binding> bindings = bindingTableManager.getActiveBindings();
-		manager.setBindings(bindings.toArray(new Binding[bindings.size()]));
-
-		// BindingPersistence reader = new BindingPersistence(manager,
-		// commandService);
-		// reader.reRead();
-		// Iterator i =
-		// manager.getActiveBindingsDisregardingContextFlat().iterator();
-		// while (i.hasNext()) {
-		// Binding binding = (Binding) i.next();
-		// addBinding(binding);
-		// }
-
-		bindingPersistence.dispose();
+		BindingPersistence bp = new BindingPersistence(manager, commandManager);
+		bp.read();
 	}
 
 	private MCommand findCommand(String id) {
@@ -379,6 +348,17 @@
 		return null;
 	}
 
+	private void saveLegacyPreferences(Scheme activeScheme, Binding[] bindings) throws IOException {
+		BindingPersistence.write(activeScheme, bindings);
+		try {
+			manager.setActiveScheme(activeScheme);
+		} catch (final NotDefinedException e) {
+			WorkbenchPlugin.log("The active scheme is not currently defined.", //$NON-NLS-1$
+					WorkbenchPlugin.getStatus(e));
+		}
+		manager.setBindings(bindings);
+	}
+
 	/*
 	 * (non-Javadoc)
 	 * 
@@ -387,107 +367,74 @@
 	 * .bindings.Scheme, org.eclipse.jface.bindings.Binding[])
 	 */
 	public void savePreferences(Scheme activeScheme, Binding[] bindings) throws IOException {
+		saveLegacyPreferences(activeScheme, bindings);
 
-		Collection<Binding> activeBindings = bindingTableManager.getActiveBindings();
-		Binding[] activeBindingsArray = activeBindings.toArray(new Binding[activeBindings.size()]);
+		// save the active scheme to the model
+		writeSchemeToModel(activeScheme);
 
-		Binding b;
+		// weeds out any of the deleted system bindings using the binding
+		// manager
+		HashSet<Binding> activeBindings = new HashSet<Binding>(
+				manager.getActiveBindingsDisregardingContextFlat());
 
-		Collection<Binding> activeUserBindings = new ArrayList<Binding>();
-
-		boolean madeChanges = false; // flag to actually save the prefs
-
-		// go through the list of active bindings (from the BTM) and DEACTIVATE
-		// any bindings that are not included in the list of bindings passed
-		// from the new keys pref page
-		for (int i = 0; i < activeBindingsArray.length; i++) {
-			b = getEqualBinding(bindings, activeBindingsArray[i]);
-
-			// if we didn't find the binding, then it wasn't included in the
-			// list passed from the new keys pref page, so this binding needs to
-			// be deactivated
-			if (b == null) {
-				bindingService.deactivateBinding(activeBindingsArray[i]);
-
-				// make sure we keep this binding manager consistent with the
-				// BTM since the keys pref page will read off this
-				manager.removeBinding(activeBindingsArray[i]);
-
-				// if we're deactivating a SYSTEM binding, then keep it in the
-				// list of bindings to write to xml, but make sure it gets
-				// flagged as disabled
-				if (activeBindingsArray[i].getType() == Binding.SYSTEM) {
-					// inactiveSystemBindings.add(activeBindingsArray[i]);
-					BindingCopies.addInactiveSysBinding(activeBindingsArray[i]);
+		// get all of the (active) model bindings that point to the actual runtime
+		// bindings
+		HashMap<Binding, MKeyBinding> bindingToKey = new HashMap<Binding, MKeyBinding>();
+		for (MBindingTable table : application.getBindingTables()) {
+			for (MKeyBinding modelBinding : table.getBindings()) {
+				final Object obj = modelBinding.getTransientData().get(
+						EBindingService.MODEL_TO_BINDING_KEY);
+				if (obj instanceof Binding) {
+					bindingToKey.put((Binding) obj, modelBinding);
 				}
-
-				// flag that changes were made to the bindings so that we need
-				// to save
-				madeChanges = true;
 			}
 		}
 
-		// go though the list of bindings passed from the new keys pref page and
-		// ACTIVATE the NEW bindings added
-		for (int i = 0; i < bindings.length; i++) {
-			b = getEqualBinding(activeBindingsArray, bindings[i]);
-
-			// if we didn't find the binding, that means it's a new one, so
-			// let's activate it (as long as the command isn't null)
-			if (b == null && bindings[i].getParameterizedCommand() != null) {
-
-				bindingService.activateBinding(bindings[i]);
-
-				// make sure we keep this binding manager consistent with the
-				// BTM since the keys pref page will read off this
-				manager.addBinding(bindings[i]);
-
-				// flag that changes were made to the bindings, so we need
-				// to persist them
-				madeChanges = true;
-
-				// Since the binding persistence only writes out active USER
-				// bindings and deactivated SYSTEM bindings, there's no point in
-				// sending the entire bindings list and searching USER bindings.
-				if (bindings[i].getType() == Binding.USER) {
-					activeUserBindings.add(bindings[i]);
-				} else {
-					BindingCopies.removeInactiveSysBinding(bindings[i]);
+		// go through each of the (active) bindings in the model to see if there are any
+		// bindings that we should remove
+		final HashSet<Binding> deleted = new HashSet<Binding>(bindingToKey.keySet());
+		deleted.removeAll(activeBindings);
+		for (Binding binding : deleted) {
+			if (binding.getType() == Binding.USER) {
+				removeBinding(binding);
+			} else {
+				final MKeyBinding model = bindingToKey.get(binding);
+				if (!model.getTags().contains(EBindingService.DELETED_BINDING_TAG)) {
+					model.getTags().add(EBindingService.DELETED_BINDING_TAG);
 				}
-
-				// since we've activated a new binding, we need to see if it's
-				// replacing one of the old bindings (in which case the old
-				// binding needs to be deactivated)
-				// ... but not right now
-			}
-			// else if the binding was already activated AND it's a USER
-			// binding, then we'll need to persist it as well
-			else if (bindings[i].getType() == Binding.USER) {
-				activeUserBindings.add(bindings[i]);
-				madeChanges = true;
 			}
 		}
-
-		// if we made any changes, then they need to be persisted
-		if (madeChanges) {
-			// BindingPersistence.write(activeScheme, bindings);
-			BindingPersistence.write(activeScheme,
-					activeUserBindings.toArray(new Binding[activeUserBindings.size()]),
-					BindingCopies.getInactiveSysBindings());
-			// TODO: these numbers don't make sense... dig a litter deeper
+		
+		// go through each of the active bindings (from the binding manager) to
+		// 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);
+				}
+			} else {
+				addBinding(binding);
+			}
 		}
-
 	}
 
-	private Binding getEqualBinding(Binding[] bindings, Binding target) {
-		Binding theBinding = null;
 
-		for (int i = 0; i < bindings.length && theBinding == null; i++) {
-			if (bindings[i].equals(target)) {
-				theBinding = bindings[i];
+	private void writeSchemeToModel(Scheme activeScheme) {
+		List<String> tags = application.getTags();
+		boolean found = false;
+		// replace the old scheme id
+		Iterator<String> i = tags.iterator();
+		while (i.hasNext() && !found) {
+			String tag = i.next();
+			if (tag.startsWith(EBindingService.ACTIVE_SCHEME_TAG)) {
+				i.remove();
+				found = true;
 			}
 		}
-		return theBinding;
+		tags.add(EBindingService.ACTIVE_SCHEME_TAG + ":" + activeScheme.getId()); //$NON-NLS-1$
 	}
 
 	/*
@@ -508,7 +455,7 @@
 	 * org.eclipse.ui.keys.IBindingService#getConflictsFor(org.eclipse.jface
 	 * .bindings.TriggerSequence)
 	 */
-	public Collection getConflictsFor(TriggerSequence sequence) {
+	public Collection<Binding> getConflictsFor(TriggerSequence sequence) {
 		return bindingService.getConflictsFor(sequence);
 	}
 
@@ -565,29 +512,46 @@
 	 *            The binding to be added; must not be <code>null</code>.
 	 */
 	public final void addBinding(final Binding binding) {
-		MBindingTable table = null;
+		MBindingTable table = getMTable(binding.getContextId());
+		MKeyBinding keyBinding = createMKeyBinding(binding);
+		if (keyBinding != null) {
+			table.getBindings().add(keyBinding);
+		}
+	}
+
+	/**
+	 * @param contextId
+	 * @return
+	 */
+	private MBindingTable getMTable(String contextId) {
 		for (MBindingTable bt : application.getBindingTables()) {
-			if (bt.getBindingContext().getElementId().equals(binding.getContextId())) {
-				table = bt;
-				break;
+			if (bt.getBindingContext().getElementId().equals(contextId)) {
+				return bt;
 			}
 		}
-		if (table == null) {
-			table = CommandsFactoryImpl.eINSTANCE.createBindingTable();
-			tablesToRemove.add(table);
-			table.setBindingContext(getBindingContext(binding.getContextId()));
-			table.setElementId(binding.getContextId());
-			application.getBindingTables().add(table);
-		}
+		// create a new table if we couldn't find one
+		MBindingTable table = CommandsFactoryImpl.eINSTANCE.createBindingTable();
+		table.setBindingContext(getBindingContext(contextId));
+		table.setElementId(contextId);
+		application.getBindingTables().add(table);
+		return table;
+
+	}
+
+
+	private MKeyBinding createMKeyBinding(Binding binding) {
 		final MKeyBinding keyBinding = CommandsFactoryImpl.eINSTANCE.createKeyBinding();
+
 		ParameterizedCommand parmCmd = binding.getParameterizedCommand();
 
 		MCommand cmd = findCommand(parmCmd.getId());
 		if (cmd == null) {
-			return;
+			return null;
 		}
 		keyBinding.setCommand(cmd);
+		// keyBinding.setKeySequence(binding.getTriggerSequence().format());
 		keyBinding.setKeySequence(binding.getTriggerSequence().format());
+
 		for (Object obj : parmCmd.getParameterMap().entrySet()) {
 			Map.Entry entry = (Map.Entry) obj;
 			MParameter p = CommandsFactoryImpl.eINSTANCE.createParameter();
@@ -596,15 +560,69 @@
 			p.setValue((String) entry.getValue());
 			keyBinding.getParameters().add(p);
 		}
-		table.getBindings().add(keyBinding);
-		if (!tablesToRemove.contains(table)) {
-			final MBindingTable theTable = table;
-			bindingsToRemove.add(new Runnable() {
-				public void run() {
-					theTable.getBindings().remove(keyBinding);
-				}
-			});
+
+		List<String> tags = keyBinding.getTags();
+		// just add the 'schemeId' tag if the binding is for anything other than
+		// the default scheme
+		if (binding.getSchemeId() != null
+				&& !binding.getSchemeId().equals(BindingPersistence.getDefaultSchemeId())) {
+			tags.add(EBindingService.SCHEME_ID_ATTR_TAG + ":" + binding.getSchemeId()); //$NON-NLS-1$
 		}
+		if (binding.getLocale() != null) {
+			tags.add(EBindingService.LOCALE_ATTR_TAG + ":" + binding.getLocale()); //$NON-NLS-1$
+		}
+		if (binding.getPlatform() != null) {
+			tags.add(EBindingService.PLATFORM_ATTR_TAG + ":" + binding.getPlatform()); //$NON-NLS-1$
+		}
+		// just add the 'type' tag if it's a user binding
+		if (binding.getType() == Binding.USER) {
+			tags.add(EBindingService.TYPE_ATTR_TAG + ":user"); //$NON-NLS-1$
+		}
+		keyBinding.getTransientData().put(EBindingService.MODEL_TO_BINDING_KEY, binding);
+		return keyBinding;
+	}
+
+	private MKeyBinding findMKeyBinding(MBindingTable table, Binding binding) {
+		List<MKeyBinding> mBindings = table.getBindings();
+
+		String bindingSchemeId = binding.getSchemeId() == null ? IBindingService.DEFAULT_DEFAULT_ACTIVE_SCHEME_ID
+				: binding.getSchemeId();
+
+		if (binding.getParameterizedCommand() != null) {
+			String commandId = binding.getParameterizedCommand().getId();
+
+			for (MKeyBinding curr : mBindings) {
+				Binding transientBinding = (Binding) curr.getTransientData().get(
+						EBindingService.MODEL_TO_BINDING_KEY);
+				if (transientBinding != null) {
+					if (binding.equals(transientBinding)) {
+						return curr;
+					}
+					continue;
+				}
+				// check equality
+				if (curr.getKeySequence().equals(binding.getTriggerSequence().format())
+						&& curr.getCommand() != null
+						&& curr.getCommand().getElementId().equals(commandId)) {
+
+					String schemeId = IBindingService.DEFAULT_DEFAULT_ACTIVE_SCHEME_ID;
+					List<String> tags = curr.getTags();
+					// grab the scheme id from the tags
+					for (String tag : tags) {
+						if (tag.startsWith(EBindingService.SCHEME_ID_ATTR_TAG)) {
+							schemeId = tag.substring(9);
+							break;
+						}
+					}
+					// if the scheme ids are the same, then we found the
+					// MKeyBinding
+					if (schemeId.equals(bindingSchemeId)) {
+						return curr;
+					}
+				}
+			}
+		}
+		return null;
 	}
 
 	/**
@@ -615,6 +633,7 @@
 	 *            The binding to be removed; must not be <code>null</code>.
 	 */
 	public final void removeBinding(final Binding binding) {
+		MKeyBinding mKeyBinding;
 		MBindingTable table = null;
 		for (MBindingTable bt : application.getBindingTables()) {
 			if (bt.getBindingContext().getElementId().equals(binding.getContextId())) {
@@ -625,30 +644,36 @@
 		if (table == null) {
 			return;
 		}
-		final MKeyBinding keyBinding = CommandsFactoryImpl.eINSTANCE.createKeyBinding();
-		ParameterizedCommand parmCmd = binding.getParameterizedCommand();
 
-		MCommand cmd = findCommand(parmCmd.getId());
-		if (cmd == null) {
-			return;
+		// if we're removing a user binding, just remove it from the model and
+		// the listeners will take care of removing the binding from the runtime
+		// system
+		if (binding.getType() == Binding.USER) {
+			mKeyBinding = this.findMKeyBinding(table, binding);
+			if (mKeyBinding != null) {
+				table.getBindings().remove(mKeyBinding);
+			}
 		}
-		keyBinding.setCommand(cmd);
-		keyBinding.setKeySequence(binding.getTriggerSequence().format());
-		for (Object obj : parmCmd.getParameterMap().entrySet()) {
-			Map.Entry entry = (Map.Entry) obj;
-			MParameter p = CommandsFactoryImpl.eINSTANCE.createParameter();
-			p.setElementId((String) entry.getKey());
-			p.setName((String) entry.getKey());
-			p.setValue((String) entry.getValue());
-			keyBinding.getParameters().add(p);
+		// if we're removing a system binding, then find the model binding, add
+		// a 'deleted' tag, and explicitly remove the binding from the runtime
+		// system
+		else {
+			mKeyBinding = this.findMKeyBinding(table, binding);
+			if (mKeyBinding != null) {
+				mKeyBinding.getTags().add(EBindingService.DELETED_BINDING_TAG);
+			}
 		}
-		table.getBindings().remove(keyBinding);
-		// if we need to be clean:
-		manager.removeBinding(binding);
 	}
 
 	public BindingManager getBindingManager() {
 		return manager;
 	}
 
+	public Collection<Binding> getActiveBindings() {
+		return bindingService.getActiveBindings();
+	}
+
+	public WorkbenchKeyboard getKeyboard() {
+		return new WorkbenchKeyboard(dispatcher);
+	}
 }
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/keys/model/KeyController.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/keys/model/KeyController.java
index 70ef47b..ce35e36 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/keys/model/KeyController.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/keys/model/KeyController.java
@@ -16,7 +16,6 @@
 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;
@@ -27,7 +26,6 @@
 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;
@@ -144,7 +142,7 @@
 				final Scheme copy = bindingManager.getScheme(scheme.getId());
 				copy.define(scheme.getName(), scheme.getDescription(), scheme
 						.getParentId());
-				if (definedSchemes[i] == bindingService.getActiveScheme()) {
+				if (definedSchemes[i].getId().equals(bindingService.getActiveScheme().getId())) {
 					modelActiveScheme = copy;
 				}
 			}
@@ -154,6 +152,7 @@
 					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());
@@ -425,15 +424,8 @@
 	 */
 	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());
-
+			bindingService.savePreferences(fBindingManager.getActiveScheme(),
+					fBindingManager.getBindings());
 		} catch (IOException e) {
 			logPreferenceStoreException(e);
 		}
@@ -485,7 +477,6 @@
 			fBindingManager.setActiveScheme(defaultScheme);
 		} catch (final NotDefinedException e) {
 			// At least we tried....
-			e.printStackTrace();
 		}
 
 		// Restore any User defined bindings
@@ -495,18 +486,6 @@
 				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);