blob: 52597843af775a6dd68a387218534d2bda6031f3 [file] [log] [blame]
/*******************************************************************************
* 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.e4.ui.workbench.swt.util;
import org.eclipse.e4.ui.model.application.commands.MBindingContext;
import java.util.ArrayList;
import java.util.Collection;
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.core.runtime.IStatus;
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.bindings.EBindingService;
import org.eclipse.e4.ui.bindings.internal.BindingCopies;
import org.eclipse.e4.ui.bindings.internal.BindingTable;
import org.eclipse.e4.ui.bindings.internal.BindingTableManager;
import org.eclipse.e4.ui.internal.workbench.Activator;
import org.eclipse.e4.ui.internal.workbench.Policy;
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.jface.bindings.Binding;
import org.eclipse.jface.bindings.TriggerSequence;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
/**
* Process contexts in the model, feeding them into the command service.
*/
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;
private EventHandler additionHandler;
private EventHandler contextHandler;
@PostConstruct
public void init() {
defineBindingTables();
cleanTables();
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);
}
}
}
// goes through the entire active bindings list and replaces SYSTEM
// bindings with any USER bindings that were persisted
private void cleanTables() {
ArrayList<Binding> dirtyBindings = new ArrayList<Binding>();
Binding dirtyBinding;
Binding[] userBindings = BindingCopies.getUserDefinedBindings();
Binding curr;
// go through all USER bindings and check if there is an "equal" SYSTEM
// binding
for (int i = 0; i < userBindings.length; i++) {
curr = userBindings[i];
// they should all be USER bindings, but double check anyway
if (curr.getType() == Binding.USER) {
dirtyBinding = checkDirty(curr);
// if the SYSTEM binding is marked as dirty, then throw it in a
// list and we'll remove it later
if (dirtyBinding != null) {
dirtyBindings.add(dirtyBinding);
}
}
}
//System.out.println("@@@ dirty bindings -> " + dirtyBindings.size());
// go through the list of bindings that are marked as dirty (if any) and
// remove them from the BindingTableManager
for (int i = 0; i < dirtyBindings.size(); i++) {
dirtyBinding = dirtyBindings.get(i);
bindingTables.getTable(dirtyBinding.getContextId()).removeBinding(
dirtyBinding);
}
}
private Binding checkDirty(Binding b) {
Collection<Binding> activeBindings = bindingTables.getActiveBindings();
Iterator<Binding> iter = activeBindings.iterator();
Binding curr;
Binding dirtyBinding = null;
while (iter.hasNext() && dirtyBinding == null) {
curr = iter.next();
// make sure we're only comparing SYSTEM bindings so that we don't
// remove the wrong ones, and make sure the bindings we're comparing
// actually have a command
if (curr.getType() == Binding.SYSTEM
&& curr.getParameterizedCommand() != null
&& b.getParameterizedCommand() != null) {
if (curr.getContextId().equals(b.getContextId())
&& curr.getParameterizedCommand().equals(
b.getParameterizedCommand())
&& curr.getSchemeId().equals(b.getSchemeId())) {
// mark this binding as dirty, and it will be removed
dirtyBinding = curr;
}
}
}
return dirtyBinding;
}
private void defineBindingTables() {
Activator.trace(Policy.DEBUG_CMDS,
"Initialize binding tables from model", null); //$NON-NLS-1$
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) {
// if (keyBinding.getType() == Binding.USER)
bindingTable.addBinding(keyBinding);
}
}
private Binding createBinding(Context bindingContext, MCommand cmdModel,
List<MParameter> modelParms, String keySequence, MKeyBinding binding) {
if (cmdModel == null) {
Activator.log(IStatus.ERROR, "binding with no command: " + binding); //$NON-NLS-1$
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);
Binding keyBinding = null;
if (cmd == null || sequence == null) {
System.err.println("Failed to handle binding: " + binding); //$NON-NLS-1$
} else {
try {
int bindingType = Binding.SYSTEM;
// go thru the copied list of USER defined bindings to see if
// this particular binding being created matches any of them
if (BindingCopies.isUserBinding(sequence, cmd,
"org.eclipse.ui.defaultAcceleratorConfiguration",
bindingContext.getId())) {
bindingType = Binding.USER;
}
// TODO: NEED TO CHANGE THIS!!!
keyBinding = bindingService
.createBinding(
sequence,
cmd,
"org.eclipse.ui.defaultAcceleratorConfiguration", bindingContext.getId(), null, null, bindingType); //$NON-NLS-1$
} catch (IllegalArgumentException e) {
Activator.trace(Policy.DEBUG_MENUS,
"failed to create: " + binding, e); //$NON-NLS-1$
return null;
}
}
return keyBinding;
}
private void updateBinding(MKeyBinding binding, boolean add) {
Object parentObj = ((EObject) binding).eContainer();
if (!(parentObj instanceof MBindingTable)) {
return;
}
MBindingTable bt = (MBindingTable) parentObj;
final Context bindingContext = contextManager.getContext(bt
.getBindingContext().getElementId());
BindingTable table = bindingTables.getTable(bindingContext.getId());
if (table == null) {
Activator.log(IStatus.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);
if (UIEvents.EventTypes.ADD.equals(event
.getProperty(UIEvents.EventTags.TYPE))
&& newObj instanceof MKeyBinding) {
MKeyBinding binding = (MKeyBinding) newObj;
updateBinding(binding, true);
} else if (UIEvents.EventTypes.REMOVE.equals(event
.getProperty(UIEvents.EventTags.TYPE))
&& oldObj instanceof MKeyBinding) {
MKeyBinding binding = (MKeyBinding) oldObj;
updateBinding(binding, false);
}
} 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);
updateBinding(binding, true);
} else if (UIEvents.KeySequence.KEYSEQUENCE
.equals(attrName)) {
MKeyBinding oldBinding = (MKeyBinding) EcoreUtil
.copy((EObject) binding);
oldBinding.setKeySequence((String) oldObj);
updateBinding(oldBinding, false);
updateBinding(binding, true);
}
} 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);
updateBinding(binding, true);
} 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);
updateBinding(binding, true);
}
}
}
}
};
broker.subscribe(UIEvents.buildTopic(
UIEvents.BindingTableContainer.TOPIC,
UIEvents.BindingTableContainer.BINDINGTABLES), additionHandler);
broker.subscribe(UIEvents.buildTopic(UIEvents.BindingTable.TOPIC,
UIEvents.BindingTable.BINDINGS), additionHandler);
broker.subscribe(UIEvents.buildTopic(UIEvents.KeyBinding.TOPIC,
UIEvents.KeyBinding.COMMAND), additionHandler);
broker.subscribe(UIEvents.buildTopic(UIEvents.KeyBinding.TOPIC,
UIEvents.KeyBinding.PARAMETERS), additionHandler);
broker.subscribe(UIEvents.buildTopic(UIEvents.KeySequence.TOPIC,
UIEvents.KeySequence.KEYSEQUENCE), 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.buildTopic(UIEvents.Context.TOPIC,
UIEvents.Context.CONTEXT), contextHandler);
}
private void unregsiterModelListeners() {
broker.unsubscribe(additionHandler);
broker.unsubscribe(additionHandler);
broker.unsubscribe(additionHandler);
broker.unsubscribe(additionHandler);
broker.unsubscribe(additionHandler);
broker.unsubscribe(contextHandler);
}
}