📄 bindingmanager.java
字号:
map.put(triggerSequence, binding); } } } return prefixTable; } /** * <p> * Clears the cache, and the existing solution. If debugging is turned on, * then this will also print a message to standard out. * </p> * <p> * This method completes in <code>O(1)</code>. * </p> */ private final void clearCache() { if (DEBUG) { Tracing.printTrace("BINDINGS", "Clearing cache"); //$NON-NLS-1$ //$NON-NLS-2$ } cachedBindings.clear(); clearSolution(); } /** * <p> * Clears the existing solution. * </p> * <p> * This method completes in <code>O(1)</code>. */ private final void clearSolution() { setActiveBindings(null, null, null); } /** * Compares the identifier of two schemes, and decides which scheme is the * youngest (i.e., the child) of the two. Both schemes should be active * schemes. * * @param schemeId1 * The identifier of the first scheme; must not be * <code>null</code>. * @param schemeId2 * The identifier of the second scheme; must not be * <code>null</code>. * @return <code>0</code> if the two schemes are equal of if neither * scheme is active; <code>1</code> if the second scheme is the * youngest; and <code>-1</code> if the first scheme is the * youngest. * @since 3.2 */ private final int compareSchemes(final String schemeId1, final String schemeId2) { if (!schemeId2.equals(schemeId1)) { for (int i = 0; i < activeSchemeIds.length; i++) { final String schemePointer = activeSchemeIds[i]; if (schemeId2.equals(schemePointer)) { return 1; } else if (schemeId1.equals(schemePointer)) { return -1; } } } return 0; } /** * <p> * Computes the bindings given the context tree, and inserts them into the * <code>commandIdsByTrigger</code>. It is assumed that * <code>locales</code>,<code>platforsm</code> and * <code>schemeIds</code> correctly reflect the state of the application. * This method does not deal with caching. * </p> * <p> * This method completes in <code>O(n)</code>, where <code>n</code> is * the number of bindings. * </p> * * @param activeContextTree * The map representing the tree of active contexts. The map is * one of child to parent, each being a context id ( * <code>String</code>). The keys are never <code>null</code>, * but the values may be (i.e., no parent). This map may be * empty. It may be <code>null</code> if we shouldn't consider * contexts. * @param bindingsByTrigger * The empty of map that is intended to be filled with triggers ( * <code>TriggerSequence</code>) to bindings ( * <code>Binding</code>). This value must not be * <code>null</code> and must be empty. * @param triggersByCommandId * The empty of map that is intended to be filled with command * identifiers (<code>String</code>) to triggers ( * <code>TriggerSequence</code>). This value must either be * <code>null</code> (indicating that these values are not * needed), or empty (indicating that this map should be * computed). */ private final void computeBindings(final Map activeContextTree, final Map bindingsByTrigger, final Map triggersByCommandId) { /* * FIRST PASS: Remove all of the bindings that are marking deletions. */ final Binding[] trimmedBindings = removeDeletions(bindings); /* * SECOND PASS: Just throw in bindings that match the current state. If * there is more than one match for a binding, then create a list. */ final Map possibleBindings = new HashMap(); final int length = trimmedBindings.length; for (int i = 0; i < length; i++) { final Binding binding = trimmedBindings[i]; boolean found; // Check the context. final String contextId = binding.getContextId(); if ((activeContextTree != null) && (!activeContextTree.containsKey(contextId))) { continue; } // Check the locale. if (!localeMatches(binding)) { continue; } // Check the platform. if (!platformMatches(binding)) { continue; } // Check the scheme ids. final String schemeId = binding.getSchemeId(); found = false; if (activeSchemeIds != null) { for (int j = 0; j < activeSchemeIds.length; j++) { if (Util.equals(schemeId, activeSchemeIds[j])) { found = true; break; } } } if (!found) { continue; } // Insert the match into the list of possible matches. final TriggerSequence trigger = binding.getTriggerSequence(); final Object existingMatch = possibleBindings.get(trigger); if (existingMatch instanceof Binding) { possibleBindings.remove(trigger); final Collection matches = new ArrayList(); matches.add(existingMatch); matches.add(binding); possibleBindings.put(trigger, matches); } else if (existingMatch instanceof Collection) { final Collection matches = (Collection) existingMatch; matches.add(binding); } else { possibleBindings.put(trigger, binding); } } /* * THIRD PASS: In this pass, we move any non-conflicting bindings * directly into the map. In the case of conflicts, we apply some * further logic to try to resolve them. If the conflict can't be * resolved, then we log the problem. */ final Iterator possibleBindingItr = possibleBindings.entrySet() .iterator(); while (possibleBindingItr.hasNext()) { final Map.Entry entry = (Map.Entry) possibleBindingItr.next(); final TriggerSequence trigger = (TriggerSequence) entry.getKey(); final Object match = entry.getValue(); /* * What we do depends slightly on whether we are trying to build a * list of all possible bindings (disregarding context), or a flat * map given the currently active contexts. */ if (activeContextTree == null) { // We are building the list of all possible bindings. final Collection bindings = new ArrayList(); if (match instanceof Binding) { bindings.add(match); bindingsByTrigger.put(trigger, bindings); addReverseLookup(triggersByCommandId, ((Binding) match) .getParameterizedCommand(), trigger); } else if (match instanceof Collection) { bindings.addAll(resolveConflicts((Collection) match)); bindingsByTrigger.put(trigger, bindings); final Iterator matchItr = bindings.iterator(); while (matchItr.hasNext()) { addReverseLookup(triggersByCommandId, ((Binding) matchItr.next()) .getParameterizedCommand(), trigger); } } } else { // We are building the flat map of trigger to commands. if (match instanceof Binding) { final Binding binding = (Binding) match; bindingsByTrigger.put(trigger, binding); addReverseLookup(triggersByCommandId, binding .getParameterizedCommand(), trigger); } else if (match instanceof Collection) { final Binding winner = resolveConflicts((Collection) match, activeContextTree); if (winner == null) { if (DEBUG) { Tracing.printTrace("BINDINGS", //$NON-NLS-1$ "A conflict occurred for " + trigger); //$NON-NLS-1$ Tracing.printTrace("BINDINGS", " " + match); //$NON-NLS-1$ //$NON-NLS-2$ } } else { bindingsByTrigger.put(trigger, winner); addReverseLookup(triggersByCommandId, winner .getParameterizedCommand(), trigger); } } } } } /** * <p> * Notifies this manager that the context manager has changed. This method * is intended for internal use only. * </p> * <p> * This method completes in <code>O(1)</code>. * </p> */ public final void contextManagerChanged( final ContextManagerEvent contextManagerEvent) { if (contextManagerEvent.isActiveContextsChanged()) { clearSolution(); } } /** * Returns the number of strokes in an array of triggers. It is assumed that * there is one natural key per trigger. The strokes are counted based on * the type of key. Natural keys are worth one; ctrl is worth two; shift is * worth four; and alt is worth eight. * * @param triggers * The triggers on which to count strokes; must not be * <code>null</code>. * @return The value of the strokes in the triggers. * @since 3.2 */ private final int countStrokes(final Trigger[] triggers) { int strokeCount = triggers.length; for (int i = 0; i < triggers.length; i++) { final Trigger trigger = triggers[i]; if (trigger instanceof KeyStroke) { final KeyStroke keyStroke = (KeyStroke) trigger; final int modifierKeys = keyStroke.getModifierKeys(); final IKeyLookup lookup = KeyLookupFactory.getDefault(); if ((modifierKeys & lookup.getAlt()) != 0) { strokeCount += 8; } if ((modifierKeys & lookup.getCtrl()) != 0) { strokeCount += 2; } if ((modifierKeys & lookup.getShift()) != 0) { strokeCount += 4; } if ((modifierKeys & lookup.getCommand()) != 0) { strokeCount += 2; } } else { strokeCount += 99; } } return strokeCount; } /** * <p> * Creates a tree of context identifiers, representing the hierarchical * structure of the given contexts. The tree is structured as a mapping from * child to parent. * </p> * <p> * This method completes in <code>O(n)</code>, where <code>n</code> is * the height of the context tree. * </p> * * @param contextIds * The set of context identifiers to be converted into a tree; * must not be <code>null</code>. * @return The tree of contexts to use; may be empty, but never * <code>null</code>. The keys and values are both strings. */ private final Map createContextTreeFor(final Set contextIds) { final Map contextTree = new HashMap(); final Iterator contextIdItr = contextIds.iterator(); while (contextIdItr.hasNext()) { String childContextId = (String) contextIdItr.next(); while (childContextId != null) { // Check if we've already got the part of the tree from here up. if (contextTree.containsKey(childContextId)) { break; } // Retrieve the context. final Context childContext = contextManager .getContext(childContextId); // Add the child-parent pair to the tree. try { final String parentContextId = childContext.getParentId(); contextTree.put(childContextId, parentContextId); childContextId = parentContextId; } catch (final NotDefinedException e) { break; // stop ascending } } } return contextTree; } /** * <p> * Creates a tree of context identifiers, representing the hierarchical * structure of the given contexts. The tree is structured as a mapping from * child to parent. In this tree, the key binding specific filtering of * contexts will have taken place. * </p> * <p> * This method completes in <code>O(n^2)</code>, where <code>n</code> * is the height of the context tree. * </p> * * @param contextIds * The set of context identifiers to be converted into a tree; * must not be <code>null</code>. * @return The tree of contexts to use; may be empty, but never * <code>null</code>. The keys and values are both strings. */ private final Map createFilteredContextTreeFor(final Set contextIds) { // Check to see whether a dialog or window is active. boolean dialog = false; boolean window = false; Iterator contextIdItr = contextIds.iterator(); while (contextIdItr.hasNext()) { final String contextId = (String) contextIdItr.next(); if (IContextIds.CONTEXT_ID_DIALOG.equals(contextId)) { dialog = true; continue; } if (IContextIds.CONTEXT_ID_WINDOW.equals(contextId)) { window = true; continue; } } /* * Remove all context identifiers for contexts whose parents are dialog * or window, and the corresponding dialog or window context is not * active. */ contextIdItr = contextIds.iterator(); while (contextIdItr.hasNext()) { String contextId = (String) contextIdItr.next(); Context context = contextManager.getContext(contextId); try { String parentId = context.getParentId(); while (parentId != null) { if (IContextIds.CONTEXT_ID_DIALOG.equals(parentId)) { if (!dialog) { contextIdItr.remove(); } break; } if (IContextIds.CONTEXT_ID_WINDOW.equals(parentId)) { if (!window) { contextIdItr.remove(); } break; } if (IContextIds.CONTEXT_ID_DIALOG_AND_WINDOW
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -