blob: 071526b4f3789438fd6950db08ce23c1dac80499 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.internal.keys.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.ParameterizedCommand;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.jface.bindings.Binding;
import org.eclipse.jface.bindings.BindingManager;
import org.eclipse.jface.bindings.TriggerSequence;
import org.eclipse.jface.bindings.keys.KeyBinding;
import org.eclipse.jface.bindings.keys.KeySequence;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.internal.util.Util;
import org.eclipse.ui.services.IServiceLocator;
/**
* @since 3.4
*
*/
public class BindingModel extends CommonModel {
public static final String PROP_BINDING_ADD = "bindingAdd"; //$NON-NLS-1$
public static final String PROP_BINDING_ELEMENT_MAP = "bindingElementMap"; //$NON-NLS-1$
public static final String PROP_BINDING_FILTER = "bindingFilter"; //$NON-NLS-1$
public static final String PROP_BINDING_REMOVE = "bindingRemove"; //$NON-NLS-1$
public static final String PROP_BINDINGS = "bindings"; //$NON-NLS-1$
public static final String PROP_CONFLICT_ELEMENT_MAP = "bindingConfictMap"; //$NON-NLS-1$
final static boolean deletes(final Binding del, final Binding binding) {
boolean deletes = true;
deletes &= Util.equals(del.getContextId(), binding.getContextId());
deletes &= Util.equals(del.getTriggerSequence(), binding
.getTriggerSequence());
if (del.getLocale() != null) {
deletes &= Util.equals(del.getLocale(), binding.getLocale());
}
if (del.getPlatform() != null) {
deletes &= Util.equals(del.getPlatform(), binding.getPlatform());
}
deletes &= (binding.getType() == Binding.SYSTEM);
deletes &= Util.equals(del.getParameterizedCommand(), null);
return deletes;
}
private Collection allParameterizedCommands;
private BindingManager bindingManager;
/**
* Holds all the {@link BindingElement} objects.
*/
private HashSet bindingElements;
/**
* A map of {@link Binding} objects to {@link BindingElement} objects.
*/
private Map bindingToElement;
/**
* A map of {@link ParameterizedCommand} objects to {@link BindingElement}
* objects.
*/
private Map commandToElement;
/**
* @param kc
*/
public BindingModel(KeyController kc) {
super(kc);
}
/**
* Makes a copy of the selected element.
*
*/
public void copy() {
BindingElement element = (BindingElement) getSelectedElement();
copy(element);
}
/**
* Makes a copy of the
*
* @param element
*/
public void copy(BindingElement element) {
if (element == null || !(element.getModelObject() instanceof Binding)) {
return;
}
BindingElement be = new BindingElement(controller);
ParameterizedCommand parameterizedCommand = ((Binding) element
.getModelObject()).getParameterizedCommand();
be.init(parameterizedCommand);
be.setParent(this);
bindingElements.add(be);
commandToElement.put(parameterizedCommand, be);
controller.firePropertyChange(this, PROP_BINDING_ADD, null, be);
setSelectedElement(be);
}
/**
* @return Returns the bindings.
*/
public HashSet getBindings() {
return bindingElements;
}
/**
* @return Returns the bindingToElement.
*/
public Map getBindingToElement() {
return bindingToElement;
}
/**
* @return Returns the commandToElement.
*/
public Map getCommandToElement() {
return commandToElement;
}
/**
* The initialization only.
*
* @param locator
* @param manager
* @param model
*/
public void init(IServiceLocator locator, BindingManager manager,
ContextModel model) {
Set cmdsForBindings = new HashSet();
bindingToElement = new HashMap();
commandToElement = new HashMap();
bindingElements = new HashSet();
bindingManager = manager;
Iterator i = manager.getActiveBindingsDisregardingContextFlat()
.iterator();
while (i.hasNext()) {
Binding b = (Binding) i.next();
BindingElement be = new BindingElement(controller);
be.init(b, model);
be.setParent(this);
bindingElements.add(be);
bindingToElement.put(b, be);
cmdsForBindings.add(b.getParameterizedCommand());
}
ICommandService commandService = (ICommandService) locator
.getService(ICommandService.class);
final Collection commandIds = commandService.getDefinedCommandIds();
allParameterizedCommands = new HashSet();
final Iterator commandIdItr = commandIds.iterator();
while (commandIdItr.hasNext()) {
final String currentCommandId = (String) commandIdItr.next();
final Command currentCommand = commandService
.getCommand(currentCommandId);
try {
allParameterizedCommands.addAll(ParameterizedCommand
.generateCombinations(currentCommand));
} catch (final NotDefinedException e) {
// It is safe to just ignore undefined commands.
}
}
i = allParameterizedCommands.iterator();
while (i.hasNext()) {
ParameterizedCommand cmd = (ParameterizedCommand) i.next();
if (!cmdsForBindings.contains(cmd)) {
BindingElement be = new BindingElement(controller);
be.init(cmd);
be.setParent(this);
bindingElements.add(be);
commandToElement.put(cmd, be);
}
}
}
/**
* Refreshes the binding model to be in sync with the {@link BindingManager}.
*
* @param contextModel
*/
public void refresh(ContextModel contextModel) {
Set cmdsForBindings = new HashSet();
Collection activeManagerBindings = bindingManager
.getActiveBindingsDisregardingContextFlat();
// add any bindings that we don't already have.
Iterator i = activeManagerBindings.iterator();
while (i.hasNext()) {
KeyBinding b = (KeyBinding) i.next();
ParameterizedCommand parameterizedCommand = b
.getParameterizedCommand();
cmdsForBindings.add(parameterizedCommand);
if (!bindingToElement.containsKey(b)) {
BindingElement be = new BindingElement(controller);
be.init(b, contextModel);
be.setParent(this);
bindingElements.add(be);
bindingToElement.put(b, be);
controller.firePropertyChange(this, PROP_BINDING_ADD, null, be);
if (commandToElement.containsKey(parameterizedCommand)
&& be.getUserDelta().intValue() == Binding.SYSTEM) {
Object remove = commandToElement.remove(parameterizedCommand);
bindingElements.remove(remove);
controller.firePropertyChange(this, PROP_BINDING_REMOVE,
null, remove);
}
}
}
// remove bindings that shouldn't be there
i = bindingElements.iterator();
while (i.hasNext()) {
BindingElement be = (BindingElement) i.next();
Object obj = be.getModelObject();
if (obj instanceof Binding) {
Binding b = (Binding) obj;
if (!activeManagerBindings.contains(b)) {
be.fill(b.getParameterizedCommand());
bindingToElement.remove(b);
i.remove();
controller.firePropertyChange(this, PROP_BINDING_REMOVE,
null, be);
}
} else {
cmdsForBindings.add(obj);
}
}
// If we removed the last binding for a parameterized command,
// put back the CMD
i = allParameterizedCommands.iterator();
while (i.hasNext()) {
ParameterizedCommand cmd = (ParameterizedCommand) i.next();
if (!cmdsForBindings.contains(cmd)) {
BindingElement be = new BindingElement(controller);
be.init(cmd);
be.setParent(this);
bindingElements.add(be);
commandToElement.put(cmd, be);
controller.firePropertyChange(this, PROP_BINDING_ADD, null, be);
}
}
}
/**
* Removes the selected element's binding
*
*/
public void remove() {
BindingElement element = (BindingElement) getSelectedElement();
remove(element);
}
/**
* Removes the <code>bindingElement</code> binding.
*
* @param bindingElement
*/
public void remove(BindingElement bindingElement) {
if (bindingElement == null
|| !(bindingElement.getModelObject() instanceof Binding)) {
return;
}
KeyBinding keyBinding = (KeyBinding) bindingElement.getModelObject();
if (keyBinding.getType() == Binding.USER) {
bindingManager.removeBinding(keyBinding);
} else {
KeySequence keySequence = keyBinding.getKeySequence();
// Add the delete binding
bindingManager.addBinding(new KeyBinding(keySequence, null,
keyBinding.getSchemeId(), keyBinding.getContextId(), null,
null, null, Binding.USER));
// Unbind any conflicts affected by the delete binding
ConflictModel conflictModel = controller.getConflictModel();
conflictModel.updateConflictsFor(bindingElement);
Collection conflictsList = conflictModel.getConflicts();
if (conflictsList != null) {
Object[] conflicts = conflictsList.toArray();
for (int i = 0; i < conflicts.length; i++) {
BindingElement be = (BindingElement) conflicts[i];
if (be == bindingElement) {
continue;
}
Object modelObject = be.getModelObject();
if (modelObject instanceof Binding) {
Binding binding = (Binding) modelObject;
if (binding.getType() != Binding.SYSTEM) {
continue;
}
ParameterizedCommand pCommand = binding
.getParameterizedCommand();
be.fill(pCommand);
commandToElement.put(pCommand, be);
}
}
}
}
ParameterizedCommand parameterizedCommand = keyBinding
.getParameterizedCommand();
bindingElement.fill(parameterizedCommand);
commandToElement.put(parameterizedCommand, bindingElement);
controller.firePropertyChange(this, PROP_CONFLICT_ELEMENT_MAP, null,
bindingElement);
}
/**
* Restores the specified BindingElement. A refresh should be performed
* afterwards. The refresh may be done after several elements have been
* restored.
*
* @param element
*/
public void restoreBinding(BindingElement element) {
if (element == null) {
return;
}
Object modelObject = element.getModelObject();
ParameterizedCommand cmd = null;
if (modelObject instanceof ParameterizedCommand) {
cmd = (ParameterizedCommand) modelObject;
TriggerSequence trigger = bindingManager
.getBestActiveBindingFor(cmd.getId());
Binding binding = bindingManager.getPerfectMatch(trigger);
if (binding != null && binding.getType() == Binding.SYSTEM) {
return;
}
} else if (modelObject instanceof KeyBinding) {
cmd = ((KeyBinding) modelObject).getParameterizedCommand();
}
// Remove any USER bindings
Binding[] managerBindings = bindingManager.getBindings();
ArrayList systemBindings = new ArrayList();
ArrayList removalBindings = new ArrayList();
for (int i = 0; i < managerBindings.length; i++) {
if (managerBindings[i].getParameterizedCommand() == null) {
removalBindings.add(managerBindings[i]);
} else if (managerBindings[i].getParameterizedCommand().equals(cmd)) {
if (managerBindings[i].getType() == Binding.USER) {
bindingManager.removeBinding(managerBindings[i]);
} else if (managerBindings[i].getType() == Binding.SYSTEM) {
systemBindings.add(managerBindings[i]);
}
}
}
// Clear the USER bindings for parameterized commands
Iterator i = systemBindings.iterator();
while (i.hasNext()) {
Binding sys = (Binding) i.next();
Iterator j = removalBindings.iterator();
while (j.hasNext()) {
Binding del = (Binding) j.next();
if (deletes(del, sys) && del.getType() == Binding.USER) {
bindingManager.removeBinding(del);
}
}
}
setSelectedElement(null);
bindingElements.remove(element);
bindingToElement.remove(modelObject);
commandToElement.remove(modelObject);
controller.firePropertyChange(this, PROP_BINDING_REMOVE, null, element);
}
/**
* Restores the currently selected binding.
*
* @param contextModel
*/
public void restoreBinding(ContextModel contextModel) {
BindingElement element = (BindingElement) getSelectedElement();
if (element == null) {
return;
}
restoreBinding(element);
refresh(contextModel);
Object obj = element.getModelObject();
ParameterizedCommand cmd = null;
if (obj instanceof ParameterizedCommand) {
cmd = (ParameterizedCommand) obj;
} else if (obj instanceof KeyBinding) {
cmd = ((KeyBinding) obj).getParameterizedCommand();
}
boolean done = false;
Iterator i = bindingElements.iterator();
// Reselects the command
while (i.hasNext() && !done) {
BindingElement be = (BindingElement) i.next();
obj = be.getModelObject();
ParameterizedCommand pcmd = null;
if (obj instanceof ParameterizedCommand) {
pcmd = (ParameterizedCommand) obj;
} else if (obj instanceof KeyBinding) {
pcmd = ((KeyBinding) obj).getParameterizedCommand();
}
if (cmd.equals(pcmd)) {
done = true;
setSelectedElement(be);
}
}
}
/**
* @param bindings
* The bindings to set.
*/
public void setBindings(HashSet bindings) {
HashSet old = this.bindingElements;
this.bindingElements = bindings;
controller.firePropertyChange(this, PROP_BINDINGS, old, bindings);
}
/**
* @param bindingToElement
* The bindingToElement to set.
*/
public void setBindingToElement(Map bindingToElement) {
Map old = this.bindingToElement;
this.bindingToElement = bindingToElement;
controller.firePropertyChange(this, PROP_BINDING_ELEMENT_MAP, old,
bindingToElement);
}
}