1 11 12 package org.eclipse.ui.internal.keys; 13 14 import java.util.ArrayList ; 15 import java.util.Collection ; 16 import java.util.Comparator ; 17 import java.util.Iterator ; 18 import java.util.List ; 19 import java.util.Map ; 20 import java.util.ResourceBundle ; 21 import java.util.SortedMap ; 22 import java.util.TreeMap ; 23 24 import org.eclipse.core.commands.Command; 25 import org.eclipse.core.commands.ParameterizedCommand; 26 import org.eclipse.core.commands.common.CommandException; 27 import org.eclipse.core.commands.common.NotDefinedException; 28 import org.eclipse.jface.bindings.Binding; 29 import org.eclipse.jface.bindings.TriggerSequence; 30 import org.eclipse.jface.bindings.keys.KeySequence; 31 import org.eclipse.jface.bindings.keys.KeyStroke; 32 import org.eclipse.jface.dialogs.Dialog; 33 import org.eclipse.jface.dialogs.PopupDialog; 34 import org.eclipse.jface.preference.PreferenceDialog; 35 import org.eclipse.jface.window.Window; 36 import org.eclipse.swt.SWT; 37 import org.eclipse.swt.graphics.Point; 38 import org.eclipse.swt.graphics.Rectangle; 39 import org.eclipse.swt.layout.GridData; 40 import org.eclipse.swt.layout.GridLayout; 41 import org.eclipse.swt.widgets.Composite; 42 import org.eclipse.swt.widgets.Control; 43 import org.eclipse.swt.widgets.Event; 44 import org.eclipse.swt.widgets.Label; 45 import org.eclipse.swt.widgets.Listener; 46 import org.eclipse.swt.widgets.Shell; 47 import org.eclipse.swt.widgets.Table; 48 import org.eclipse.swt.widgets.TableColumn; 49 import org.eclipse.swt.widgets.TableItem; 50 import org.eclipse.ui.IWorkbench; 51 import org.eclipse.ui.activities.IActivityManager; 52 import org.eclipse.ui.commands.ICommandService; 53 import org.eclipse.ui.contexts.IContextService; 54 import org.eclipse.ui.dialogs.PreferencesUtil; 55 import org.eclipse.ui.internal.util.Util; 56 import org.eclipse.ui.keys.IBindingService; 57 58 import com.ibm.icu.text.MessageFormat; 59 60 72 final class KeyAssistDialog extends PopupDialog { 73 74 79 private static final String BINDING_KEY = "Binding.bindings.jface.eclipse.org"; 81 85 private static final int NO_REMEMBERED_WIDTH = -1; 86 87 90 private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle 91 .getBundle(KeyAssistDialog.class.getName()); 92 93 96 private final IActivityManager activityManager; 97 98 101 private final IBindingService bindingService; 102 103 108 private Binding binding = null; 109 110 113 private final List bindings = new ArrayList (); 114 115 118 private final ICommandService commandService; 119 120 124 private Table completionsTable = null; 125 126 129 private boolean hasRememberedState = false; 130 131 134 private final KeyBindingState keyBindingState; 135 136 140 private int previousWidth = NO_REMEMBERED_WIDTH; 141 142 145 private final WorkbenchKeyboard workbenchKeyboard; 146 147 152 private SortedMap conflictMatches; 153 154 171 KeyAssistDialog(final IWorkbench workbench, 172 final WorkbenchKeyboard associatedKeyboard, 173 final KeyBindingState associatedState) { 174 super((Shell) null, PopupDialog.INFOPOPUP_SHELLSTYLE, true, false, 175 false, false, null, null); 176 177 this.activityManager = workbench.getActivitySupport() 178 .getActivityManager(); 179 this.bindingService = (IBindingService) workbench 180 .getService(IBindingService.class); 181 this.commandService = (ICommandService) workbench 182 .getService(ICommandService.class); 183 this.keyBindingState = associatedState; 184 this.workbenchKeyboard = associatedKeyboard; 185 186 this.setInfoText(getKeySequenceString()); 187 } 188 189 193 final void clearRememberedState() { 194 previousWidth = NO_REMEMBERED_WIDTH; 195 binding = null; 196 hasRememberedState = false; 197 } 198 199 206 public final boolean close() { 207 return close(false); 208 } 209 210 219 public final boolean close(final boolean rememberState) { 220 return close(rememberState, true); 221 } 222 223 234 private final boolean close(final boolean rememberState, 235 final boolean resetState) { 236 final Shell shell = getShell(); 237 if (rememberState) { 238 final int widthToRemember; 240 if ((shell != null) && (!shell.isDisposed())) { 241 widthToRemember = getShell().getSize().x; 242 } else { 243 widthToRemember = NO_REMEMBERED_WIDTH; 244 } 245 246 final Binding bindingToRemember; 248 if ((completionsTable != null) && (!completionsTable.isDisposed())) { 249 final int selectedIndex = completionsTable.getSelectionIndex(); 250 if (selectedIndex != -1) { 251 final TableItem selectedItem = completionsTable 252 .getItem(selectedIndex); 253 bindingToRemember = (Binding) selectedItem 254 .getData(BINDING_KEY); 255 } else { 256 bindingToRemember = null; 257 } 258 } else { 259 bindingToRemember = null; 260 } 261 262 rememberState(widthToRemember, bindingToRemember); 263 completionsTable = null; 264 } 265 266 if (resetState) { 267 keyBindingState.reset(); 268 } 269 return super.close(); 270 } 271 272 281 private final void configureLocation(final Point size) { 282 final Shell shell = getShell(); 283 284 final Shell workbenchWindowShell = keyBindingState 285 .getAssociatedWindow().getShell(); 286 final int xCoord; 287 final int yCoord; 288 if (workbenchWindowShell != null) { 289 293 final Rectangle workbenchWindowBounds = workbenchWindowShell 294 .getBounds(); 295 xCoord = workbenchWindowBounds.x + workbenchWindowBounds.width 296 - size.x - 10; 297 yCoord = workbenchWindowBounds.y + workbenchWindowBounds.height 298 - size.y - 10; 299 300 } else { 301 xCoord = 0; 302 yCoord = 0; 303 304 } 305 final Rectangle bounds = new Rectangle(xCoord, yCoord, size.x, size.y); 306 shell.setBounds(getConstrainedShellBounds(bounds)); 307 } 308 309 318 private final Point configureSize() { 319 final Shell shell = getShell(); 320 321 shell.pack(); 323 final Point size = shell.getSize(); 324 325 if ((previousWidth != NO_REMEMBERED_WIDTH) && (previousWidth > size.x)) { 327 size.x = previousWidth; 328 } 329 330 final Shell workbenchWindowShell = keyBindingState 332 .getAssociatedWindow().getShell(); 333 if (workbenchWindowShell != null) { 334 final Point workbenchWindowSize = workbenchWindowShell.getSize(); 335 final int maxWidth = workbenchWindowSize.x * 2 / 5; 336 final int maxHeight = workbenchWindowSize.y / 2; 337 if (size.x > maxWidth) { 338 size.x = maxWidth; 339 } 340 if (size.y > maxHeight) { 341 size.y = maxHeight; 342 } 343 } 344 345 shell.setSize(size); 347 return size; 348 } 349 350 356 private String getKeySequenceString() { 357 final Command command = commandService 358 .getCommand("org.eclipse.ui.window.showKeyAssist"); final TriggerSequence[] keyBindings = bindingService 360 .getActiveBindingsFor(new ParameterizedCommand(command, null)); 361 final int keyBindingsCount = keyBindings.length; 362 final KeySequence currentState = keyBindingState.getCurrentSequence(); 363 final int prefixSize = currentState.getKeyStrokes().length; 364 365 KeySequence keySequence = null; 367 for (int i = 0; i < keyBindingsCount; i++) { 368 keySequence = (KeySequence) keyBindings[i]; 369 370 if (prefixSize > 0) { 372 if (keySequence.startsWith(currentState, false)) { 373 377 final KeyStroke[] oldKeyStrokes = keySequence 378 .getKeyStrokes(); 379 final int newSize = oldKeyStrokes.length - prefixSize; 380 final KeyStroke[] newKeyStrokes = new KeyStroke[newSize]; 381 System.arraycopy(oldKeyStrokes, prefixSize, newKeyStrokes, 382 0, newSize); 383 keySequence = KeySequence.getInstance(newKeyStrokes); 384 break; 385 } 386 387 391 keySequence = null; 392 continue; 393 394 } 395 396 break; 398 } 399 if (keySequence == null) { 400 return null; } 402 403 return MessageFormat.format(Util.translateString(RESOURCE_BUNDLE, 404 "openPreferencePage"), new Object [] { keySequence.format() }); 406 } 407 408 417 protected final Control createDialogArea(final Composite parent) { 418 registerShellType(); 420 421 final Composite composite = new Composite(parent, SWT.NONE); 423 final GridLayout compositeLayout = new GridLayout(); 424 compositeLayout.marginHeight = 0; 425 compositeLayout.marginWidth = 0; 426 composite.setLayout(compositeLayout); 427 composite.setLayoutData(new GridData(GridData.FILL_BOTH)); 428 composite.setBackground(parent.getBackground()); 429 430 final SortedMap partialMatches; 432 if (conflictMatches != null) { 433 partialMatches = conflictMatches; 434 conflictMatches = null; 435 } else { 436 partialMatches = getPartialMatches(); 437 } 438 439 if (partialMatches.isEmpty()) { 440 createEmptyDialogArea(composite); 441 } else { 442 createTableDialogArea(composite, partialMatches); 443 } 444 return composite; 445 } 446 447 457 private final void createEmptyDialogArea(final Composite parent) { 458 final Label noMatchesLabel = new Label(parent, SWT.NULL); 459 noMatchesLabel.setText(Util.translateString(RESOURCE_BUNDLE, 460 "NoMatches.Message")); noMatchesLabel.setLayoutData(new GridData(GridData.FILL_BOTH)); 462 noMatchesLabel.setBackground(parent.getBackground()); 463 } 464 465 478 private final void createTableDialogArea(final Composite parent, 479 final SortedMap partialMatches) { 480 completionsTable = new Table(parent, SWT.FULL_SELECTION | SWT.SINGLE); 482 final GridData gridData = new GridData(GridData.FILL_BOTH); 483 completionsTable.setLayoutData(gridData); 484 completionsTable.setBackground(parent.getBackground()); 485 completionsTable.setLinesVisible(true); 486 487 bindings.clear(); 489 final TableColumn columnCommandName = new TableColumn(completionsTable, 490 SWT.LEFT, 0); 491 final TableColumn columnKeySequence = new TableColumn(completionsTable, 492 SWT.LEFT, 1); 493 final Iterator itemsItr = partialMatches.entrySet().iterator(); 494 while (itemsItr.hasNext()) { 495 final Map.Entry entry = (Map.Entry ) itemsItr.next(); 496 final TriggerSequence sequence = (TriggerSequence) entry.getValue(); 497 final Binding binding = (Binding) entry.getKey(); 498 final ParameterizedCommand command = binding 499 .getParameterizedCommand(); 500 try { 501 final String [] text = { command.getName(), sequence.format() }; 502 final TableItem item = new TableItem(completionsTable, SWT.NULL); 503 item.setText(text); 504 item.setData(BINDING_KEY, binding); 505 bindings.add(binding); 506 } catch (NotDefinedException e) { 507 } 509 } 510 511 Dialog.applyDialogFont(parent); 512 columnKeySequence.pack(); 513 if (previousWidth != NO_REMEMBERED_WIDTH) { 514 columnKeySequence.setWidth(previousWidth); 515 } 516 columnCommandName.pack(); 517 518 522 completionsTable.addListener(SWT.DefaultSelection, new Listener() { 523 public final void handleEvent(final Event event) { 524 executeKeyBinding(event); 525 } 526 }); 527 } 528 529 532 private final void editKeyBinding() { 533 final String keysPageId = "org.eclipse.ui.preferencePages.Keys"; final PreferenceDialog dialog = PreferencesUtil 536 .createPreferenceDialogOn(getShell(), keysPageId, null, binding); 537 538 542 clearRememberedState(); 543 544 dialog.open(); 546 } 547 548 552 private final void executeKeyBinding(final Event trigger) { 553 final int selectionIndex = completionsTable.getSelectionIndex(); 555 if (selectionIndex >= 0) { 556 final Binding binding = (Binding) bindings.get(selectionIndex); 557 try { 558 workbenchKeyboard.executeCommand(binding, trigger); 559 } catch (final CommandException e) { 560 workbenchKeyboard.logException(e, binding 561 .getParameterizedCommand()); 562 } 563 } 564 } 565 566 574 private final SortedMap getPartialMatches() { 575 final Map partialMatches = bindingService 577 .getPartialMatches(keyBindingState.getCurrentSequence()); 578 579 final SortedMap sortedMatches = new TreeMap (new Comparator () { 581 public final int compare(final Object a, final Object b) { 582 final Binding bindingA = (Binding) a; 583 final Binding bindingB = (Binding) b; 584 final ParameterizedCommand commandA = bindingA 585 .getParameterizedCommand(); 586 final ParameterizedCommand commandB = bindingB 587 .getParameterizedCommand(); 588 try { 589 return commandA.getName().compareTo(commandB.getName()); 590 } catch (final NotDefinedException e) { 591 return 0; 593 } 594 } 595 }); 596 597 602 final Iterator partialMatchItr = partialMatches.entrySet().iterator(); 603 while (partialMatchItr.hasNext()) { 604 final Map.Entry entry = (Map.Entry ) partialMatchItr.next(); 605 final Binding binding = (Binding) entry.getValue(); 606 final Command command = binding.getParameterizedCommand() 607 .getCommand(); 608 if (command.isDefined() 609 && activityManager.getIdentifier(command.getId()) 610 .isEnabled()) { 611 sortedMatches.put(binding, entry.getKey()); 612 } 613 } 614 615 return sortedMatches; 616 617 } 618 619 625 private final boolean hasRememberedState() { 626 return hasRememberedState; 627 } 628 629 637 public final int open() { 638 if (hasRememberedState()) { 640 editKeyBinding(); 641 clearRememberedState(); 642 return Window.OK; 643 } 644 645 final Shell shell = getShell(); 647 if (shell != null) { 648 close(false, false); 649 } 650 create(); 651 652 final Point size = configureSize(); 654 configureLocation(size); 655 656 return super.open(); 658 } 659 660 666 public final int open(Collection bindings) { 667 conflictMatches = new TreeMap (new Comparator () { 668 public final int compare(final Object a, final Object b) { 669 final Binding bindingA = (Binding) a; 670 final Binding bindingB = (Binding) b; 671 final ParameterizedCommand commandA = bindingA 672 .getParameterizedCommand(); 673 final ParameterizedCommand commandB = bindingB 674 .getParameterizedCommand(); 675 try { 676 return commandA.getName().compareTo(commandB.getName()); 677 } catch (final NotDefinedException e) { 678 return 0; 680 } 681 } 682 }); 683 Iterator i = bindings.iterator(); 684 while (i.hasNext()) { 685 Binding b = (Binding) i.next(); 686 conflictMatches.put(b, b.getTriggerSequence()); 687 } 688 689 final Shell shell = getShell(); 691 if (shell != null) { 692 close(false, false); 693 } 694 create(); 695 696 final Point size = configureSize(); 698 configureLocation(size); 699 700 return super.open(); 702 } 703 704 709 private final void registerShellType() { 710 final Shell shell = getShell(); 711 final IContextService contextService = (IContextService) keyBindingState 712 .getAssociatedWindow().getWorkbench().getService( 713 IContextService.class); 714 contextService.registerShell(shell, contextService 715 .getShellType((Shell) shell.getParent())); 716 } 717 718 726 private final void rememberState(final int previousWidth, 727 final Binding binding) { 728 this.previousWidth = previousWidth; 729 this.binding = binding; 730 hasRememberedState = true; 731 } 732 733 740 protected final void setParentShell(final Shell newParentShell) { 741 super.setParentShell(newParentShell); 742 } 743 } 744 | Popular Tags |