1 11 12 package org.eclipse.jface.bindings.keys; 13 14 import java.util.ArrayList ; 15 import java.util.Collection ; 16 import java.util.Collections ; 17 import java.util.Iterator ; 18 import java.util.List ; 19 import java.util.TreeSet ; 20 21 import org.eclipse.jface.util.IPropertyChangeListener; 22 import org.eclipse.jface.util.PropertyChangeEvent; 23 import org.eclipse.swt.SWT; 24 import org.eclipse.swt.events.DisposeEvent; 25 import org.eclipse.swt.events.DisposeListener; 26 import org.eclipse.swt.events.FocusEvent; 27 import org.eclipse.swt.events.FocusListener; 28 import org.eclipse.swt.events.ModifyEvent; 29 import org.eclipse.swt.events.ModifyListener; 30 import org.eclipse.swt.graphics.Font; 31 import org.eclipse.swt.graphics.Point; 32 import org.eclipse.swt.widgets.Display; 33 import org.eclipse.swt.widgets.Event; 34 import org.eclipse.swt.widgets.Listener; 35 import org.eclipse.swt.widgets.Text; 36 37 49 public final class KeySequenceText { 50 51 55 private class KeyTrapListener implements Listener { 56 61 private int insertionIndex = -1; 62 63 67 void clearInsertionIndex() { 68 insertionIndex = -1; 69 } 70 71 80 private final KeyStroke[] deleteKeyStroke(final KeyStroke[] keyStrokes) { 81 clearInsertionIndex(); 82 83 if (hasSelection()) { 84 88 final KeyStroke[][] deletedKeyStrokes = new KeyStroke[1][]; 89 deleteSelection(keyStrokes, false, deletedKeyStrokes); 90 return deletedKeyStrokes[0]; 91 } 92 93 if (keyStrokes.length > 0) { 95 final int newKeyStrokesLength = keyStrokes.length - 1; 96 final KeyStroke[] newKeyStrokes = new KeyStroke[newKeyStrokesLength]; 97 System.arraycopy(keyStrokes, 0, newKeyStrokes, 0, 98 newKeyStrokesLength); 99 return newKeyStrokes; 100 } 101 102 return keyStrokes; 103 } 104 105 116 public void handleEvent(Event event) { 117 KeyStroke[] keyStrokes = getKeySequence().getKeyStrokes(); 118 119 if (event.type == SWT.KeyDown) { 121 keyStrokes = handleKeyDown(event, keyStrokes); 122 } else if (event.type == SWT.KeyUp) { 123 keyStrokes = handleKeyUp(event, keyStrokes); 124 } 125 126 setKeySequence(KeySequence.getInstance(keyStrokes)); 128 129 event.doit = false; 131 } 132 133 145 private KeyStroke[] handleKeyDown(Event event, KeyStroke[] keyStrokes) { 146 if ((event.character == SWT.BS) && (event.stateMask == 0)) { 148 return deleteKeyStroke(keyStrokes); 149 } 150 151 return insertKeyStroke(event, keyStrokes); 152 } 153 154 168 private final KeyStroke[] handleKeyUp(final Event event, 169 final KeyStroke[] keyStrokes) { 170 if (hasIncompleteStroke()) { 171 175 Event mockEvent = new Event(); 176 if ((event.keyCode & SWT.MODIFIER_MASK) != 0) { 177 mockEvent.stateMask = event.stateMask - event.keyCode; 179 } else { 180 184 mockEvent.stateMask = event.stateMask; 185 } 186 187 191 int key = SWTKeySupport 192 .convertEventToUnmodifiedAccelerator(mockEvent); 193 KeyStroke remainingStroke = SWTKeySupport 194 .convertAcceleratorToKeyStroke(key); 195 final int keyStrokesLength = keyStrokes.length; 196 final KeyStroke[] newKeyStrokes; 197 if ((keyStrokesLength > 0) 198 && (remainingStroke.getModifierKeys() != 0)) { 199 newKeyStrokes = new KeyStroke[keyStrokesLength]; 200 System.arraycopy(keyStrokes, 0, newKeyStrokes, 0, 201 keyStrokesLength - 1); 202 newKeyStrokes[keyStrokesLength - 1] = remainingStroke; 203 204 } else if (keyStrokesLength > 0) { 205 newKeyStrokes = new KeyStroke[keyStrokesLength - 1]; 206 System.arraycopy(keyStrokes, 0, newKeyStrokes, 0, 207 keyStrokesLength - 1); 208 209 } else if (remainingStroke.getModifierKeys() != 0) { 210 newKeyStrokes = new KeyStroke[keyStrokesLength + 1]; 211 System.arraycopy(keyStrokes, 0, newKeyStrokes, 0, 212 keyStrokesLength); 213 newKeyStrokes[keyStrokesLength] = remainingStroke; 214 215 } else { 216 newKeyStrokes = keyStrokes; 217 218 } 219 220 return newKeyStrokes; 221 } 222 223 return keyStrokes; 224 } 225 226 256 private final KeyStroke[] insertKeyStroke(final Event event, 257 KeyStroke[] keyStrokes) { 258 int key = SWTKeySupport.convertEventToUnmodifiedAccelerator(event); 260 KeyStroke stroke = SWTKeySupport.convertAcceleratorToKeyStroke(key); 261 262 266 if ((SWT.NUM_LOCK == stroke.getNaturalKey()) 267 || (SWT.CAPS_LOCK == stroke.getNaturalKey()) 268 || (SWT.SCROLL_LOCK == stroke.getNaturalKey())) { 269 return keyStrokes; 270 } 271 272 if (insertionIndex != -1) { 273 if (stroke.isComplete()) { 275 keyStrokes = insertStrokeAt(keyStrokes, stroke, 276 insertionIndex); 277 clearInsertionIndex(); 278 } 279 280 } else if (hasSelection()) { 281 final KeyStroke[][] deletedKeyStrokes = new KeyStroke[1][]; 283 insertionIndex = deleteSelection(keyStrokes, stroke 284 .isComplete(), deletedKeyStrokes); 285 keyStrokes = deletedKeyStrokes[0]; 286 if ((stroke.isComplete()) 287 || (insertionIndex >= keyStrokes.length)) { 288 keyStrokes = insertStrokeAt(keyStrokes, stroke, 289 insertionIndex); 290 clearInsertionIndex(); 291 } 292 293 } else { 294 if ((hasIncompleteStroke()) && (keyStrokes.length > 0)) { 296 final KeyStroke[] newKeyStrokes = new KeyStroke[keyStrokes.length - 1]; 297 System.arraycopy(keyStrokes, 0, newKeyStrokes, 0, 298 keyStrokes.length - 1); 299 keyStrokes = newKeyStrokes; 300 } 301 302 if ((keyStrokes.length == 0) 304 || (insertionIndex >= keyStrokes.length) 305 || (isCursorInLastPosition())) { 306 keyStrokes = insertStrokeAt(keyStrokes, stroke, 307 keyStrokes.length); 308 clearInsertionIndex(); 309 } else { 310 314 final KeyStroke[][] deletedKeyStrokes = new KeyStroke[1][]; 315 insertionIndex = deleteSelection(keyStrokes, stroke 316 .isComplete(), deletedKeyStrokes); 317 keyStrokes = deletedKeyStrokes[0]; 318 if (stroke.isComplete()) { 319 keyStrokes = insertStrokeAt(keyStrokes, stroke, 320 insertionIndex); 321 clearInsertionIndex(); 322 } 323 } 324 325 } 326 327 return keyStrokes; 328 } 329 } 330 331 335 private class TraversalFilter implements Listener { 336 345 public void handleEvent(Event event) { 346 switch (event.detail) { 347 case SWT.TRAVERSE_ESCAPE: 348 case SWT.TRAVERSE_MNEMONIC: 349 case SWT.TRAVERSE_NONE: 350 case SWT.TRAVERSE_PAGE_NEXT: 351 case SWT.TRAVERSE_PAGE_PREVIOUS: 352 case SWT.TRAVERSE_RETURN: 353 event.type = SWT.None; 354 event.doit = false; 355 break; 356 357 case SWT.TRAVERSE_TAB_NEXT: 358 case SWT.TRAVERSE_TAB_PREVIOUS: 359 if ((event.stateMask & (SWT.MODIFIER_MASK ^ SWT.SHIFT)) != 0) { 362 event.type = SWT.None; 364 event.doit = false; 365 break; 366 } 367 368 370 case SWT.TRAVERSE_ARROW_NEXT: 371 case SWT.TRAVERSE_ARROW_PREVIOUS: 372 default: 373 if (hasIncompleteStroke()) { 376 final KeyStroke[] oldKeyStrokes = getKeySequence() 377 .getKeyStrokes(); 378 final int newKeyStrokesLength = oldKeyStrokes.length - 1; 379 if (newKeyStrokesLength >= 1) { 380 final KeyStroke[] newKeyStrokes = new KeyStroke[newKeyStrokesLength]; 381 System.arraycopy(oldKeyStrokes, 0, newKeyStrokes, 0, 382 newKeyStrokesLength); 383 setKeySequence(KeySequence.getInstance(newKeyStrokes)); 384 } else { 385 setKeySequence(KeySequence.getInstance()); 386 } 387 } 388 } 389 390 } 391 } 392 393 397 private class TraversalFilterManager implements FocusListener { 398 399 private TraversalFilter filter = new TraversalFilter(); 400 401 private boolean filtering = false; 402 403 409 public void focusGained(FocusEvent event) { 410 Display.getCurrent().addFilter(SWT.Traverse, filter); 411 filtering = true; 412 } 413 414 420 public void focusLost(FocusEvent event) { 421 Display.getCurrent().removeFilter(SWT.Traverse, filter); 422 filtering = false; 423 } 424 425 428 public void dispose() { 429 if (filtering) { 430 Display.getCurrent().removeFilter(SWT.Traverse, filter); 431 } 432 } 433 } 434 435 440 private class UpdateSequenceListener implements ModifyListener { 441 447 public void modifyText(ModifyEvent event) { 448 try { 449 KeySequence originalSequence = getKeySequence(); 451 452 String contents = getText(); 454 KeySequence newSequence = KeySequence.getInstance(contents); 455 456 if (!originalSequence.equals(newSequence)) { 458 setKeySequence(newSequence); 459 } 460 461 } catch (ParseException e) { 462 setKeySequence(getKeySequence()); 464 } 465 } 466 } 467 468 static { 469 TreeSet trappedKeys = new TreeSet (); 470 trappedKeys.add(SWTKeySupport.convertAcceleratorToKeyStroke(SWT.TAB)); 471 trappedKeys.add(SWTKeySupport.convertAcceleratorToKeyStroke(SWT.TAB 472 | SWT.SHIFT)); 473 trappedKeys.add(SWTKeySupport.convertAcceleratorToKeyStroke(SWT.BS)); 474 List trappedKeyList = new ArrayList (trappedKeys); 475 TRAPPED_KEYS = Collections.unmodifiableList(trappedKeyList); 476 } 477 478 479 private static final String EMPTY_STRING = ""; 481 485 public static final int INFINITE = -1; 486 487 493 public static final String P_KEY_SEQUENCE = "org.eclipse.jface.bindings.keys.KeySequenceText.KeySequence"; 495 500 public static final List TRAPPED_KEYS; 501 502 505 private final KeyTrapListener keyFilter = new KeyTrapListener(); 506 507 510 private KeySequence keySequence = KeySequence.getInstance(); 511 512 516 private Collection listeners = null; 517 518 519 private int maxStrokes = INFINITE; 520 521 522 private final Text text; 523 524 528 private final UpdateSequenceListener updateSequenceListener = new UpdateSequenceListener(); 529 530 538 public KeySequenceText(Text wrappedText) { 539 text = wrappedText; 540 541 if ("carbon".equals(SWT.getPlatform())) { final Font font = new Font(text.getDisplay(), 546 "Lucida Grande", 13, SWT.NORMAL); text.setFont(font); 548 text.addDisposeListener(new DisposeListener() { 549 public void widgetDisposed(DisposeEvent e) { 550 font.dispose(); 551 } 552 }); 553 } 554 555 text.addListener(SWT.KeyUp, keyFilter); 557 text.addListener(SWT.KeyDown, keyFilter); 558 559 final TraversalFilterManager traversalFilterManager = new TraversalFilterManager(); 560 text.addFocusListener(traversalFilterManager); 561 text.addDisposeListener(new DisposeListener() { 562 public void widgetDisposed(DisposeEvent e) { 563 traversalFilterManager.dispose(); 564 } 565 }); 566 567 text.addModifyListener(updateSequenceListener); 569 } 570 571 580 public final void addPropertyChangeListener( 581 final IPropertyChangeListener listener) { 582 if (listener == null) { 583 return; 584 } 585 586 if (listeners == null) { 587 listeners = new ArrayList (1); 588 } 589 590 listeners.add(listener); 591 } 592 593 596 public void clear() { 597 final KeySequence oldKeySequence = keySequence; 598 keySequence = KeySequence.getInstance(); 599 text.setText(EMPTY_STRING); 600 firePropertyChangeEvent(oldKeySequence); 601 } 602 603 620 private final int deleteSelection(final KeyStroke[] keyStrokes, 621 final boolean allowIncomplete, final KeyStroke[][] deletedKeyStrokes) { 622 Point selection = text.getSelection(); 624 int start = selection.x; 625 int end = selection.y; 626 627 634 String string = new String (); 635 List currentStrokes = new ArrayList (); 636 int startTextIndex = 0; final int keyStrokesLength = keyStrokes.length; 638 int i; 639 for (i = 0; (i < keyStrokesLength) && (string.length() < start); i++) { 640 startTextIndex = string.length(); 641 currentStrokes.add(keyStrokes[i]); 642 string = KeySequence.getInstance(currentStrokes).format(); 643 } 644 645 649 int startStrokeIndex; 650 if (string.length() == start) { 651 startStrokeIndex = currentStrokes.size(); 652 } else { 653 startStrokeIndex = currentStrokes.size() - 1; 654 } 655 656 661 int endStrokeIndex; 662 if (start == end) { 663 return startStrokeIndex; 664 } 665 666 for (; (i < keyStrokesLength) && (string.length() < end); i++) { 667 currentStrokes.add(keyStrokes[i]); 668 string = KeySequence.getInstance(currentStrokes).format(); 669 } 670 endStrokeIndex = currentStrokes.size() - 1; 671 if (endStrokeIndex < 0) { 672 endStrokeIndex = 0; 673 } 674 675 679 final int newLength = endStrokeIndex - startStrokeIndex + 1; 680 deletedKeyStrokes[0] = new KeyStroke[newLength]; 681 final KeyStroke startStroke = keyStrokes[startStrokeIndex]; 682 System.arraycopy(keyStrokes, 0, keyStrokes, 0, newLength); 683 684 688 if (allowIncomplete) { 689 final int modifierKeys = startStroke.getModifierKeys(); 690 KeyStroke incompleteStroke = KeyStroke.getInstance(modifierKeys, 691 KeyStroke.NO_KEY); 692 int incompleteStrokeLength = incompleteStroke.format().length(); 693 if ((startTextIndex + incompleteStrokeLength) <= start) { 694 final KeyStroke[] added = new KeyStroke[newLength + 1]; 695 System.arraycopy(deletedKeyStrokes[0], 0, added, 0, 696 startStrokeIndex); 697 added[startStrokeIndex] = incompleteStroke; 698 System.arraycopy(deletedKeyStrokes[0], startStrokeIndex, added, 699 startStrokeIndex + 1, newLength); 700 deletedKeyStrokes[0] = added; 701 } 702 } 703 704 return startStrokeIndex; 705 } 706 707 714 protected final void firePropertyChangeEvent( 715 final KeySequence oldKeySequence) { 716 if (listeners != null) { 717 final Iterator listenerItr = listeners.iterator(); 718 final PropertyChangeEvent event = new PropertyChangeEvent(this, 719 P_KEY_SEQUENCE, oldKeySequence, getKeySequence()); 720 while (listenerItr.hasNext()) { 721 final IPropertyChangeListener listener = (IPropertyChangeListener) listenerItr 722 .next(); 723 listener.propertyChange(event); 724 } 725 } 726 } 727 728 734 public KeySequence getKeySequence() { 735 return keySequence; 736 } 737 738 743 private String getText() { 744 return text.getText(); 745 } 746 747 753 private boolean hasIncompleteStroke() { 754 return !keySequence.isComplete(); 755 } 756 757 763 private boolean hasSelection() { 764 return (text.getSelectionCount() > 0); 765 } 766 767 774 public void insert(KeyStroke stroke) { 775 if (!stroke.isComplete()) { 776 return; 777 } 778 779 final KeySequence keySequence = getKeySequence(); 781 final KeyStroke[] oldKeyStrokes = keySequence.getKeyStrokes(); 782 final KeyStroke[] newKeyStrokes; 783 if ((hasIncompleteStroke()) && (!keySequence.isEmpty())) { 784 final int newKeyStrokesLength = oldKeyStrokes.length - 1; 785 newKeyStrokes = new KeyStroke[newKeyStrokesLength]; 786 System.arraycopy(oldKeyStrokes, 0, newKeyStrokes, 0, 787 newKeyStrokesLength); 788 } else { 789 newKeyStrokes = oldKeyStrokes; 790 } 791 792 KeyStroke[][] deletedKeyStrokes = new KeyStroke[1][]; 793 int index = deleteSelection(newKeyStrokes, false, deletedKeyStrokes); 794 if (index == -1) { 795 index = 0; 796 } 797 798 final KeyStroke[] keyStrokes = insertStrokeAt(newKeyStrokes, stroke, index); 799 keyFilter.clearInsertionIndex(); 800 setKeySequence(KeySequence.getInstance(keyStrokes)); 801 } 802 803 819 private final KeyStroke[] insertStrokeAt(final KeyStroke[] keyStrokes, 820 KeyStroke stroke, int index) { 821 final int keyStrokesLength = keyStrokes.length; 822 final KeyStroke currentStroke = (index >= keyStrokesLength) ? null 823 : keyStrokes[index]; 824 if ((currentStroke != null) && (!currentStroke.isComplete())) { 825 int modifierKeys = currentStroke.getModifierKeys(); 826 final int naturalKey = stroke.getNaturalKey(); 827 modifierKeys |= stroke.getModifierKeys(); 828 keyStrokes[index] = KeyStroke.getInstance(modifierKeys, naturalKey); 829 return keyStrokes; 830 } 831 832 final KeyStroke[] newKeyStrokes = new KeyStroke[keyStrokesLength + 1]; 833 System.arraycopy(keyStrokes, 0, newKeyStrokes, 0, index); 834 newKeyStrokes[index] = stroke; 835 if (index < keyStrokesLength) { 836 System.arraycopy(keyStrokes, index, newKeyStrokes, index + 1, 837 keyStrokesLength-index); 838 } 839 return newKeyStrokes; 840 } 841 842 849 private boolean isCursorInLastPosition() { 850 return (text.getSelection().y >= getText().length()); 851 } 852 853 860 public final void removePropertyChangeListener( 861 final IPropertyChangeListener listener) { 862 if ((listener == null) || (listeners == null)) { 863 return; 864 } 865 866 listeners.remove(listener); 867 } 868 869 884 public void setKeySequence(KeySequence newKeySequence) { 885 final KeySequence oldKeySequence = keySequence; 886 keySequence = newKeySequence; 887 888 if (maxStrokes != INFINITE) { 890 final KeyStroke[] oldKeyStrokes = keySequence.getKeyStrokes(); 891 if (maxStrokes < oldKeyStrokes.length) { 892 final KeyStroke[] newKeyStrokes = new KeyStroke[maxStrokes]; 893 System 894 .arraycopy(oldKeyStrokes, 0, newKeyStrokes, 0, 895 maxStrokes); 896 keySequence = KeySequence.getInstance(newKeyStrokes); 897 } 898 } 899 900 String currentString = getText(); 902 String newString = keySequence.format(); 903 if (!currentString.equals(newString)) { 904 text.removeModifyListener(updateSequenceListener); 906 text.setText(keySequence.format()); 907 text.addModifyListener(updateSequenceListener); 908 text.setSelection(getText().length()); 909 } 910 911 firePropertyChangeEvent(oldKeySequence); 912 } 913 914 921 public int getKeyStrokeLimit() { 922 return maxStrokes; 923 } 924 925 933 public void setKeyStrokeLimit(int keyStrokeLimit) { 934 if (keyStrokeLimit > 0 || keyStrokeLimit == INFINITE) { 935 this.maxStrokes = keyStrokeLimit; 936 } else { 937 throw new IllegalArgumentException (); 938 } 939 940 setKeySequence(getKeySequence()); 942 } 943 } 944 | Popular Tags |