| /******************************************************************************* |
| * Copyright (c) 2000, 2003 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 Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.ui.internal.commands; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.SortedSet; |
| import java.util.TreeSet; |
| |
| import org.eclipse.ui.internal.WorkbenchPlugin; |
| import org.eclipse.ui.internal.util.Util; |
| import org.eclipse.ui.keys.KeySequence; |
| import org.eclipse.ui.keys.KeyStroke; |
| |
| final class KeySequenceBindingNode { |
| |
| final static class Assignment implements Comparable { |
| boolean hasPluginCommandIdInFirstKeyConfiguration; |
| boolean hasPluginCommandIdInInheritedKeyConfiguration; |
| |
| boolean hasPreferenceCommandIdInFirstKeyConfiguration; |
| boolean hasPreferenceCommandIdInInheritedKeyConfiguration; |
| String pluginCommandIdInFirstKeyConfiguration; |
| String pluginCommandIdInInheritedKeyConfiguration; |
| String preferenceCommandIdInFirstKeyConfiguration; |
| String preferenceCommandIdInInheritedKeyConfiguration; |
| |
| public int compareTo(Object object) { |
| Assignment castedObject = (Assignment) object; |
| int compareTo = |
| hasPreferenceCommandIdInFirstKeyConfiguration == false |
| ? (castedObject.hasPreferenceCommandIdInFirstKeyConfiguration |
| == true |
| ? -1 |
| : 0) |
| : 1; |
| |
| if (compareTo == 0) { |
| compareTo = |
| hasPreferenceCommandIdInInheritedKeyConfiguration == false |
| ? (castedObject |
| .hasPreferenceCommandIdInInheritedKeyConfiguration |
| == true |
| ? -1 |
| : 0) |
| : 1; |
| |
| if (compareTo == 0) { |
| compareTo = |
| hasPluginCommandIdInFirstKeyConfiguration == false |
| ? (castedObject |
| .hasPluginCommandIdInFirstKeyConfiguration |
| == true |
| ? -1 |
| : 0) |
| : 1; |
| |
| if (compareTo == 0) { |
| compareTo = |
| hasPluginCommandIdInInheritedKeyConfiguration |
| == false |
| ? (castedObject |
| .hasPluginCommandIdInInheritedKeyConfiguration |
| == true |
| ? -1 |
| : 0) |
| : 1; |
| |
| if (compareTo == 0) { |
| compareTo = |
| Util.compare( |
| preferenceCommandIdInFirstKeyConfiguration, |
| castedObject |
| .preferenceCommandIdInFirstKeyConfiguration); |
| |
| if (compareTo == 0) { |
| compareTo = |
| Util.compare( |
| preferenceCommandIdInInheritedKeyConfiguration, |
| castedObject |
| .preferenceCommandIdInInheritedKeyConfiguration); |
| |
| if (compareTo == 0) { |
| compareTo = |
| Util.compare( |
| pluginCommandIdInFirstKeyConfiguration, |
| castedObject |
| .pluginCommandIdInFirstKeyConfiguration); |
| |
| if (compareTo == 0) |
| compareTo = |
| Util.compare( |
| pluginCommandIdInInheritedKeyConfiguration, |
| castedObject |
| .pluginCommandIdInInheritedKeyConfiguration); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| return compareTo; |
| } |
| |
| boolean contains(String commandId) { |
| return Util.equals( |
| commandId, |
| preferenceCommandIdInFirstKeyConfiguration) |
| || Util.equals( |
| commandId, |
| preferenceCommandIdInInheritedKeyConfiguration) |
| || Util.equals(commandId, pluginCommandIdInFirstKeyConfiguration) |
| || Util.equals( |
| commandId, |
| pluginCommandIdInInheritedKeyConfiguration); |
| } |
| |
| public boolean equals(Object object) { |
| if (!(object instanceof Assignment)) |
| return false; |
| |
| Assignment castedObject = (Assignment) object; |
| boolean equals = true; |
| equals &= hasPreferenceCommandIdInFirstKeyConfiguration |
| == castedObject.hasPreferenceCommandIdInFirstKeyConfiguration; |
| equals &= hasPreferenceCommandIdInInheritedKeyConfiguration |
| == castedObject.hasPreferenceCommandIdInInheritedKeyConfiguration; |
| equals &= hasPluginCommandIdInFirstKeyConfiguration |
| == castedObject.hasPluginCommandIdInFirstKeyConfiguration; |
| equals &= hasPluginCommandIdInInheritedKeyConfiguration |
| == castedObject.hasPluginCommandIdInInheritedKeyConfiguration; |
| equals &= preferenceCommandIdInFirstKeyConfiguration |
| == castedObject.preferenceCommandIdInFirstKeyConfiguration; |
| equals &= preferenceCommandIdInInheritedKeyConfiguration |
| == castedObject.preferenceCommandIdInInheritedKeyConfiguration; |
| equals &= pluginCommandIdInFirstKeyConfiguration |
| == castedObject.pluginCommandIdInFirstKeyConfiguration; |
| equals &= pluginCommandIdInInheritedKeyConfiguration |
| == castedObject.pluginCommandIdInInheritedKeyConfiguration; |
| return equals; |
| } |
| } |
| |
| static void add( |
| Map keyStrokeNodeByKeyStrokeMap, |
| KeySequence keySequence, |
| String contextId, |
| String keyConfigurationId, |
| int rank, |
| String platform, |
| String locale, |
| String commandId) { |
| List keyStrokes = keySequence.getKeyStrokes(); |
| Map root = keyStrokeNodeByKeyStrokeMap; |
| KeySequenceBindingNode keySequenceBindingNode = null; |
| |
| for (int i = 0; i < keyStrokes.size(); i++) { |
| KeyStroke keyStroke = (KeyStroke) keyStrokes.get(i); |
| keySequenceBindingNode = |
| (KeySequenceBindingNode) root.get(keyStroke); |
| |
| if (keySequenceBindingNode == null) { |
| keySequenceBindingNode = new KeySequenceBindingNode(); |
| root.put(keyStroke, keySequenceBindingNode); |
| } |
| |
| root = keySequenceBindingNode.childKeyStrokeNodeByKeyStrokeMap; |
| } |
| |
| if (keySequenceBindingNode != null) |
| keySequenceBindingNode.add( |
| contextId, |
| keyConfigurationId, |
| rank, |
| platform, |
| locale, |
| commandId); |
| } |
| |
| static Map find(Map keyStrokeNodeByKeyStrokeMap, KeySequence keySequence) { |
| Iterator iterator = keySequence.getKeyStrokes().iterator(); |
| KeySequenceBindingNode keySequenceBindingNode = null; |
| |
| while (iterator.hasNext()) { |
| keySequenceBindingNode = |
| (KeySequenceBindingNode) keyStrokeNodeByKeyStrokeMap.get( |
| iterator.next()); |
| |
| if (keySequenceBindingNode == null) |
| return null; |
| |
| keyStrokeNodeByKeyStrokeMap = |
| keySequenceBindingNode.childKeyStrokeNodeByKeyStrokeMap; |
| } |
| |
| return keyStrokeNodeByKeyStrokeMap; |
| } |
| |
| static Map getAssignmentsByContextIdKeySequence( |
| Map keyStrokeNodeByKeyStrokeMap, |
| KeySequence prefix) { |
| Map assignmentsByContextIdByKeySequence = new HashMap(); |
| Iterator iterator = keyStrokeNodeByKeyStrokeMap.entrySet().iterator(); |
| |
| while (iterator.hasNext()) { |
| Map.Entry entry = (Map.Entry) iterator.next(); |
| KeyStroke keyStroke = (KeyStroke) entry.getKey(); |
| KeySequenceBindingNode keySequenceBindingNode = |
| (KeySequenceBindingNode) entry.getValue(); |
| List keyStrokes = new ArrayList(prefix.getKeyStrokes()); |
| keyStrokes.add(keyStroke); |
| KeySequence keySequence = KeySequence.getInstance(keyStrokes); |
| Map childAssignmentsByContextIdByKeySequence = |
| getAssignmentsByContextIdKeySequence( |
| keySequenceBindingNode.childKeyStrokeNodeByKeyStrokeMap, |
| keySequence); |
| |
| if (childAssignmentsByContextIdByKeySequence.size() >= 1) |
| assignmentsByContextIdByKeySequence.putAll( |
| childAssignmentsByContextIdByKeySequence); |
| |
| assignmentsByContextIdByKeySequence.put( |
| keySequence, |
| keySequenceBindingNode.assignmentsByContextId); |
| } |
| |
| return assignmentsByContextIdByKeySequence; |
| } |
| |
| static void getKeySequenceBindingDefinitions( |
| Map keyStrokeNodeByKeyStrokeMap, |
| KeySequence prefix, |
| int rank, |
| List keySequenceBindingDefinitions) { |
| Iterator iterator = keyStrokeNodeByKeyStrokeMap.entrySet().iterator(); |
| |
| while (iterator.hasNext()) { |
| Map.Entry entry = (Map.Entry) iterator.next(); |
| KeyStroke keyStroke = (KeyStroke) entry.getKey(); |
| KeySequenceBindingNode keySequenceBindingNode = |
| (KeySequenceBindingNode) entry.getValue(); |
| List keyStrokes = new ArrayList(prefix.getKeyStrokes()); |
| keyStrokes.add(keyStroke); |
| KeySequence keySequence = KeySequence.getInstance(keyStrokes); |
| Map contextMap = keySequenceBindingNode.contextMap; |
| Iterator iterator2 = contextMap.entrySet().iterator(); |
| |
| while (iterator2.hasNext()) { |
| Map.Entry entry2 = (Map.Entry) iterator2.next(); |
| String contextId = (String) entry2.getKey(); |
| Map keyConfigurationMap = (Map) entry2.getValue(); |
| Iterator iterator3 = keyConfigurationMap.entrySet().iterator(); |
| |
| while (iterator3.hasNext()) { |
| Map.Entry entry3 = (Map.Entry) iterator3.next(); |
| String keyConfigurationId = (String) entry3.getKey(); |
| Map rankMap = (Map) entry3.getValue(); |
| Map platformMap = (Map) rankMap.get(new Integer(rank)); |
| |
| if (platformMap != null) { |
| Iterator iterator4 = platformMap.entrySet().iterator(); |
| |
| while (iterator4.hasNext()) { |
| Map.Entry entry4 = (Map.Entry) iterator4.next(); |
| String platform = (String) entry4.getKey(); |
| Map localeMap = (Map) entry4.getValue(); |
| Iterator iterator5 = |
| localeMap.entrySet().iterator(); |
| |
| while (iterator5.hasNext()) { |
| Map.Entry entry5 = (Map.Entry) iterator5.next(); |
| String locale = (String) entry5.getKey(); |
| Set commandIds = (Set) entry5.getValue(); |
| Iterator iterator6 = commandIds.iterator(); |
| |
| while (iterator6.hasNext()) { |
| String commandId = |
| (String) iterator6.next(); |
| keySequenceBindingDefinitions.add( |
| new KeySequenceBindingDefinition( |
| contextId, |
| commandId, |
| keyConfigurationId, |
| keySequence, |
| locale, |
| platform, |
| null)); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| getKeySequenceBindingDefinitions( |
| keySequenceBindingNode.childKeyStrokeNodeByKeyStrokeMap, |
| keySequence, |
| rank, |
| keySequenceBindingDefinitions); |
| } |
| } |
| |
| static Map getKeySequenceBindingsByCommandId(Map keySequenceMap) { |
| Map commandMap = new HashMap(); |
| Iterator iterator = keySequenceMap.entrySet().iterator(); |
| |
| while (iterator.hasNext()) { |
| Map.Entry entry = (Map.Entry) iterator.next(); |
| KeySequence keySequence = (KeySequence) entry.getKey(); |
| Match match = (Match) entry.getValue(); |
| String commandId = match.getCommandId(); |
| int value = match.getValue(); |
| SortedSet keySequenceBindings = |
| (SortedSet) commandMap.get(commandId); |
| |
| if (keySequenceBindings == null) { |
| keySequenceBindings = new TreeSet(); |
| commandMap.put(commandId, keySequenceBindings); |
| } |
| |
| keySequenceBindings.add(new KeySequenceBinding(keySequence, value)); |
| } |
| |
| return commandMap; |
| } |
| |
| static Map getMatchesByKeySequence( |
| Map keyStrokeNodeByKeyStrokeMap, |
| KeySequence prefix) { |
| Map keySequenceMap = new HashMap(); |
| Iterator iterator = keyStrokeNodeByKeyStrokeMap.entrySet().iterator(); |
| |
| while (iterator.hasNext()) { |
| Map.Entry entry = (Map.Entry) iterator.next(); |
| KeyStroke keyStroke = (KeyStroke) entry.getKey(); |
| KeySequenceBindingNode keySequenceBindingNode = |
| (KeySequenceBindingNode) entry.getValue(); |
| List keyStrokes = new ArrayList(prefix.getKeyStrokes()); |
| keyStrokes.add(keyStroke); |
| KeySequence keySequence = KeySequence.getInstance(keyStrokes); |
| Map childMatchesByKeySequence = |
| getMatchesByKeySequence( |
| keySequenceBindingNode.childKeyStrokeNodeByKeyStrokeMap, |
| keySequence); |
| |
| if (childMatchesByKeySequence.size() >= 1) |
| keySequenceMap.putAll(childMatchesByKeySequence); |
| else if ( |
| keySequenceBindingNode.match != null |
| && keySequenceBindingNode.match.getCommandId() != null) |
| keySequenceMap.put(keySequence, keySequenceBindingNode.match); |
| } |
| |
| return keySequenceMap; |
| } |
| |
| static void remove( |
| Map keyStrokeNodeByKeyStrokeMap, |
| KeySequence keySequence, |
| String contextId, |
| String keyConfigurationId, |
| int rank, |
| String platform, |
| String locale) { |
| Iterator iterator = keySequence.getKeyStrokes().iterator(); |
| KeySequenceBindingNode keySequenceBindingNode = null; |
| |
| while (iterator.hasNext()) { |
| keySequenceBindingNode = |
| (KeySequenceBindingNode) keyStrokeNodeByKeyStrokeMap.get( |
| iterator.next()); |
| |
| if (keySequenceBindingNode == null) |
| return; |
| |
| keyStrokeNodeByKeyStrokeMap = |
| keySequenceBindingNode.childKeyStrokeNodeByKeyStrokeMap; |
| } |
| |
| keySequenceBindingNode.remove( |
| contextId, |
| keyConfigurationId, |
| rank, |
| platform, |
| locale); |
| } |
| |
| static void remove( |
| Map keyStrokeNodeByKeyStrokeMap, |
| KeySequence keySequence, |
| String contextId, |
| String keyConfigurationId, |
| int rank, |
| String platform, |
| String locale, |
| String commandId) { |
| Iterator iterator = keySequence.getKeyStrokes().iterator(); |
| KeySequenceBindingNode keySequenceBindingNode = null; |
| |
| while (iterator.hasNext()) { |
| keySequenceBindingNode = |
| (KeySequenceBindingNode) keyStrokeNodeByKeyStrokeMap.get( |
| iterator.next()); |
| |
| if (keySequenceBindingNode == null) |
| return; |
| |
| keyStrokeNodeByKeyStrokeMap = |
| keySequenceBindingNode.childKeyStrokeNodeByKeyStrokeMap; |
| } |
| |
| keySequenceBindingNode.remove( |
| contextId, |
| keyConfigurationId, |
| rank, |
| platform, |
| locale, |
| commandId); |
| } |
| |
| static void solve( |
| Map keyStrokeNodeByKeyStrokeMap, |
| String[] keyConfigurationIds, |
| String[] platforms, |
| String[] locales) { |
| for (Iterator iterator = |
| keyStrokeNodeByKeyStrokeMap.values().iterator(); |
| iterator.hasNext(); |
| ) { |
| KeySequenceBindingNode keySequenceBindingNode = |
| (KeySequenceBindingNode) iterator.next(); |
| keySequenceBindingNode.solveAssignmentsByContextId( |
| keyConfigurationIds, |
| platforms, |
| locales); |
| solve( |
| keySequenceBindingNode.childKeyStrokeNodeByKeyStrokeMap, |
| keyConfigurationIds, |
| platforms, |
| locales); |
| } |
| } |
| |
| static void solve( |
| Map keyStrokeNodeByKeyStrokeMap, |
| Map contextIds, |
| String[] keyConfigurationIds, |
| String[] platforms, |
| String[] locales) { |
| for (Iterator iterator = |
| keyStrokeNodeByKeyStrokeMap.values().iterator(); |
| iterator.hasNext(); |
| ) { |
| KeySequenceBindingNode keySequenceBindingNode = |
| (KeySequenceBindingNode) iterator.next(); |
| keySequenceBindingNode.solveMatch( |
| contextIds, |
| keyConfigurationIds, |
| platforms, |
| locales); |
| solve( |
| keySequenceBindingNode.childKeyStrokeNodeByKeyStrokeMap, |
| contextIds, |
| keyConfigurationIds, |
| platforms, |
| locales); |
| } |
| } |
| private Map contextMap = new HashMap(); |
| |
| private Map assignmentsByContextId = new HashMap(); |
| private Map childKeyStrokeNodeByKeyStrokeMap = new HashMap(); |
| private Match match = null; |
| |
| private KeySequenceBindingNode() { |
| } |
| |
| private void add( |
| String contextId, |
| String keyConfigurationId, |
| int rank, |
| String platform, |
| String locale, |
| String commandId) { |
| Map keyConfigurationMap = (Map) contextMap.get(contextId); |
| |
| if (keyConfigurationMap == null) { |
| keyConfigurationMap = new HashMap(); |
| contextMap.put(contextId, keyConfigurationMap); |
| } |
| |
| Map rankMap = (Map) keyConfigurationMap.get(keyConfigurationId); |
| |
| if (rankMap == null) { |
| rankMap = new HashMap(); |
| keyConfigurationMap.put(keyConfigurationId, rankMap); |
| } |
| |
| Map platformMap = (Map) rankMap.get(new Integer(rank)); |
| |
| if (platformMap == null) { |
| platformMap = new HashMap(); |
| rankMap.put(new Integer(rank), platformMap); |
| } |
| |
| Map localeMap = (Map) platformMap.get(platform); |
| |
| if (localeMap == null) { |
| localeMap = new HashMap(); |
| platformMap.put(platform, localeMap); |
| } |
| |
| Set commandIds = (Set) localeMap.get(locale); |
| |
| if (commandIds == null) { |
| commandIds = new HashSet(); |
| localeMap.put(locale, commandIds); |
| } |
| |
| commandIds.add(commandId); |
| } |
| |
| private void remove( |
| String contextId, |
| String keyConfigurationId, |
| int rank, |
| String platform, |
| String locale) { |
| Map keyConfigurationMap = (Map) contextMap.get(contextId); |
| |
| if (keyConfigurationMap != null) { |
| Map rankMap = (Map) keyConfigurationMap.get(keyConfigurationId); |
| |
| if (rankMap != null) { |
| Map platformMap = (Map) rankMap.get(new Integer(rank)); |
| |
| if (platformMap != null) { |
| Map localeMap = (Map) platformMap.get(platform); |
| |
| if (localeMap != null) { |
| localeMap.remove(locale); |
| |
| if (localeMap.isEmpty()) { |
| platformMap.remove(platform); |
| |
| if (platformMap.isEmpty()) { |
| rankMap.remove(new Integer(rank)); |
| |
| if (rankMap.isEmpty()) { |
| keyConfigurationMap.remove( |
| keyConfigurationId); |
| |
| if (keyConfigurationMap.isEmpty()) |
| contextMap.remove(contextId); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| private void remove( |
| String contextId, |
| String keyConfigurationId, |
| int rank, |
| String platform, |
| String locale, |
| String commandId) { |
| Map keyConfigurationMap = (Map) contextMap.get(contextId); |
| |
| if (keyConfigurationMap != null) { |
| Map rankMap = (Map) keyConfigurationMap.get(keyConfigurationId); |
| |
| if (rankMap != null) { |
| Map platformMap = (Map) rankMap.get(new Integer(rank)); |
| |
| if (platformMap != null) { |
| Map localeMap = (Map) platformMap.get(platform); |
| |
| if (localeMap != null) { |
| Set commandIds = (Set) localeMap.get(locale); |
| |
| if (commandIds != null) { |
| commandIds.remove(commandId); |
| |
| if (commandIds.isEmpty()) { |
| localeMap.remove(locale); |
| |
| if (localeMap.isEmpty()) { |
| platformMap.remove(platform); |
| |
| if (platformMap.isEmpty()) { |
| rankMap.remove(new Integer(rank)); |
| |
| if (rankMap.isEmpty()) { |
| keyConfigurationMap.remove( |
| keyConfigurationId); |
| |
| if (keyConfigurationMap.isEmpty()) |
| contextMap.remove(contextId); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| private void solveAssignmentsByContextId( |
| String[] keyConfigurationIds, |
| String[] platforms, |
| String[] locales) { |
| assignmentsByContextId.clear(); |
| |
| for (Iterator iterator = contextMap.entrySet().iterator(); |
| iterator.hasNext(); |
| ) { |
| Map.Entry entry = (Map.Entry) iterator.next(); |
| String contextId = (String) entry.getKey(); |
| Map keyConfigurationMap = (Map) entry.getValue(); |
| KeySequenceBindingNode.Assignment assignment = null; |
| |
| if (keyConfigurationMap != null) |
| for (int keyConfiguration = 0; |
| keyConfiguration < keyConfigurationIds.length |
| && keyConfiguration < 0xFF; |
| keyConfiguration++) { |
| Map rankMap = |
| (Map) keyConfigurationMap.get( |
| keyConfigurationIds[keyConfiguration]); |
| |
| if (rankMap != null) |
| for (int rank = 0; rank <= 1; rank++) { |
| Map platformMap = |
| (Map) rankMap.get(new Integer(rank)); |
| |
| if (platformMap != null) |
| for (int platform = 0; |
| platform < platforms.length |
| && platform < 0xFF; |
| platform++) { |
| Map localeMap = |
| (Map) platformMap.get( |
| platforms[platform]); |
| |
| if (localeMap != null) |
| for (int locale = 0; |
| locale < locales.length |
| && locale < 0xFF; |
| locale++) { |
| Set commandIds = |
| (Set) localeMap.get( |
| locales[locale]); |
| |
| if (commandIds != null) { |
| String commandId = |
| commandIds.size() == 1 |
| ? (String) commandIds |
| .iterator() |
| .next() |
| : null; |
| |
| if (assignment == null) |
| assignment = |
| new Assignment(); |
| |
| switch (rank) { |
| case 0 : |
| if (keyConfiguration |
| == 0 |
| && !assignment |
| .hasPreferenceCommandIdInFirstKeyConfiguration) { |
| assignment |
| .hasPreferenceCommandIdInFirstKeyConfiguration = |
| true; |
| assignment |
| .preferenceCommandIdInFirstKeyConfiguration = |
| commandId; |
| } else if ( |
| !assignment |
| .hasPreferenceCommandIdInInheritedKeyConfiguration) { |
| assignment |
| .hasPreferenceCommandIdInInheritedKeyConfiguration = |
| true; |
| assignment |
| .preferenceCommandIdInInheritedKeyConfiguration = |
| commandId; |
| } |
| |
| break; |
| |
| case 1 : |
| if (keyConfiguration |
| == 0 |
| && !assignment |
| .hasPluginCommandIdInFirstKeyConfiguration) { |
| assignment |
| .hasPluginCommandIdInFirstKeyConfiguration = |
| true; |
| assignment |
| .pluginCommandIdInFirstKeyConfiguration = |
| commandId; |
| } else if ( |
| !assignment |
| .hasPluginCommandIdInInheritedKeyConfiguration) { |
| assignment |
| .hasPluginCommandIdInInheritedKeyConfiguration = |
| true; |
| assignment |
| .pluginCommandIdInInheritedKeyConfiguration = |
| commandId; |
| } |
| |
| break; |
| } |
| } |
| } |
| } |
| |
| } |
| |
| } |
| |
| if (assignment != null) |
| assignmentsByContextId.put(contextId, assignment); |
| } |
| } |
| |
| /** |
| * <p> |
| * Finds a single match for this key binding node, given the state passed in |
| * as parameters. The match will contain a single command identifier, and a |
| * match value (a rough approximation of how accurate the match may be -- |
| * lower is better). |
| * </p> |
| * <p> |
| * The matching algorithm checks for a match in each context given -- in the |
| * order provided. Similar, it checks the key configuration, the rank (see |
| * below), the platform, and the locale -- in the order provided. If a |
| * single command identifier (note: this could be <code>null</code>-- |
| * indicating a removed key binding) matches the given characteristics, then |
| * it is added to the list. For each context identifier, there can be at |
| * most one match. If there is no match, |
| * <em>or the match has a <code>null</code> command identifier</em>, |
| * then we will move on to consider the next context. |
| * </p> |
| * <p> |
| * The rank is a special value. It is either <code>0</code> or |
| * <code>1</code>. It is used for marking removed key bindings. The |
| * removed command identifier is moved to the first rank, and a |
| * <code>null</code> command identifier is placed in the zeroth rank. The |
| * ranking mechanism is controlled externally, but only the zeroth and first |
| * ranks are considered internally. |
| * </p> |
| * <p> |
| * When this method completes, <code>match</code> will contain the best |
| * possible match, if any. If no match can be found, then <code>match</code> |
| * will be <code>null</code>. |
| * </p> |
| * <p> |
| * TODO Doug's Note (May 29, 2004): This mechanism is insanely complex for |
| * what it is doing, and doesn't seem to cover all of the use cases. This |
| * would be a good candidate for refactoring in the future. Most of this |
| * code was written by Chris McLaren, but I've had to hack in some |
| * behavioural changes to accomodate bugs for 3.0. If you're looking for |
| * insight as to how it currently works, you might try talking to one of us. |
| * Most notably, the fall through mechanism for <code>null</code> command |
| * identifiers. My main concerns are: interactions between key |
| * configurations, and unbinding a key in a child context so as to bind it |
| * in a parent context. |
| * </p> |
| * |
| * @param contextTree |
| * The tree of contexts to consider. The tree is represented as a |
| * map of child context identifiers to parent context |
| * identifiers. This value must never be <code>null</code>, |
| * though it may contain <code>null</code> parents. It should |
| * never contain <code>null</code> children. It should only |
| * contain strings. |
| * @param keyConfigurationIds |
| * The key configuration identifiers in the order they should be |
| * considered. This value must never be <code>null</code>, |
| * though it may contain <code>null</code> values. |
| * <code>null</code> values typically indicate "any". |
| * @param platforms |
| * The platform identifiers in the order they should be |
| * considered. This value must never be <code>null</code>, |
| * though it may contain <code>null</code> values. |
| * <code>null</code> values typically indicate "any". |
| * @param locales |
| * The locale identifiers in the order they should be considered. |
| * This value must never be <code>null</code>, though it may |
| * contain <code>null</code> values. <code>null</code> values |
| * typically indicate "any". |
| */ |
| private void solveMatch(Map contextTree, |
| String[] keyConfigurationIds, String[] platforms, String[] locales) { |
| // Clear out the current match. |
| match = null; |
| |
| // Get an array of context identifiers. |
| final String[] contextIds = (String[]) contextTree.keySet().toArray( |
| new String[contextTree.size()]); |
| |
| // Get the maximum indices to consider. |
| final int maxContext = (contextIds.length > 0xFF) ? 0xFF |
| : contextIds.length; |
| int maxKeyConfiguration = (keyConfigurationIds.length > 0xFF) ? 0xFF |
| : keyConfigurationIds.length; |
| final int maxPlatform = (platforms.length > 0xFF) ? 0xFF |
| : platforms.length; |
| final int maxLocale = (locales.length > 0xFF) ? 0xFF : locales.length; |
| |
| // Peel apart the nested map looking for matches. |
| final Collection contextIdsNotToConsider = new HashSet(); |
| for (int context = 0; context < maxContext; context++) { |
| boolean matchFoundForThisContext = false; |
| |
| /* |
| * Check to see if the context identifier has been nixed by a child |
| * context. That is, has a non-null match been found in a child |
| * context? |
| */ |
| final String contextId = contextIds[context]; |
| if (contextIdsNotToConsider.contains(contextId)) { |
| continue; |
| } |
| |
| final Map keyConfigurationMap = (Map) contextMap.get(contextId); |
| if (keyConfigurationMap != null) |
| for (int keyConfiguration = 0; keyConfiguration < maxKeyConfiguration |
| && !matchFoundForThisContext; keyConfiguration++) { |
| final Map rankMap = (Map) keyConfigurationMap |
| .get(keyConfigurationIds[keyConfiguration]); |
| |
| if (rankMap != null) { |
| for (int rank = 0; rank <= 1; rank++) { |
| final Map platformMap = (Map) rankMap |
| .get(new Integer(rank)); |
| |
| if (platformMap != null) |
| for (int platform = 0; platform < maxPlatform |
| && !matchFoundForThisContext; platform++) { |
| final Map localeMap = (Map) platformMap |
| .get(platforms[platform]); |
| |
| if (localeMap != null) |
| for (int locale = 0; locale < maxLocale |
| && !matchFoundForThisContext; locale++) { |
| final Set commandIds = (Set) localeMap |
| .get(locales[locale]); |
| |
| if (commandIds != null) { |
| /* |
| * Jump to the next |
| * context. |
| */ |
| matchFoundForThisContext = true; |
| |
| /* |
| * Get the command |
| * identifier. |
| */ |
| final String commandId = commandIds |
| .size() == 1 ? (String) commandIds |
| .iterator() |
| .next() |
| : null; |
| |
| /* |
| * Make sure we |
| * don't consider |
| * any higher key |
| * configurations |
| * again. |
| */ |
| maxKeyConfiguration = keyConfiguration + 1; |
| |
| /* |
| * Make sure we |
| * don't consider |
| * any parents of |
| * this context, if |
| * the command |
| * identifier is not |
| * null. |
| */ |
| if (commandId != null) { |
| String parentContext = (String) contextTree |
| .get(contextId); |
| while (parentContext != null) { |
| contextIdsNotToConsider |
| .add(parentContext); |
| parentContext = (String) contextTree |
| .get(parentContext); |
| } |
| |
| /* |
| * Check for a |
| * conflict. |
| */ |
| if ((match != null) |
| && (!contextIdsNotToConsider |
| .contains(contextIds[match |
| .getValue() >> 24]))) { |
| WorkbenchPlugin |
| .log("Conflicting key binding for '" //$NON-NLS-1$ |
| + commandId |
| + "' and '" //$NON-NLS-1$ |
| + match |
| .getCommandId() |
| + "'"); //$NON-NLS-1$ |
| match = null; |
| |
| } else { |
| match = new Match( |
| commandId, |
| (context << 24) |
| + (keyConfiguration << 16) |
| + (platform << 8) |
| + locale); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |