Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 185523 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/jface/bindings/CachedBindingSet.java (+14 lines)
Lines 61-66 Link Here
61
	 * This value may be <code>null</code> if it has not yet been initialized.
61
	 * This value may be <code>null</code> if it has not yet been initialized.
62
	 */
62
	 */
63
	private Map bindingsByTrigger = null;
63
	private Map bindingsByTrigger = null;
64
	
65
	private Map conflictsByTrigger = null;
64
66
65
	/**
67
	/**
66
	 * The hash code for this object. This value is computed lazily, and marked
68
	 * The hash code for this object. This value is computed lazily, and marked
Lines 229-234 Link Here
229
	final Map getBindingsByTrigger() {
231
	final Map getBindingsByTrigger() {
230
		return bindingsByTrigger;
232
		return bindingsByTrigger;
231
	}
233
	}
234
	
235
	final Map getConflictsByTrigger() {
236
		return conflictsByTrigger;
237
	}
232
238
233
	/**
239
	/**
234
	 * Returns the map of prefixes to a map of trigger sequence to command
240
	 * Returns the map of prefixes to a map of trigger sequence to command
Lines 294-299 Link Here
294
300
295
		this.bindingsByTrigger = commandIdsByTrigger;
301
		this.bindingsByTrigger = commandIdsByTrigger;
296
	}
302
	}
303
	
304
	final void setConflictsByTrigger(final Map c) {
305
		if (c == null) {
306
			throw new NullPointerException(
307
					"Cannot set a null binding conflicts"); //$NON-NLS-1$
308
		}
309
		conflictsByTrigger = c;
310
	}
297
311
298
	/**
312
	/**
299
	 * Sets the map of prefixes to a map of trigger sequence to command
313
	 * Sets the map of prefixes to a map of trigger sequence to command
(-)src/org/eclipse/jface/bindings/BindingManager.java (-11 / +24 lines)
Lines 42-47 Link Here
42
import org.eclipse.jface.bindings.keys.KeyLookupFactory;
42
import org.eclipse.jface.bindings.keys.KeyLookupFactory;
43
import org.eclipse.jface.bindings.keys.KeyStroke;
43
import org.eclipse.jface.bindings.keys.KeyStroke;
44
import org.eclipse.jface.contexts.IContextIds;
44
import org.eclipse.jface.contexts.IContextIds;
45
import org.eclipse.jface.internal.InternalPolicy;
45
import org.eclipse.jface.util.Policy;
46
import org.eclipse.jface.util.Policy;
46
import org.eclipse.jface.util.Util;
47
import org.eclipse.jface.util.Util;
47
import org.eclipse.swt.SWT;
48
import org.eclipse.swt.SWT;
Lines 181-186 Link Here
181
	 * Otherwise, this value may be empty.
182
	 * Otherwise, this value may be empty.
182
	 */
183
	 */
183
	private Map activeBindingsByParameterizedCommand = null;
184
	private Map activeBindingsByParameterizedCommand = null;
185
	
186
	private Set triggerConflicts = new HashSet();
184
187
185
	/**
188
	/**
186
	 * The scheme that is currently active. An active scheme is the one that is
189
	 * The scheme that is currently active. An active scheme is the one that is
Lines 272-279 Link Here
272
	 */
275
	 */
273
	private Map prefixTable = null;
276
	private Map prefixTable = null;
274
277
275
	private Set triggerConflicts = new HashSet();
276
277
	/**
278
	/**
278
	 * <p>
279
	 * <p>
279
	 * Constructs a new instance of <code>BindingManager</code>.
280
	 * Constructs a new instance of <code>BindingManager</code>.
Lines 438-444 Link Here
438
	 * This method completes in <code>O(1)</code>.
439
	 * This method completes in <code>O(1)</code>.
439
	 */
440
	 */
440
	private final void clearSolution() {
441
	private final void clearSolution() {
441
		setActiveBindings(null, null, null);
442
		setActiveBindings(null, null, null, null);
442
	}
443
	}
443
444
444
	/**
445
	/**
Lines 511-517 Link Here
511
	 *            computed).
512
	 *            computed).
512
	 */
513
	 */
513
	private final void computeBindings(final Map activeContextTree,
514
	private final void computeBindings(final Map activeContextTree,
514
			final Map bindingsByTrigger, final Map triggersByCommandId) {
515
			final Map bindingsByTrigger, final Map triggersByCommandId, 
516
			final Map conflictsByTrigger) {
515
		/*
517
		/*
516
		 * FIRST PASS: Remove all of the bindings that are marking deletions.
518
		 * FIRST PASS: Remove all of the bindings that are marking deletions.
517
		 */
519
		 */
Lines 632-637 Link Here
632
							activeContextTree);
634
							activeContextTree);
633
					if (winner == null) {
635
					if (winner == null) {
634
						// warn once ... so as not to flood the logs
636
						// warn once ... so as not to flood the logs
637
						conflictsByTrigger.put(trigger, match);
635
						if (triggerConflicts.add(trigger)) {
638
						if (triggerConflicts.add(trigger)) {
636
							final StringWriter sw = new StringWriter();
639
							final StringWriter sw = new StringWriter();
637
							final BufferedWriter buffer = new BufferedWriter(sw);
640
							final BufferedWriter buffer = new BufferedWriter(sw);
Lines 997-1006 Link Here
997
		// Compute the active bindings.
1000
		// Compute the active bindings.
998
		commandIdsByTrigger = new HashMap();
1001
		commandIdsByTrigger = new HashMap();
999
		final Map triggersByParameterizedCommand = new HashMap();
1002
		final Map triggersByParameterizedCommand = new HashMap();
1003
		final Map conflictsByTrigger = new HashMap();
1000
		computeBindings(null, commandIdsByTrigger,
1004
		computeBindings(null, commandIdsByTrigger,
1001
				triggersByParameterizedCommand);
1005
				triggersByParameterizedCommand, conflictsByTrigger);
1002
		existingCache.setBindingsByTrigger(commandIdsByTrigger);
1006
		existingCache.setBindingsByTrigger(commandIdsByTrigger);
1003
		existingCache.setTriggersByCommandId(triggersByParameterizedCommand);
1007
		existingCache.setTriggersByCommandId(triggersByParameterizedCommand);
1008
		existingCache.setConflictsByTrigger(conflictsByTrigger);
1004
		return Collections.unmodifiableMap(commandIdsByTrigger);
1009
		return Collections.unmodifiableMap(commandIdsByTrigger);
1005
	}
1010
	}
1006
1011
Lines 1057-1067 Link Here
1057
1062
1058
		// Compute the active bindings.
1063
		// Compute the active bindings.
1059
		final Map commandIdsByTrigger = new HashMap();
1064
		final Map commandIdsByTrigger = new HashMap();
1065
		final Map conflictsByTrigger = new HashMap();
1060
		triggersByParameterizedCommand = new HashMap();
1066
		triggersByParameterizedCommand = new HashMap();
1061
		computeBindings(null, commandIdsByTrigger,
1067
		computeBindings(null, commandIdsByTrigger,
1062
				triggersByParameterizedCommand);
1068
				triggersByParameterizedCommand, conflictsByTrigger);
1063
		existingCache.setBindingsByTrigger(commandIdsByTrigger);
1069
		existingCache.setBindingsByTrigger(commandIdsByTrigger);
1064
		existingCache.setTriggersByCommandId(triggersByParameterizedCommand);
1070
		existingCache.setTriggersByCommandId(triggersByParameterizedCommand);
1071
		existingCache.setConflictsByTrigger(conflictsByTrigger);
1065
1072
1066
		return Collections.unmodifiableMap(triggersByParameterizedCommand);
1073
		return Collections.unmodifiableMap(triggersByParameterizedCommand);
1067
	}
1074
	}
Lines 1703-1709 Link Here
1703
		if (bindings == null) {
1710
		if (bindings == null) {
1704
			// Not yet initialized. This is happening too early. Do nothing.
1711
			// Not yet initialized. This is happening too early. Do nothing.
1705
			setActiveBindings(Collections.EMPTY_MAP, Collections.EMPTY_MAP,
1712
			setActiveBindings(Collections.EMPTY_MAP, Collections.EMPTY_MAP,
1706
					Collections.EMPTY_MAP);
1713
					Collections.EMPTY_MAP, Collections.EMPTY_MAP);
1707
			return;
1714
			return;
1708
		}
1715
		}
1709
1716
Lines 1732-1738 Link Here
1732
				Tracing.printTrace("BINDINGS", "Cache hit"); //$NON-NLS-1$ //$NON-NLS-2$
1739
				Tracing.printTrace("BINDINGS", "Cache hit"); //$NON-NLS-1$ //$NON-NLS-2$
1733
			}
1740
			}
1734
			setActiveBindings(commandIdsByTrigger, existingCache
1741
			setActiveBindings(commandIdsByTrigger, existingCache
1735
					.getTriggersByCommandId(), existingCache.getPrefixTable());
1742
					.getTriggersByCommandId(), existingCache.getPrefixTable(),
1743
					existingCache.getConflictsByTrigger());
1736
			return;
1744
			return;
1737
		}
1745
		}
1738
1746
Lines 1744-1755 Link Here
1744
		// Compute the active bindings.
1752
		// Compute the active bindings.
1745
		commandIdsByTrigger = new HashMap();
1753
		commandIdsByTrigger = new HashMap();
1746
		final Map triggersByParameterizedCommand = new HashMap();
1754
		final Map triggersByParameterizedCommand = new HashMap();
1755
		final Map conflictsByTrigger = new HashMap();
1747
		computeBindings(activeContextTree, commandIdsByTrigger,
1756
		computeBindings(activeContextTree, commandIdsByTrigger,
1748
				triggersByParameterizedCommand);
1757
				triggersByParameterizedCommand, conflictsByTrigger);
1749
		existingCache.setBindingsByTrigger(commandIdsByTrigger);
1758
		existingCache.setBindingsByTrigger(commandIdsByTrigger);
1750
		existingCache.setTriggersByCommandId(triggersByParameterizedCommand);
1759
		existingCache.setTriggersByCommandId(triggersByParameterizedCommand);
1760
		existingCache.setConflictsByTrigger(conflictsByTrigger);
1751
		setActiveBindings(commandIdsByTrigger, triggersByParameterizedCommand,
1761
		setActiveBindings(commandIdsByTrigger, triggersByParameterizedCommand,
1752
				buildPrefixTable(commandIdsByTrigger));
1762
				buildPrefixTable(commandIdsByTrigger),
1763
				conflictsByTrigger);
1753
		existingCache.setPrefixTable(prefixTable);
1764
		existingCache.setPrefixTable(prefixTable);
1754
	}
1765
	}
1755
1766
Lines 2153-2163 Link Here
2153
	 *            solution.
2164
	 *            solution.
2154
	 */
2165
	 */
2155
	private final void setActiveBindings(final Map activeBindings,
2166
	private final void setActiveBindings(final Map activeBindings,
2156
			final Map activeBindingsByCommandId, final Map prefixTable) {
2167
			final Map activeBindingsByCommandId, final Map prefixTable,
2168
			final Map conflicts) {
2157
		this.activeBindings = activeBindings;
2169
		this.activeBindings = activeBindings;
2158
		final Map previousBindingsByParameterizedCommand = this.activeBindingsByParameterizedCommand;
2170
		final Map previousBindingsByParameterizedCommand = this.activeBindingsByParameterizedCommand;
2159
		this.activeBindingsByParameterizedCommand = activeBindingsByCommandId;
2171
		this.activeBindingsByParameterizedCommand = activeBindingsByCommandId;
2160
		this.prefixTable = prefixTable;
2172
		this.prefixTable = prefixTable;
2173
		InternalPolicy.currentConflicts = conflicts;
2161
2174
2162
		fireBindingManagerChanged(new BindingManagerEvent(this, true,
2175
		fireBindingManagerChanged(new BindingManagerEvent(this, true,
2163
				previousBindingsByParameterizedCommand, false, null, false,
2176
				previousBindingsByParameterizedCommand, false, null, false,
(-)src/org/eclipse/jface/internal/InternalPolicy.java (+8 lines)
Lines 10-15 Link Here
10
 ******************************************************************************/
10
 ******************************************************************************/
11
package org.eclipse.jface.internal;
11
package org.eclipse.jface.internal;
12
12
13
import java.util.HashMap;
14
import java.util.Map;
15
13
/**
16
/**
14
 * Internal class used for non-API debug flags.
17
 * Internal class used for non-API debug flags.
15
 * 
18
 * 
Lines 25-28 Link Here
25
	 */
28
	 */
26
	public static boolean DEBUG_LOG_REENTRANT_VIEWER_CALLS = false;
29
	public static boolean DEBUG_LOG_REENTRANT_VIEWER_CALLS = false;
27
30
31
	/**
32
	 * (NON-API) Instead of logging current conflicts they can be
33
	 * held here.  If there is a problem, they can be reported then.
34
	 */
35
	public static Map currentConflicts = new HashMap();
28
}
36
}
(-)Eclipse UI/org/eclipse/ui/internal/keys/WorkbenchKeyboard.java (-7 / +38 lines)
Lines 11-16 Link Here
11
package org.eclipse.ui.internal.keys;
11
package org.eclipse.ui.internal.keys;
12
12
13
import java.util.ArrayList;
13
import java.util.ArrayList;
14
import java.util.Collection;
14
import java.util.Iterator;
15
import java.util.Iterator;
15
import java.util.List;
16
import java.util.List;
16
import java.util.ResourceBundle;
17
import java.util.ResourceBundle;
Lines 29-34 Link Here
29
import org.eclipse.jface.bindings.keys.KeyStroke;
30
import org.eclipse.jface.bindings.keys.KeyStroke;
30
import org.eclipse.jface.bindings.keys.ParseException;
31
import org.eclipse.jface.bindings.keys.ParseException;
31
import org.eclipse.jface.bindings.keys.SWTKeySupport;
32
import org.eclipse.jface.bindings.keys.SWTKeySupport;
33
import org.eclipse.jface.internal.InternalPolicy;
32
import org.eclipse.swt.SWT;
34
import org.eclipse.swt.SWT;
33
import org.eclipse.swt.custom.StyledText;
35
import org.eclipse.swt.custom.StyledText;
34
import org.eclipse.swt.widgets.Combo;
36
import org.eclipse.swt.widgets.Combo;
Lines 463-469 Link Here
463
		}
465
		}
464
466
465
		try {
467
		try {
466
			final IHandlerService handlerService = (IHandlerService) workbench.getService(IHandlerService.class);
468
			final IHandlerService handlerService = (IHandlerService) workbench
469
					.getService(IHandlerService.class);
467
			handlerService.executeCommand(parameterizedCommand, trigger);
470
			handlerService.executeCommand(parameterizedCommand, trigger);
468
		} catch (final NotDefinedException e) {
471
		} catch (final NotDefinedException e) {
469
			// The command is not defined. Forwarded to the IExecutionListener.
472
			// The command is not defined. Forwarded to the IExecutionListener.
Lines 590-600 Link Here
590
	 */
593
	 */
591
	private Binding getPerfectMatch(KeySequence keySequence) {
594
	private Binding getPerfectMatch(KeySequence keySequence) {
592
		if (bindingService == null) {
595
		if (bindingService == null) {
593
			bindingService = (IBindingService) workbench.getService(IBindingService.class);
596
			bindingService = (IBindingService) workbench
597
					.getService(IBindingService.class);
594
		}
598
		}
595
		return bindingService.getPerfectMatch(keySequence);
599
		return bindingService.getPerfectMatch(keySequence);
596
	}
600
	}
597
	
601
598
	final KeySequence getBuffer() {
602
	final KeySequence getBuffer() {
599
		return state.getCurrentSequence();
603
		return state.getCurrentSequence();
600
	}
604
	}
Lines 643-649 Link Here
643
	 */
647
	 */
644
	private boolean isPartialMatch(KeySequence keySequence) {
648
	private boolean isPartialMatch(KeySequence keySequence) {
645
		if (bindingService == null) {
649
		if (bindingService == null) {
646
			bindingService = (IBindingService) workbench.getService(IBindingService.class);
650
			bindingService = (IBindingService) workbench
651
					.getService(IBindingService.class);
647
		}
652
		}
648
		return bindingService.isPartialMatch(keySequence);
653
		return bindingService.isPartialMatch(keySequence);
649
	}
654
	}
Lines 660-666 Link Here
660
	 */
665
	 */
661
	private boolean isPerfectMatch(KeySequence keySequence) {
666
	private boolean isPerfectMatch(KeySequence keySequence) {
662
		if (bindingService == null) {
667
		if (bindingService == null) {
663
			bindingService = (IBindingService) workbench.getService(IBindingService.class);
668
			bindingService = (IBindingService) workbench
669
					.getService(IBindingService.class);
664
		}
670
		}
665
		return bindingService.isPerfectMatch(keySequence);
671
		return bindingService.isPerfectMatch(keySequence);
666
	}
672
	}
Lines 720-725 Link Here
720
		}
726
		}
721
		keyAssistDialog.open();
727
		keyAssistDialog.open();
722
	}
728
	}
729
	
730
	public final void openKeyAssistShell(Collection bindings) {
731
		if (keyAssistDialog == null) {
732
			keyAssistDialog = new KeyAssistDialog(workbench, this, state);
733
		}
734
		if (keyAssistDialog.getShell() == null) {
735
			keyAssistDialog.setParentShell(Util.getShellToParentOn());
736
		}
737
		keyAssistDialog.open(bindings);
738
	}
723
739
724
	/**
740
	/**
725
	 * Processes a key press with respect to the key binding architecture. This
741
	 * Processes a key press with respect to the key binding architecture. This
Lines 758-764 Link Here
758
			final Widget widget = event.widget;
774
			final Widget widget = event.widget;
759
775
760
			// Update the contexts.
776
			// Update the contexts.
761
			final ContextService contextService = (ContextService) workbench.getService(IContextService.class);
777
			final ContextService contextService = (ContextService) workbench
778
					.getService(IContextService.class);
762
			if ((widget instanceof Control) && (!widget.isDisposed())) {
779
			if ((widget instanceof Control) && (!widget.isDisposed())) {
763
				final Shell shell = ((Control) widget).getShell();
780
				final Shell shell = ((Control) widget).getShell();
764
				contextService.updateShellKludge(shell);
781
				contextService.updateShellKludge(shell);
Lines 767-773 Link Here
767
			}
784
			}
768
785
769
			// Update the handlers.
786
			// Update the handlers.
770
			final HandlerService handlerService = (HandlerService) workbench.getService(IHandlerService.class);
787
			final HandlerService handlerService = (HandlerService) workbench
788
					.getService(IHandlerService.class);
771
			if ((widget instanceof Control) && (!widget.isDisposed())) {
789
			if ((widget instanceof Control) && (!widget.isDisposed())) {
772
				final Shell shell = ((Control) widget).getShell();
790
				final Shell shell = ((Control) widget).getShell();
773
				handlerService.updateShellKludge(shell);
791
				handlerService.updateShellKludge(shell);
Lines 776-781 Link Here
776
			}
794
			}
777
		}
795
		}
778
796
797
		KeySequence errorSequence = null;
798
		Collection errorMatch = null;
799
779
		KeySequence sequenceBeforeKeyStroke = state.getCurrentSequence();
800
		KeySequence sequenceBeforeKeyStroke = state.getCurrentSequence();
780
		for (Iterator iterator = potentialKeyStrokes.iterator(); iterator
801
		for (Iterator iterator = potentialKeyStrokes.iterator(); iterator
781
				.hasNext();) {
802
				.hasNext();) {
Lines 806-815 Link Here
806
				// We don't want to swallow keyboard navigation keys.
827
				// We don't want to swallow keyboard navigation keys.
807
				return false;
828
				return false;
808
829
830
			} else {
831
				Collection match = (InternalPolicy.currentConflicts==null?null:(Collection) InternalPolicy.currentConflicts
832
						.get(sequenceAfterKeyStroke));
833
				if (match != null) {
834
					errorSequence = sequenceAfterKeyStroke;
835
					errorMatch = match;
836
				}
809
			}
837
			}
810
		}
838
		}
811
839
812
		resetState(true);
840
		resetState(true);
841
		if (sequenceBeforeKeyStroke.isEmpty() && errorSequence != null) {
842
			openKeyAssistShell(errorMatch);
843
		}
813
		return !sequenceBeforeKeyStroke.isEmpty();
844
		return !sequenceBeforeKeyStroke.isEmpty();
814
	}
845
	}
815
846
(-)Eclipse UI/org/eclipse/ui/internal/keys/KeyAssistDialog.java (-2 / +51 lines)
Lines 11-18 Link Here
11
11
12
package org.eclipse.ui.internal.keys;
12
package org.eclipse.ui.internal.keys;
13
13
14
import com.ibm.icu.text.MessageFormat;
15
import java.util.ArrayList;
14
import java.util.ArrayList;
15
import java.util.Collection;
16
import java.util.Comparator;
16
import java.util.Comparator;
17
import java.util.Iterator;
17
import java.util.Iterator;
18
import java.util.List;
18
import java.util.List;
Lines 55-60 Link Here
55
import org.eclipse.ui.internal.util.Util;
55
import org.eclipse.ui.internal.util.Util;
56
import org.eclipse.ui.keys.IBindingService;
56
import org.eclipse.ui.keys.IBindingService;
57
57
58
import com.ibm.icu.text.MessageFormat;
59
58
/**
60
/**
59
 * <p>
61
 * <p>
60
 * A dialog displaying a list of key bindings. The dialog will execute a command
62
 * A dialog displaying a list of key bindings. The dialog will execute a command
Lines 142-147 Link Here
142
	 */
144
	 */
143
	private final WorkbenchKeyboard workbenchKeyboard;
145
	private final WorkbenchKeyboard workbenchKeyboard;
144
146
147
	private SortedMap conflictMatches;
148
145
	/**
149
	/**
146
	 * Constructs a new instance of <code>KeyAssistDialog</code>. When the
150
	 * Constructs a new instance of <code>KeyAssistDialog</code>. When the
147
	 * dialog is first constructed, it contains no widgets. The dialog is first
151
	 * dialog is first constructed, it contains no widgets. The dialog is first
Lines 419-425 Link Here
419
		composite.setBackground(parent.getBackground());
423
		composite.setBackground(parent.getBackground());
420
424
421
		// Layout the partial matches.
425
		// Layout the partial matches.
422
		final SortedMap partialMatches = getPartialMatches();
426
		final SortedMap partialMatches;
427
		if (conflictMatches!=null) {
428
			partialMatches = conflictMatches;
429
			conflictMatches=null;
430
		} else {
431
			partialMatches = getPartialMatches();
432
		}
433
		
423
		if (partialMatches.isEmpty()) {
434
		if (partialMatches.isEmpty()) {
424
			createEmptyDialogArea(composite);
435
			createEmptyDialogArea(composite);
425
		} else {
436
		} else {
Lines 640-645 Link Here
640
		// Call the super method.
651
		// Call the super method.
641
		return super.open();
652
		return super.open();
642
	}
653
	}
654
	
655
	public final int open(Collection bindings) {
656
		conflictMatches  = new TreeMap(new Comparator() {
657
			public final int compare(final Object a, final Object b) {
658
				final Binding bindingA = (Binding) a;
659
				final Binding bindingB = (Binding) b;
660
				final ParameterizedCommand commandA = bindingA
661
						.getParameterizedCommand();
662
				final ParameterizedCommand commandB = bindingB
663
						.getParameterizedCommand();
664
				try {
665
					return commandA.getName().compareTo(commandB.getName());
666
				} catch (final NotDefinedException e) {
667
					// should not happen
668
					return 0;
669
				}
670
			}
671
		});
672
		Iterator i = bindings.iterator();
673
		while (i.hasNext()) {
674
			Binding b = (Binding) i.next();
675
			conflictMatches.put(b, b.getTriggerSequence());
676
		}
677
		
678
		// If the dialog is already open, dispose the shell and recreate it.
679
		final Shell shell = getShell();
680
		if (shell != null) {
681
			close(false, false);
682
		}
683
		create();
684
685
		// Configure the size and location.
686
		final Point size = configureSize();
687
		configureLocation(size);
688
689
		// Call the super method.
690
		return super.open();
691
	}
643
692
644
	/**
693
	/**
645
	 * Registers the shell as the same type as its parent with the context
694
	 * Registers the shell as the same type as its parent with the context

Return to bug 185523