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 317201 | Differences between
and this patch

Collapse All | Expand All

(-)META-INF/MANIFEST.MF (-4 / +3 lines)
Lines 13-26 Link Here
13
 org.eclipse.e4.core.commands.internal,
13
 org.eclipse.e4.core.commands.internal,
14
 org.eclipse.e4.core.services.log,
14
 org.eclipse.e4.core.services.log,
15
 org.eclipse.e4.core.services.util,
15
 org.eclipse.e4.core.services.util,
16
 org.eclipse.jface.bindings,
17
 org.eclipse.jface.bindings.keys,
18
 org.eclipse.jface.bindings.keys.formatting,
19
 org.osgi.framework;version="1.5.0"
16
 org.osgi.framework;version="1.5.0"
20
Require-Bundle: org.eclipse.swt;bundle-version="3.6.0",
17
Require-Bundle: org.eclipse.swt;bundle-version="3.6.0",
21
 org.eclipse.core.commands;bundle-version="3.5.0",
18
 org.eclipse.core.commands;bundle-version="3.5.0",
22
 org.eclipse.e4.core.contexts,
19
 org.eclipse.e4.core.contexts,
23
 org.eclipse.e4.core.di
20
 org.eclipse.e4.core.di,
21
 org.eclipse.jface;bundle-version="3.6.0",
22
 org.eclipse.osgi;bundle-version="3.6.0"
24
Export-Package: org.eclipse.e4.ui.bindings;
23
Export-Package: org.eclipse.e4.ui.bindings;
25
  x-friends:="org.eclipse.e4.ui.workbench,
24
  x-friends:="org.eclipse.e4.ui.workbench,
26
   org.eclipse.e4.ui.workbench.renderers.swt,
25
   org.eclipse.e4.ui.workbench.renderers.swt,
(-)src/org/eclipse/e4/ui/bindings/internal/KeyAssistDialog.java (+664 lines)
Added Link Here
1
package org.eclipse.e4.ui.bindings.internal;
2
3
import java.util.ArrayList;
4
import java.util.Collection;
5
import java.util.Collections;
6
import java.util.Comparator;
7
import java.util.Iterator;
8
import java.util.List;
9
import java.util.Map;
10
import java.util.SortedMap;
11
import java.util.TreeMap;
12
import org.eclipse.core.commands.Command;
13
import org.eclipse.core.commands.ParameterizedCommand;
14
import org.eclipse.core.commands.common.CommandException;
15
import org.eclipse.core.commands.common.NotDefinedException;
16
import org.eclipse.e4.core.commands.ECommandService;
17
import org.eclipse.e4.core.contexts.IEclipseContext;
18
import org.eclipse.e4.ui.bindings.EBindingService;
19
import org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher;
20
import org.eclipse.jface.bindings.Binding;
21
import org.eclipse.jface.bindings.TriggerSequence;
22
import org.eclipse.jface.bindings.keys.KeySequence;
23
import org.eclipse.jface.bindings.keys.KeyStroke;
24
import org.eclipse.jface.dialogs.Dialog;
25
import org.eclipse.jface.dialogs.PopupDialog;
26
import org.eclipse.jface.window.Window;
27
import org.eclipse.osgi.util.NLS;
28
import org.eclipse.swt.SWT;
29
import org.eclipse.swt.graphics.Point;
30
import org.eclipse.swt.graphics.Rectangle;
31
import org.eclipse.swt.layout.GridData;
32
import org.eclipse.swt.layout.GridLayout;
33
import org.eclipse.swt.widgets.Composite;
34
import org.eclipse.swt.widgets.Control;
35
import org.eclipse.swt.widgets.Event;
36
import org.eclipse.swt.widgets.Label;
37
import org.eclipse.swt.widgets.Listener;
38
import org.eclipse.swt.widgets.Shell;
39
import org.eclipse.swt.widgets.Table;
40
import org.eclipse.swt.widgets.TableColumn;
41
import org.eclipse.swt.widgets.TableItem;
42
43
/**
44
 * <p>
45
 * A dialog displaying a list of key bindings. The dialog will execute a command if it is selected.
46
 * </p>
47
 * <p>
48
 * The methods on this class are not thread-safe and must be run from the UI thread.
49
 * </p>
50
 * 
51
 * @since 3.1
52
 */
53
final class KeyAssistDialog extends PopupDialog {
54
55
	public static final String WINDOW_SHOW_KEY_ASSIST = "org.eclipse.ui.window.showKeyAssist"; //$NON-NLS-1$
56
57
	/**
58
	 * The data key for the binding stored on an SWT widget. The key is a fully-qualified name, but
59
	 * in reverse order. This is so that the equals method will detect misses faster.
60
	 */
61
	private static final String BINDING_KEY = "Binding.bindings.jface.eclipse.org"; //$NON-NLS-1$
62
63
	/**
64
	 * The value of <code>previousWidth</code> to set if there is no remembered width.
65
	 */
66
	private static final int NO_REMEMBERED_WIDTH = -1;
67
68
	/**
69
	 * The binding service for the associated workbench.
70
	 */
71
	private final EBindingService bindingService;
72
73
	/**
74
	 * The binding that was selected when the key assist dialog last closed. This is only remembered
75
	 * until <code>clearRememberedState()</code> is called.
76
	 */
77
	private Binding binding = null;
78
79
	/**
80
	 * The ordered list of command identifiers corresponding to the table.
81
	 */
82
	private final List bindings = new ArrayList();
83
84
	/**
85
	 * The command service for the associated workbench.
86
	 */
87
	private final ECommandService commandService;
88
89
	/**
90
	 * The table containing of the possible completions. This value is <code>null</code> until the
91
	 * dialog is created.
92
	 */
93
	private Table completionsTable = null;
94
95
	/**
96
	 * Whether this dialog is currently holding some remembered state.
97
	 */
98
	private boolean hasRememberedState = false;
99
100
	/**
101
	 * The key binding state for the associated workbench.
102
	 */
103
	private KeySequence currentSequence = null;
104
105
	/**
106
	 * The width of the shell when it was previously open. This is only remembered until
107
	 * <code>clearRememberedState()</code> is called.
108
	 */
109
	private int previousWidth = NO_REMEMBERED_WIDTH;
110
111
	/**
112
	 * The key binding listener for the associated workbench.
113
	 */
114
	private final KeyBindingDispatcher workbenchKeyboard;
115
116
	/**
117
	 * A sorted map of conflicts to be used when the dialog pops up.
118
	 * 
119
	 * @since 3.3
120
	 */
121
	private SortedMap conflictMatches;
122
123
	/**
124
	 * Constructs a new instance of <code>KeyAssistDialog</code>. When the dialog is first
125
	 * constructed, it contains no widgets. The dialog is first created with no parent. If a parent
126
	 * is required, call <code>setParentShell()</code>. Also, between uses, it might be necessary to
127
	 * call <code>setParentShell()</code> as well.
128
	 * 
129
	 * @param workbench
130
	 *            The workbench in which this dialog is created; must not be <code>null</code>.
131
	 * @param associatedKeyboard
132
	 *            The key binding listener for the workbench; must not be <code>null</code>.
133
	 * @param associatedState
134
	 *            The key binding state associated with the workbench; must not be <code>null</code>
135
	 *            .
136
	 */
137
	KeyAssistDialog(final IEclipseContext context, final KeyBindingDispatcher associatedKeyboard) {
138
		super((Shell) null, PopupDialog.INFOPOPUP_SHELLSTYLE, true, false, false, false, null, null);
139
140
		this.bindingService = context.get(EBindingService.class);
141
		this.commandService = context.get(ECommandService.class);
142
		this.workbenchKeyboard = associatedKeyboard;
143
144
		this.setInfoText(getKeySequenceString());
145
	}
146
147
	/**
148
	 * Clears out the remembered state of the key assist dialog. This includes its width, as well as
149
	 * the selected binding.
150
	 */
151
	final void clearRememberedState() {
152
		previousWidth = NO_REMEMBERED_WIDTH;
153
		binding = null;
154
		hasRememberedState = false;
155
		currentSequence = null;
156
	}
157
158
	/**
159
	 * Closes this shell, but first remembers some state of the dialog. This way it will have a
160
	 * response if asked to open the dialog again or if asked to open the keys preference page. This
161
	 * does not remember the internal state.
162
	 * 
163
	 * @return Whether the shell was already closed.
164
	 */
165
	public final boolean close() {
166
		return close(false);
167
	}
168
169
	/**
170
	 * Closes this shell, but first remembers some state of the dialog. This way it will have a
171
	 * response if asked to open the dialog again or if asked to open the keys preference page.
172
	 * 
173
	 * @param rememberState
174
	 *            Whether the internal state should be remembered.
175
	 * @return Whether the shell was already closed.
176
	 */
177
	public final boolean close(final boolean rememberState) {
178
		return close(rememberState, true);
179
	}
180
181
	/**
182
	 * Closes this shell, but first remembers some state of the dialog. This way it will have a
183
	 * response if asked to open the dialog again or if asked to open the keys preference page.
184
	 * 
185
	 * @param rememberState
186
	 *            Whether the internal state should be remembered.
187
	 * @param resetState
188
	 *            Whether the state should be reset.
189
	 * @return Whether the shell was already closed.
190
	 */
191
	private final boolean close(final boolean rememberState, final boolean resetState) {
192
		final Shell shell = getShell();
193
		if (rememberState) {
194
			// Remember the previous width.
195
			final int widthToRemember;
196
			if ((shell != null) && (!shell.isDisposed())) {
197
				widthToRemember = getShell().getSize().x;
198
			} else {
199
				widthToRemember = NO_REMEMBERED_WIDTH;
200
			}
201
202
			// Remember the selected command name and key sequence.
203
			final Binding bindingToRemember;
204
			if ((completionsTable != null) && (!completionsTable.isDisposed())) {
205
				final int selectedIndex = completionsTable.getSelectionIndex();
206
				if (selectedIndex != -1) {
207
					final TableItem selectedItem = completionsTable.getItem(selectedIndex);
208
					bindingToRemember = (Binding) selectedItem.getData(BINDING_KEY);
209
				} else {
210
					bindingToRemember = null;
211
				}
212
			} else {
213
				bindingToRemember = null;
214
			}
215
216
			rememberState(widthToRemember, bindingToRemember);
217
			completionsTable = null;
218
		}
219
220
		if (resetState) {
221
			currentSequence = null;
222
		}
223
		return super.close();
224
	}
225
226
	/**
227
	 * Sets the position for the dialog based on the position of the workbench window. The dialog is
228
	 * flush with the bottom right corner of the workbench window. However, the dialog will not
229
	 * appear outside of the display's client area.
230
	 * 
231
	 * @param size
232
	 *            The final size of the dialog; must not be <code>null</code>.
233
	 */
234
	private final void configureLocation(final Point size) {
235
		final Shell shell = getShell();
236
237
		final Shell workbenchWindowShell = (Shell) shell.getParent();
238
		final int xCoord;
239
		final int yCoord;
240
		if (workbenchWindowShell != null) {
241
			/*
242
			 * Position the shell at the bottom right corner of the workbench window
243
			 */
244
			final Rectangle workbenchWindowBounds = workbenchWindowShell.getBounds();
245
			xCoord = workbenchWindowBounds.x + workbenchWindowBounds.width - size.x - 10;
246
			yCoord = workbenchWindowBounds.y + workbenchWindowBounds.height - size.y - 10;
247
248
		} else {
249
			xCoord = 0;
250
			yCoord = 0;
251
252
		}
253
		final Rectangle bounds = new Rectangle(xCoord, yCoord, size.x, size.y);
254
		shell.setBounds(getConstrainedShellBounds(bounds));
255
	}
256
257
	/**
258
	 * Sets the size for the dialog based on its previous size. The width of the dialog is its
259
	 * previous width, if it exists. Otherwise, it is simply the packed width of the dialog. The
260
	 * maximum width is 40% of the workbench window's width. The dialog's height is the packed
261
	 * height of the dialog to a maximum of half the height of the workbench window.
262
	 * 
263
	 * @return The size of the dialog
264
	 */
265
	private final Point configureSize() {
266
		final Shell shell = getShell();
267
268
		// Get the packed size of the shell.
269
		shell.pack();
270
		final Point size = shell.getSize();
271
272
		// Use the previous width if appropriate.
273
		if ((previousWidth != NO_REMEMBERED_WIDTH) && (previousWidth > size.x)) {
274
			size.x = previousWidth;
275
		}
276
277
		// Enforce maximum sizing.
278
		final Shell workbenchWindowShell = (Shell) shell.getParent();
279
		if (workbenchWindowShell != null) {
280
			final Point workbenchWindowSize = workbenchWindowShell.getSize();
281
			final int maxWidth = workbenchWindowSize.x * 2 / 5;
282
			final int maxHeight = workbenchWindowSize.y / 2;
283
			if (size.x > maxWidth) {
284
				size.x = maxWidth;
285
			}
286
			if (size.y > maxHeight) {
287
				size.y = maxHeight;
288
			}
289
		}
290
291
		// Set the size for the shell.
292
		shell.setSize(size);
293
		return size;
294
	}
295
296
	/**
297
	 * Returns a string representing the key sequence used to open this dialog.
298
	 * 
299
	 * @return the string describing the key sequence, or <code>null</code> if it cannot be
300
	 *         determined.
301
	 */
302
	private String getKeySequenceString() {
303
		final Command command = commandService.getCommand(WINDOW_SHOW_KEY_ASSIST);
304
		final TriggerSequence[] keyBindings = bindingService.getSequencesFor(
305
				new ParameterizedCommand(command, null)).toArray(new TriggerSequence[0]);
306
		final int keyBindingsCount = keyBindings.length;
307
		if (currentSequence == null) {
308
			return null;
309
		}
310
		final KeySequence currentState = currentSequence;
311
		final int prefixSize = currentState.getKeyStrokes().length;
312
313
		// Try to find the first possible matching key binding.
314
		KeySequence keySequence = null;
315
		for (int i = 0; i < keyBindingsCount; i++) {
316
			keySequence = (KeySequence) keyBindings[i];
317
318
			// Now just double-check to make sure the key is still possible.
319
			if (prefixSize > 0) {
320
				if (keySequence.startsWith(currentState, false)) {
321
					/*
322
					 * Okay, so we have a partial match. Replace the key binding with the required
323
					 * suffix completion.
324
					 */
325
					final KeyStroke[] oldKeyStrokes = keySequence.getKeyStrokes();
326
					final int newSize = oldKeyStrokes.length - prefixSize;
327
					final KeyStroke[] newKeyStrokes = new KeyStroke[newSize];
328
					System.arraycopy(oldKeyStrokes, prefixSize, newKeyStrokes, 0, newSize);
329
					keySequence = KeySequence.getInstance(newKeyStrokes);
330
					break;
331
				}
332
333
				/*
334
				 * The prefix doesn't match, so null out the key binding and try again.
335
				 */
336
				keySequence = null;
337
				continue;
338
339
			}
340
341
			// There is no prefix, so just grab the first.
342
			break;
343
		}
344
		if (keySequence == null) {
345
			return null; // couldn't find a suitable key binding
346
		}
347
348
		return NLS.bind(KeyAssistMessages.openPreferencePage, keySequence.format());
349
	}
350
351
	/**
352
	 * Creates the content area for the key assistant. This creates a table and places it inside the
353
	 * composite. The composite will contain a list of all the key bindings.
354
	 * 
355
	 * @param parent
356
	 *            The parent composite to contain the dialog area; must not be <code>null</code>.
357
	 */
358
	protected final Control createDialogArea(final Composite parent) {
359
		// First, register the shell type with the context support
360
		registerShellType();
361
362
		// Create a composite for the dialog area.
363
		final Composite composite = new Composite(parent, SWT.NONE);
364
		final GridLayout compositeLayout = new GridLayout();
365
		compositeLayout.marginHeight = 0;
366
		compositeLayout.marginWidth = 0;
367
		composite.setLayout(compositeLayout);
368
		composite.setLayoutData(new GridData(GridData.FILL_BOTH));
369
		composite.setBackground(parent.getBackground());
370
371
		// Layout the partial matches.
372
		final SortedMap partialMatches;
373
		if (conflictMatches != null) {
374
			partialMatches = conflictMatches;
375
			conflictMatches = null;
376
		} else {
377
			partialMatches = getPartialMatches();
378
		}
379
380
		if (partialMatches.isEmpty()) {
381
			createEmptyDialogArea(composite);
382
		} else {
383
			createTableDialogArea(composite, partialMatches);
384
		}
385
		return composite;
386
	}
387
388
	/**
389
	 * Creates an empty dialog area with a simple message saying there were no matches. This is used
390
	 * if no partial matches could be found. This should not really ever happen, but might be
391
	 * possible if the commands are changing while waiting for this dialog to open.
392
	 * 
393
	 * @param parent
394
	 *            The parent composite for the dialog area; must not be <code>null</code>.
395
	 */
396
	private final void createEmptyDialogArea(final Composite parent) {
397
		final Label noMatchesLabel = new Label(parent, SWT.NULL);
398
		noMatchesLabel.setText(KeyAssistMessages.NoMatches_Message);
399
		noMatchesLabel.setLayoutData(new GridData(GridData.FILL_BOTH));
400
		noMatchesLabel.setBackground(parent.getBackground());
401
	}
402
403
	/**
404
	 * Creates a dialog area with a table of the partial matches for the current key binding state.
405
	 * The table will be either the minimum width, or <code>previousWidth</code> if it is not
406
	 * <code>NO_REMEMBERED_WIDTH</code>.
407
	 * 
408
	 * @param parent
409
	 *            The parent composite for the dialog area; must not be <code>null</code>.
410
	 * @param partialMatches
411
	 *            The lexicographically sorted map of partial matches for the current state; must
412
	 *            not be <code>null</code> or empty.
413
	 */
414
	private final void createTableDialogArea(final Composite parent, final SortedMap partialMatches) {
415
		// Layout the table.
416
		completionsTable = new Table(parent, SWT.FULL_SELECTION | SWT.SINGLE);
417
		final GridData gridData = new GridData(GridData.FILL_BOTH);
418
		completionsTable.setLayoutData(gridData);
419
		completionsTable.setBackground(parent.getBackground());
420
		completionsTable.setLinesVisible(true);
421
422
		// Initialize the columns and rows.
423
		bindings.clear();
424
		final TableColumn columnCommandName = new TableColumn(completionsTable, SWT.LEFT, 0);
425
		final TableColumn columnKeySequence = new TableColumn(completionsTable, SWT.LEFT, 1);
426
		final Iterator itemsItr = partialMatches.entrySet().iterator();
427
		while (itemsItr.hasNext()) {
428
			final Map.Entry entry = (Map.Entry) itemsItr.next();
429
			final String sequence = (String) entry.getValue();
430
			final Binding binding = (Binding) entry.getKey();
431
			final ParameterizedCommand command = binding.getParameterizedCommand();
432
			try {
433
				final String[] text = { command.getName(), sequence };
434
				final TableItem item = new TableItem(completionsTable, SWT.NULL);
435
				item.setText(text);
436
				item.setData(BINDING_KEY, binding);
437
				bindings.add(binding);
438
			} catch (NotDefinedException e) {
439
				// Not much to do, but this shouldn't really happen.
440
			}
441
		}
442
443
		Dialog.applyDialogFont(parent);
444
		columnKeySequence.pack();
445
		if (previousWidth != NO_REMEMBERED_WIDTH) {
446
			columnKeySequence.setWidth(previousWidth);
447
		}
448
		columnCommandName.pack();
449
		if (completionsTable.getItems().length > 0) {
450
			completionsTable.setSelection(0);
451
		}
452
453
		/*
454
		 * If you double-click on the table, it should execute the selected command.
455
		 */
456
		completionsTable.addListener(SWT.DefaultSelection, new Listener() {
457
			public final void handleEvent(final Event event) {
458
				executeKeyBinding(event);
459
			}
460
		});
461
	}
462
463
	/**
464
	 * Edits the remembered selection in the preference dialog.
465
	 */
466
	private final void editKeyBinding() {
467
		// Create a preference dialog on the keys preference page.
468
		/*
469
		 * Forget the remembered state (so we don't get stuck editing preferences).
470
		 */
471
		clearRememberedState();
472
473
		// Open the dialog (blocking).
474
475
		// we don't support this ATM
476
	}
477
478
	/**
479
	 * Handles the default selection event on the table of possible completions. This attempts to
480
	 * execute the given command.
481
	 */
482
	private final void executeKeyBinding(final Event trigger) {
483
		// Try to execute the corresponding command.
484
		final int selectionIndex = completionsTable.getSelectionIndex();
485
		if (selectionIndex >= 0) {
486
			final Binding binding = (Binding) bindings.get(selectionIndex);
487
			try {
488
				// workbenchKeyboard.updateShellKludge(null);
489
				workbenchKeyboard.executeCommand(binding.getParameterizedCommand(), trigger);
490
			} catch (final CommandException e) {
491
				// WorkbenchPlugin.log(binding.getParameterizedCommand().toString(), e);
492
				// TODO we probably need to log something here.
493
			}
494
		}
495
	}
496
497
	/**
498
	 * Gets the list of key bindings that are partial matches to the current key binding state.
499
	 * 
500
	 * @return A sorted map of key sequences (KeySequence) to command identifier (String)
501
	 *         representing the list of enabled commands that could possibly complete the current
502
	 *         key sequence.
503
	 */
504
	private final Map getPartialMatches() {
505
		Object obj = bindingService.getPartialMatches(currentSequence);
506
		if (!(obj instanceof List)) {
507
			return Collections.EMPTY_MAP;
508
		}
509
		final List<Binding> partialMatches = (List<Binding>) obj;
510
511
		Collections.sort(partialMatches, new Comparator<Binding>() {
512
			public final int compare(final Binding bindingA, final Binding bindingB) {
513
				final ParameterizedCommand commandA = bindingA.getParameterizedCommand();
514
				final ParameterizedCommand commandB = bindingB.getParameterizedCommand();
515
				try {
516
					return commandA.getName().compareTo(commandB.getName());
517
				} catch (final NotDefinedException e) {
518
					// should not happen
519
					return 0;
520
				}
521
			}
522
		});
523
524
		/*
525
		 * Remove those partial matches for which either the command is not identified or the
526
		 * activity manager believes the command is not enabled.
527
		 */
528
		final Iterator partialMatchItr = partialMatches.entrySet().iterator();
529
		while (partialMatchItr.hasNext()) {
530
			final Map.Entry entry = (Map.Entry) partialMatchItr.next();
531
			final Binding binding = (Binding) entry.getValue();
532
			final Command command = binding.getParameterizedCommand().getCommand();
533
			if (command.isDefined() && activityManager.getIdentifier(command.getId()).isEnabled()) {
534
				TriggerSequence bestActiveBindingFor = bindingService
535
						.getBestActiveBindingFor(binding.getParameterizedCommand());
536
				sortedMatches.put(binding, bestActiveBindingFor == null ? null
537
						: bestActiveBindingFor.format());
538
			}
539
		}
540
541
		return sortedMatches;
542
543
	}
544
545
	/**
546
	 * Returns whether the dialog is currently holding some remembered state.
547
	 * 
548
	 * @return <code>true</code> if the dialog has remembered state; <code>false</code> otherwise.
549
	 */
550
	private final boolean hasRememberedState() {
551
		return hasRememberedState;
552
	}
553
554
	/**
555
	 * Opens this dialog. This method can be called multiple times on the same dialog. This only
556
	 * opens the dialog if there is no remembered state; if there is remembered state, then it tries
557
	 * to open the preference page instead.
558
	 * 
559
	 * @return The return code from this dialog.
560
	 */
561
	public final int open() {
562
		// If there is remember state, open the preference page.
563
		if (hasRememberedState()) {
564
			editKeyBinding();
565
			clearRememberedState();
566
			return Window.OK;
567
		}
568
569
		// If the dialog is already open, dispose the shell and recreate it.
570
		final Shell shell = getShell();
571
		if (shell != null) {
572
			close(false, false);
573
		}
574
		create();
575
576
		// Configure the size and location.
577
		final Point size = configureSize();
578
		configureLocation(size);
579
580
		// Call the super method.
581
		return super.open();
582
	}
583
584
	/**
585
	 * Opens this dialog with the list of bindings for the user to select from.
586
	 * 
587
	 * @return The return code from this dialog.
588
	 * @since 3.3
589
	 */
590
	public final int open(Collection bindings) {
591
		conflictMatches = new TreeMap(new Comparator() {
592
			public final int compare(final Object a, final Object b) {
593
				final Binding bindingA = (Binding) a;
594
				final Binding bindingB = (Binding) b;
595
				final ParameterizedCommand commandA = bindingA.getParameterizedCommand();
596
				final ParameterizedCommand commandB = bindingB.getParameterizedCommand();
597
				try {
598
					return commandA.getName().compareTo(commandB.getName());
599
				} catch (final NotDefinedException e) {
600
					// should not happen
601
					return 0;
602
				}
603
			}
604
		});
605
		Iterator i = bindings.iterator();
606
		while (i.hasNext()) {
607
			Binding b = (Binding) i.next();
608
			TriggerSequence bestActiveBindingFor = bindingService.getBestActiveBindingFor(b
609
					.getParameterizedCommand());
610
			conflictMatches.put(b,
611
					bestActiveBindingFor == null ? null : bestActiveBindingFor.format());
612
		}
613
614
		// If the dialog is already open, dispose the shell and recreate it.
615
		final Shell shell = getShell();
616
		if (shell != null) {
617
			close(false, false);
618
		}
619
		create();
620
621
		// Configure the size and location.
622
		final Point size = configureSize();
623
		configureLocation(size);
624
625
		// Call the super method.
626
		return super.open();
627
	}
628
629
	/**
630
	 * Registers the shell as the same type as its parent with the context support. This ensures
631
	 * that it does not modify the current state of the application.
632
	 */
633
	private final void registerShellType() {
634
		final Shell shell = getShell();
635
		final IContextService contextService = (IContextService) keyBindingState
636
				.getAssociatedWindow().getWorkbench().getService(IContextService.class);
637
		contextService.registerShell(shell, contextService.getShellType((Shell) shell.getParent()));
638
	}
639
640
	/**
641
	 * Remembers the current state of this dialog.
642
	 * 
643
	 * @param previousWidth
644
	 *            The previous width of the dialog.
645
	 * @param binding
646
	 *            The binding to remember, may be <code>null</code> if none.
647
	 */
648
	private final void rememberState(final int previousWidth, final Binding binding) {
649
		this.previousWidth = previousWidth;
650
		this.binding = binding;
651
		hasRememberedState = true;
652
	}
653
654
	/**
655
	 * Exposing this within the keys package.
656
	 * 
657
	 * @param newParentShell
658
	 *            The new parent shell; this value may be <code>null</code> if there is to be no
659
	 *            parent.
660
	 */
661
	protected final void setParentShell(final Shell newParentShell) {
662
		super.setParentShell(newParentShell);
663
	}
664
}
(-)src/org/eclipse/e4/ui/bindings/internal/KeyAssistDialog.properties (+13 lines)
Added Link Here
1
###############################################################################
2
# Copyright (c) 2000, 2008 IBM Corporation and others.
3
# All rights reserved. This program and the accompanying materials
4
# are made available under the terms of the Eclipse Public License v1.0
5
# which accompanies this distribution, and is available at
6
# http://www.eclipse.org/legal/epl-v10.html
7
#
8
# Contributors:
9
#     IBM Corporation - initial API and implementation
10
###############################################################################
11
12
NoMatches_Message=No Matches Found
13
openPreferencePage=Press "{0}" to open the preference page.
(-)src/org/eclipse/e4/ui/bindings/internal/KeyAssistMessages.java (+19 lines)
Added Link Here
1
package org.eclipse.e4.ui.bindings.internal;
2
3
import org.eclipse.osgi.util.NLS;
4
5
/**
6
 * The KeyAssistMessages class is the class that manages the messages used in the KeyAssistDialog.
7
 * 
8
 */
9
public class KeyAssistMessages extends NLS {
10
	private static final String BUNDLE_NAME = "org.eclipse.ui.internal.keys.KeyAssistDialog";//$NON-NLS-1$
11
12
	public static String NoMatches_Message;
13
	public static String openPreferencePage;
14
15
	static {
16
		// load message values from bundle file
17
		NLS.initializeMessages(BUNDLE_NAME, KeyAssistMessages.class);
18
	}
19
}
(-)src/org/eclipse/e4/ui/bindings/keys/KeyBindingDispatcher.java (-2 / +7 lines)
Lines 421-428 Link Here
421
	 * executions.
421
	 * executions.
422
	 */
422
	 */
423
	public final void openMultiKeyAssistShell() {
423
	public final void openMultiKeyAssistShell() {
424
		// TODO: we need some kind of multi binding assistence.
424
		if (keyAssistDialog == null) {
425
		resetState(true);
425
			keyAssistDialog = new KeyAssistDialog(context);
426
		}
427
		if (keyAssistDialog.getShell() == null) {
428
			keyAssistDialog.setParentShell(getDisplay().getActiveShell());
429
		}
430
		keyAssistDialog.open();
426
	}
431
	}
427
432
428
	/**
433
	/**
(-)Eclipse UI/org/eclipse/ui/internal/keys/KeyAssistDialog.java (-2 / +1 lines)
Lines 161-168 Link Here
161
	 *            The key binding state associated with the workbench; must not
161
	 *            The key binding state associated with the workbench; must not
162
	 *            be <code>null</code>.
162
	 *            be <code>null</code>.
163
	 */
163
	 */
164
	KeyAssistDialog(final IWorkbench workbench,
164
	KeyAssistDialog(final IWorkbench workbench, final KeyBindingDispatcher associatedKeyboard,
165
 final KeyBindingDispatcher associatedKeyboard,
166
			final KeyBindingState associatedState) {
165
			final KeyBindingState associatedState) {
167
		super((Shell) null, PopupDialog.INFOPOPUP_SHELLSTYLE, true, false,
166
		super((Shell) null, PopupDialog.INFOPOPUP_SHELLSTYLE, true, false,
168
				false, false, null, null);
167
				false, false, null, null);

Return to bug 317201