blob: 44fc8dac763f23af39a66a0025415fbb8289875e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
******************************************************************************/
package org.eclipse.e4.ui.bindings.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.jface.bindings.Binding;
import org.eclipse.jface.bindings.TriggerSequence;
/**
* manage tables of bindings that can be used to look up commands from keys.
*/
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<>();
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<>();
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.isEmpty() ? null : matches;
}
public Collection<Binding> getAllConflicts() {
Collection<Binding> conflictsList = new ArrayList<>();
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.isEmpty()) {
return null;
}
return bindings.get(0);
}
public Collection<Binding> getSequencesFor(ContextSet contextSet,
ParameterizedCommand parameterizedCommand) {
ArrayList<Binding> bindings = new ArrayList<>();
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<>();
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<>();
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 (final String schemePointer : activeSchemeIds) {
if (schemeId2.equals(schemePointer)) {
return 1;
} else if (schemeId1.equals(schemePointer)) {
return -1;
}
}
}
return 0;
}
}