📄 bindingmanager.java
字号:
return true; // shortcut a common case } for (int i = 0; i < locales.length; i++) { if (Util.equals(locales[i], locale)) { matches = true; break; } } return matches; } /** * <p> * Tests whether the platform for the binding matches one of the active * platforms. * </p> * <p> * This method completes in <code>O(n)</code>, where <code>n</code> is * the number of active platforms. * </p> * * @param binding * The binding with which to test; must not be <code>null</code>. * @return <code>true</code> if the binding's platform matches; * <code>false</code> otherwise. */ private final boolean platformMatches(final Binding binding) { boolean matches = false; final String platform = binding.getPlatform(); if (platform == null) { return true; // shortcut a common case } for (int i = 0; i < platforms.length; i++) { if (Util.equals(platforms[i], platform)) { matches = true; break; } } return matches; } /** * <p> * This recomputes the bindings based on changes to the state of the world. * This computation can be triggered by changes to contexts, the active * scheme, the locale, or the platform. This method tries to use the cache * of pre-computed bindings, if possible. When this method completes, * <code>activeBindings</code> will be set to the current set of bindings * and <code>cachedBindings</code> will contain an instance of * <code>CachedBindingSet</code> representing these bindings. * </p> * <p> * This method completes in <code>O(n+pn)</code>, where <code>n</code> * is the number of bindings, and <code>p</code> is the average number of * triggers in a trigger sequence. * </p> */ private final void recomputeBindings() { if (bindings == null) { // Not yet initialized. This is happening too early. Do nothing. setActiveBindings(Collections.EMPTY_MAP, Collections.EMPTY_MAP, Collections.EMPTY_MAP); return; } // Figure out the current state. final Set activeContextIds = new HashSet(contextManager .getActiveContextIds()); final Map activeContextTree = createFilteredContextTreeFor(activeContextIds); // Build a cached binding set for that state. final CachedBindingSet bindingCache = new CachedBindingSet( activeContextTree, locales, platforms, activeSchemeIds); /* * Check if the cached binding set already exists. If so, simply set the * active bindings and return. */ CachedBindingSet existingCache = (CachedBindingSet) cachedBindings .get(bindingCache); if (existingCache == null) { existingCache = bindingCache; cachedBindings.put(existingCache, existingCache); } Map commandIdsByTrigger = existingCache.getBindingsByTrigger(); if (commandIdsByTrigger != null) { if (DEBUG) { Tracing.printTrace("BINDINGS", "Cache hit"); //$NON-NLS-1$ //$NON-NLS-2$ } setActiveBindings(commandIdsByTrigger, existingCache .getTriggersByCommandId(), existingCache.getPrefixTable()); return; } // There is no cached entry for this. if (DEBUG) { Tracing.printTrace("BINDINGS", "Cache miss"); //$NON-NLS-1$ //$NON-NLS-2$ } // Compute the active bindings. commandIdsByTrigger = new HashMap(); final Map triggersByParameterizedCommand = new HashMap(); computeBindings(activeContextTree, commandIdsByTrigger, triggersByParameterizedCommand); existingCache.setBindingsByTrigger(commandIdsByTrigger); existingCache.setTriggersByCommandId(triggersByParameterizedCommand); setActiveBindings(commandIdsByTrigger, triggersByParameterizedCommand, buildPrefixTable(commandIdsByTrigger)); existingCache.setPrefixTable(prefixTable); } /** * <p>Remove the specific binding by identity. Does nothing if the binding is * not in the manager.</p> * <p> * This method completes in <code>O(n)</code>, where <code>n</code> is * the number of bindings. * </p> * * @param binding * The binding to be removed; must not be <code>null</code>. * @since 3.2 */ public final void removeBinding(final Binding binding) { if (bindings == null || bindings.length < 1) { return; } final Binding[] newBindings = new Binding[bindings.length]; boolean bindingsChanged = false; int index = 0; for (int i = 0; i < bindingCount; i++) { final Binding b = bindings[i]; if (b == binding) { bindingsChanged = true; } else { newBindings[index++] = b; } } if (bindingsChanged) { this.bindings = newBindings; bindingCount = index; clearCache(); } } /** * <p> * Removes a listener from this binding manager. * </p> * <p> * This method completes in amortized <code>O(1)</code>. * </p> * * @param listener * The listener to be removed; must not be <code>null</code>. */ public final void removeBindingManagerListener( final IBindingManagerListener listener) { removeListenerObject(listener); } /** * <p> * Removes any binding that matches the given values -- regardless of * command identifier. * </p> * <p> * This method completes in <code>O(n)</code>, where <code>n</code> is * the number of bindings. * </p> * * @param sequence * The sequence to match; may be <code>null</code>. * @param schemeId * The scheme id to match; may be <code>null</code>. * @param contextId * The context id to match; may be <code>null</code>. * @param locale * The locale to match; may be <code>null</code>. * @param platform * The platform to match; may be <code>null</code>. * @param windowManager * The window manager to match; may be <code>null</code>. TODO * Currently ignored. * @param type * The type to look for. * */ public final void removeBindings(final TriggerSequence sequence, final String schemeId, final String contextId, final String locale, final String platform, final String windowManager, final int type) { if ((bindings == null) || (bindingCount < 1)) { return; } final Binding[] newBindings = new Binding[bindings.length]; boolean bindingsChanged = false; int index = 0; for (int i = 0; i < bindingCount; i++) { final Binding binding = bindings[i]; boolean equals = true; equals &= Util.equals(sequence, binding.getTriggerSequence()); equals &= Util.equals(schemeId, binding.getSchemeId()); equals &= Util.equals(contextId, binding.getContextId()); equals &= Util.equals(locale, binding.getLocale()); equals &= Util.equals(platform, binding.getPlatform()); equals &= (type == binding.getType()); if (equals) { bindingsChanged = true; } else { newBindings[index++] = binding; } } if (bindingsChanged) { this.bindings = newBindings; bindingCount = index; clearCache(); } } /** * <p> * Attempts to remove deletion markers from the collection of bindings. * </p> * <p> * This method completes in <code>O(n)</code>, where <code>n</code> is * the number of bindings. * </p> * * @param bindings * The bindings from which the deleted items should be removed. * This array should not be <code>null</code>, but may be * empty. * @return The array of bindings with the deletions removed; never * <code>null</code>, but may be empty. Contains only instances * of <code>Binding</code>. */ private final Binding[] removeDeletions(final Binding[] bindings) { final Map deletions = new HashMap(); final Binding[] bindingsCopy = new Binding[bindingCount]; System.arraycopy(bindings, 0, bindingsCopy, 0, bindingCount); int deletedCount = 0; // Extract the deletions. for (int i = 0; i < bindingCount; i++) { final Binding binding = bindingsCopy[i]; if ((binding.getParameterizedCommand() == null) && (localeMatches(binding)) && (platformMatches(binding))) { final TriggerSequence sequence = binding.getTriggerSequence(); final Object currentValue = deletions.get(sequence); if (currentValue instanceof Binding) { final Collection collection = new ArrayList(2); collection.add(currentValue); collection.add(binding); deletions.put(sequence, collection); } else if (currentValue instanceof Collection) { final Collection collection = (Collection) currentValue; collection.add(binding); } else { deletions.put(sequence, binding); } bindingsCopy[i] = null; deletedCount++; } } if (DEBUG) { Tracing.printTrace("BINDINGS", "There are " + deletions.size() //$NON-NLS-1$ //$NON-NLS-2$ + " deletion markers"); //$NON-NLS-1$ } // Remove the deleted items. for (int i = 0; i < bindingCount; i++) { final Binding binding = bindingsCopy[i]; if (binding != null) { final Object deletion = deletions.get(binding .getTriggerSequence()); if (deletion instanceof Binding) { if (((Binding) deletion).deletes(binding)) { bindingsCopy[i] = null; deletedCount++; } } else if (deletion instanceof Collection) { final Collection collection = (Collection) deletion; final Iterator iterator = collection.iterator(); while (iterator.hasNext()) { final Object deletionBinding = iterator.next(); if (deletionBinding instanceof Binding) { if (((Binding) deletionBinding).deletes(binding)) { bindingsCopy[i] = null; deletedCount++; break; } } } } } } // Compact the array. final Binding[] returnValue = new Binding[bindingCount - deletedCount]; int index = 0; for (int i = 0; i < bindingCount; i++) { final Binding binding = bindingsCopy[i]; if (binding != null) { returnValue[index++] = binding; } } return returnValue; } /** * <p> * Attempts to resolve the conflicts for the given bindings -- irrespective * of the currently active contexts. This means that type and scheme will be * considered. * </p> * <p> * This method completes in <code>O(n)</code>, where <code>n</code> is * the number of bindings. * </p> * * @param bindings * The bindings which all match the same trigger sequence; must * not be <code>null</code>, and should contain at least two * items. This collection should only contain instances of * <code>Binding</code> (i.e., no <code>null</code> values). * @return The collection of bindings which match the current scheme. */ private final Collection resolveConflicts(final Collection bindings) { final Collection matches = new ArrayList(); final Iterator bindingItr = bindings.iterator(); Binding bestMatch = (Binding) bindingItr.next(); matches.add(bestMatch); /* * Iterate over each binding and compares it with the best match. If a * better match is found, then replace the best match and clear the * collection. If the current binding is equivalent, then simply add it * to the collection of matches. If the current binding is worse, then * do nothing. */ while (bindingItr.hasNext()) { final Binding current = (Binding) bindingItr.next(); /* * SCHEME: Test whether the current is in a child scheme. Bindings * defined in a child scheme will take priority over bindings * defined in a parent scheme -- assuming that consulting their * contexts led to a conflict. */ final String currentSchemeId = current.getSchemeId(); final String bestSchemeId = bestMatch.getSchemeId(); final int compareTo = compareSchemes(bestSchemeId, currentSchemeId); if (compareTo > 0) { bestMatch = current; matches.clear(); matches.add(current); } if (compareTo != 0) { continue; } /* * TYPE: Test for type superiority. */ if (current.getType() > bestMatch.getType()) { bestMatch = current; matches.clear(); matches.add(current); continue; } else if (bestMatch.getType() > current.getType()) { continue; } // The bindings are equivalent. matches.add(current); } // Return all of the matches. return matches; } /** * <p> * Attempts to resolve the conflicts for the g
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -