blob: f978e4ab878090e5b21cfe98403632104c5605ee [file] [log] [blame]
/************************************************************************
Copyright (c) 2002 IBM Corporation and others.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Common Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/cpl-v10.html
Contributors:
IBM - Initial implementation
************************************************************************/
package org.eclipse.ui.internal.commands.keys;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.SWT;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.WorkbenchException;
import org.eclipse.ui.XMLMemento;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.commands.Item;
public class KeyManager {
private final static java.util.Locale systemLocale = java.util.Locale.getDefault();
private final static String systemPlatform = SWT.getPlatform(); // "carbon"
private final static String KEY_SEQUENCE_SEPARATOR = ", "; //$NON-NLS-1$
private final static String KEY_STROKE_SEPARATOR = " "; //$NON-NLS-1$
private final static String LOCALE_SEPARATOR = "_"; //$NON-NLS-1$
private final static String OR_SEPARATOR = "||"; //$NON-NLS-1$
private static KeyManager instance;
public static KeyManager getInstance() {
if (instance == null)
instance = new KeyManager();
return instance;
}
public static List parseKeySequences(String keys) {
List keySequences = null;
if (keys != null) {
keySequences = new ArrayList();
StringTokenizer orTokenizer = new StringTokenizer(keys, OR_SEPARATOR);
while (orTokenizer.hasMoreTokens()) {
List keyStrokes = new ArrayList();
StringTokenizer spaceTokenizer = new StringTokenizer(orTokenizer.nextToken());
while (spaceTokenizer.hasMoreTokens()) {
int accelerator = Action.convertAccelerator(spaceTokenizer.nextToken());
if (accelerator != 0)
keyStrokes.add(KeyStroke.create(accelerator));
}
if (keyStrokes.size() >= 1)
keySequences.add(KeySequence.create(keyStrokes));
}
}
return keySequences;
}
public static KeySequence parseKeySequenceStrict(String keys) {
if (keys != null) {
List keyStrokes = new ArrayList();
StringTokenizer spaceTokenizer = new StringTokenizer(keys);
while (spaceTokenizer.hasMoreTokens()) {
int accelerator = Action.convertAccelerator(spaceTokenizer.nextToken());
if (accelerator != 0)
keyStrokes.add(KeyStroke.create(accelerator));
else
return null;
}
return KeySequence.create(keyStrokes);
}
return null;
}
private static Path pathForConfiguration(String id, Map configurationMap) {
Path path = null;
if (id != null) {
List pathItems = new ArrayList();
while (id != null) {
if (pathItems.contains(id))
return null;
Item configuration = (Item) configurationMap.get(id);
if (configuration == null)
return null;
pathItems.add(0, id);
id = configuration.getParent();
}
path = Path.create(pathItems);
}
return path;
}
private static Path pathForScope(String id, Map scopeMap) {
Path path = null;
if (id != null) {
List pathItems = new ArrayList();
while (id != null) {
if (pathItems.contains(id))
return null;
Item scope = (Item) scopeMap.get(id);
if (scope == null)
return null;
pathItems.add(0, id);
id = scope.getParent();
}
path = Path.create(pathItems);
}
return path;
}
private static Path pathForLocale(String locale) {
Path path = null;
if (locale != null) {
List pathItems = new ArrayList();
locale = locale.trim();
if (locale.length() > 0) {
StringTokenizer st = new StringTokenizer(locale, LOCALE_SEPARATOR);
while (st.hasMoreElements()) {
String value = ((String) st.nextElement()).trim();
if (value != null)
pathItems.add(value);
}
}
path = Path.create(pathItems);
}
return path;
}
private static Path pathForPlatform(String platform) {
Path path = null;
if (platform != null) {
List pathItems = new ArrayList();
platform = platform.trim();
if (platform.length() > 0)
pathItems.add(platform);
path = Path.create(pathItems);
}
return path;
}
private static Path systemLocale() {
return systemLocale != null ? pathForLocale(systemLocale.toString()) : null;
}
private static Path systemPlatform() {
return pathForPlatform(systemPlatform);
}
private static SortedMap buildConfigurationMap(SortedMap registryConfigurationMap) {
SortedMap configurationMap = new TreeMap();
Iterator iterator = registryConfigurationMap.keySet().iterator();
while (iterator.hasNext()) {
String id = (String) iterator.next();
if (id != null) {
Path path = pathForConfiguration(id, registryConfigurationMap);
if (path != null)
configurationMap.put(id, path);
}
}
return configurationMap;
}
private static SortedMap buildScopeMap(Map registryScopeMap) {
SortedMap scopeMap = new TreeMap();
Iterator iterator = registryScopeMap.keySet().iterator();
while (iterator.hasNext()) {
String id = (String) iterator.next();
if (id != null) {
Path path = pathForScope(id, registryScopeMap);
if (path != null)
scopeMap.put(id, path);
}
}
return scopeMap;
}
public static SortedSet readBindingSet(IMemento memento)
throws IllegalArgumentException {
if (memento == null)
throw new IllegalArgumentException();
IMemento[] mementos = memento.getChildren(Binding.ELEMENT);
if (mementos == null)
throw new IllegalArgumentException();
SortedSet bindingSet = new TreeSet();
for (int i = 0; i < mementos.length; i++)
bindingSet.add(Binding.read(mementos[i]));
return bindingSet;
}
public static void writeBindingSet(IMemento memento, SortedSet bindingSet)
throws IllegalArgumentException {
if (memento == null || bindingSet == null)
throw new IllegalArgumentException();
Iterator iterator = bindingSet.iterator();
while (iterator.hasNext())
((Binding) iterator.next()).write(memento.createChild(Binding.ELEMENT));
}
public static SortedSet readRegionalBindingSet(IMemento memento)
throws IllegalArgumentException {
if (memento == null)
throw new IllegalArgumentException();
IMemento[] mementos = memento.getChildren(RegionalBinding.ELEMENT);
if (mementos == null)
throw new IllegalArgumentException();
SortedSet regionalBindingSet = new TreeSet();
for (int i = 0; i < mementos.length; i++)
regionalBindingSet.add(RegionalBinding.read(mementos[i]));
return regionalBindingSet;
}
public static void writeRegionalBindingSet(IMemento memento, SortedSet regionalBindingSet)
throws IllegalArgumentException {
if (memento == null || regionalBindingSet == null)
throw new IllegalArgumentException();
Iterator iterator = regionalBindingSet.iterator();
while (iterator.hasNext())
((RegionalBinding) iterator.next()).write(memento.createChild(RegionalBinding.ELEMENT));
}
private SortedSet solveRegionalBindingSet(SortedSet regionalBindingSet, State[] states) {
class Key implements Comparable {
private final static int HASH_INITIAL = 17;
private final static int HASH_FACTOR = 27;
KeySequence keySequence;
String configuration;
String scope;
public int compareTo(Object object) {
Key key = (Key) object;
int compareTo = keySequence.compareTo(key.keySequence);
if (compareTo == 0) {
compareTo = configuration.compareTo(key.configuration);
if (compareTo == 0)
compareTo = scope.compareTo(key.scope);
}
return compareTo;
}
public boolean equals(Object object) {
if (!(object instanceof Key))
return false;
Key key = (Key) object;
return keySequence.equals(key.keySequence) && configuration.equals(key.configuration) && scope.equals(key.scope);
}
public int hashCode() {
int result = HASH_INITIAL;
result = result * HASH_FACTOR + keySequence.hashCode();
result = result * HASH_FACTOR + configuration.hashCode();
result = result * HASH_FACTOR + scope.hashCode();
return result;
}
}
SortedSet bindingSet = new TreeSet();
Map map = new TreeMap();
Iterator iterator = regionalBindingSet.iterator();
while (iterator.hasNext()) {
RegionalBinding regionalBinding = (RegionalBinding) iterator.next();
Binding binding = regionalBinding.getBinding();
List pathItems = new ArrayList();
pathItems.add(pathForPlatform(regionalBinding.getPlatform()));
pathItems.add(pathForLocale(regionalBinding.getLocale()));
State state = State.create(pathItems);
Key key = new Key();
key.keySequence = binding.getKeySequence();
key.configuration = binding.getConfiguration();
key.scope = binding.getScope();
Map stateMap = (Map) map.get(key);
if (stateMap == null) {
stateMap = new TreeMap();
map.put(key, stateMap);
}
List bindings = (List) stateMap.get(state);
if (bindings == null) {
bindings = new ArrayList();
stateMap.put(state, bindings);
}
bindings.add(binding);
}
Iterator iterator2 = map.values().iterator();
while (iterator2.hasNext()) {
Map stateMap = (Map) iterator2.next();
int bestMatch = -1;
List bindings = null;
Iterator iterator3 = stateMap.entrySet().iterator();
while (iterator3.hasNext()) {
Map.Entry entry = (Map.Entry) iterator3.next();
State testState = (State) entry.getKey();
List testBindingSet = (List) entry.getValue();
int testMatch = testState.match(states[0]);
if (testMatch >= 0) {
if (bindings == null || testMatch < bestMatch) {
bindings = testBindingSet;
bestMatch = testMatch;
}
if (bestMatch == 0)
break;
}
}
if (bindings != null) {
Iterator iterator4 = bindings.iterator();
while (iterator4.hasNext()) {
Binding binding = (Binding) iterator4.next();
bindingSet.add(Binding.create(binding.getAction(), binding.getConfiguration(), binding.getKeySequence(), binding.getPlugin(),
binding.getRank() + bestMatch, binding.getScope()));
}
}
}
return bindingSet;
}
/*
private SortedSet solveRegionalBindingSet(SortedSet regionalBindingSet, State[] states) {
SortedMap tree = new TreeMap();
Iterator iterator = regionalBindingSet.iterator();
while (iterator.hasNext()) {
RegionalBinding regionalBinding = (RegionalBinding) iterator.next();
Binding binding = regionalBinding.getBinding();
List pathItems = new ArrayList();
pathItems.add(pathForPlatform(regionalBinding.getPlatform()));
pathItems.add(pathForLocale(regionalBinding.getLocale()));
Node.add(tree, binding, State.create(pathItems));
}
Node.solve(tree, states);
SortedSet matchSet = new TreeSet();
Node.toMatchSet(tree, matchSet);
SortedSet bindingSet = new TreeSet();
iterator = matchSet.iterator();
while (iterator.hasNext())
bindingSet.add(((Match) iterator.next()).getBinding());
return bindingSet;
}
*/
private KeyMachine keyMachine;
private SortedSet preferenceBindingSet;
private SortedMap registryConfigurationMap;
private SortedMap registryScopeMap;
private SortedSet registryRegionalBindingSet;
private SortedSet registryBindingSet;
private KeyManager() {
super();
keyMachine = KeyMachine.create();
loadPreference();
loadRegistry();
update();
}
public KeyMachine getKeyMachine() {
return keyMachine;
}
public SortedSet getPreferenceBindingSet() {
return preferenceBindingSet;
}
public SortedSet getRegistryBindingSet() {
return registryBindingSet;
}
public SortedMap getRegistryConfigurationMap() {
return registryConfigurationMap;
}
public SortedSet getRegistryRegionalBindingSet() {
return registryRegionalBindingSet;
}
public SortedMap getRegistryScopeMap() {
return registryScopeMap;
}
public void loadPreference() {
preferenceBindingSet = Collections.unmodifiableSortedSet(new TreeSet());
IPreferenceStore preferenceStore = WorkbenchPlugin.getDefault().getPreferenceStore();
String preferenceString = preferenceStore.getString("org.eclipse.ui.keybindings");
if (preferenceString != null && preferenceString.length() != 0) {
StringReader stringReader = new StringReader(preferenceString);
try {
XMLMemento xmlMemento = XMLMemento.createReadRoot(stringReader);
IMemento memento = xmlMemento.getChild("bindings");
if (memento != null)
preferenceBindingSet = Collections.unmodifiableSortedSet(readBindingSet(memento));
} catch (WorkbenchException eWorkbench) {
}
}
}
public void loadRegistry() {
Registry registry = Registry.getInstance();
registryConfigurationMap = Collections.unmodifiableSortedMap(registry.getConfigurationMap());
registryScopeMap = Collections.unmodifiableSortedMap(registry.getScopeMap());
registryRegionalBindingSet = Collections.unmodifiableSortedSet(registry.getRegionalBindingSet());
List pathItems = new ArrayList();
pathItems.add(systemPlatform());
pathItems.add(systemLocale());
State[] states = new State[] { State.create(pathItems) };
registryBindingSet = Collections.unmodifiableSortedSet(solveRegionalBindingSet(registryRegionalBindingSet, states));
}
public void savePreference() {
XMLMemento xmlMemento = XMLMemento.createWriteRoot("org.eclipse.ui.keybindings");
IMemento memento = xmlMemento.createChild("bindings");
writeBindingSet(memento, preferenceBindingSet);
StringWriter stringWriter = new StringWriter();
String preferenceString = null;
try {
xmlMemento.save(stringWriter);
preferenceString = stringWriter.toString();
} catch (IOException eIO) {
}
IPreferenceStore preferenceStore = WorkbenchPlugin.getDefault().getPreferenceStore();
preferenceStore.setValue("org.eclipse.ui.keybindings", preferenceString);
}
public boolean setPreferenceBindingSet(SortedSet preferenceBindingSet)
throws IllegalArgumentException {
if (preferenceBindingSet == null)
throw new IllegalArgumentException();
preferenceBindingSet = new TreeSet(preferenceBindingSet);
Iterator iterator = preferenceBindingSet.iterator();
while (iterator.hasNext())
if (!(iterator.next() instanceof Binding))
throw new IllegalArgumentException();
if (this.preferenceBindingSet.equals(preferenceBindingSet))
return false;
this.preferenceBindingSet = Collections.unmodifiableSortedSet(preferenceBindingSet);
return true;
}
public void update() {
SortedMap configurationMap = buildConfigurationMap(registryConfigurationMap);
SortedMap scopeMap = buildScopeMap(registryScopeMap);
SortedSet bindingSet = new TreeSet();
bindingSet.addAll(preferenceBindingSet);
bindingSet.addAll(registryBindingSet);
keyMachine.setConfigurationMap(configurationMap);
keyMachine.setScopeMap(scopeMap);
keyMachine.setBindingSet(bindingSet);
}
public String getTextForAction(String action)
throws IllegalArgumentException {
if (action == null)
throw new IllegalArgumentException();
String text = null;
Map actionMap = getKeyMachine().getActionMap();
SortedSet matchSet = (SortedSet) actionMap.get(action);
if (matchSet != null && !matchSet.isEmpty()) {
Match match = (Match) matchSet.first();
if (match != null)
text = getTextForKeySequence(match.getBinding().getKeySequence());
}
return text;
}
public String getTextForKeySequence(KeySequence keySequence)
throws IllegalArgumentException {
if (keySequence == null)
throw new IllegalArgumentException();
StringBuffer stringBuffer = new StringBuffer();
Iterator iterator = keySequence.getKeyStrokes().iterator();
int i = 0;
while (iterator.hasNext()) {
if (i != 0)
stringBuffer.append(KEY_STROKE_SEPARATOR);
KeyStroke keyStroke = (KeyStroke) iterator.next();
int accelerator = keyStroke.getAccelerator();
stringBuffer.append(Action.convertAccelerator(accelerator));
i++;
}
return stringBuffer.toString();
}
}