1 /* DefaultEditorKit.java -- 2 Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package javax.swing.text; 40 41 import gnu.java.lang.CPStringBuilder; 42 43 import java.awt.Toolkit; 44 import java.awt.event.ActionEvent; 45 46 import java.io.BufferedReader; 47 import java.io.IOException; 48 import java.io.InputStream; 49 import java.io.InputStreamReader; 50 import java.io.OutputStream; 51 import java.io.OutputStreamWriter; 52 import java.io.Reader; 53 import java.io.Writer; 54 55 import javax.swing.Action; 56 import javax.swing.SwingConstants; 57 58 /** 59 * The default implementation of {@link EditorKit}. This <code>EditorKit</code> 60 * a plain text <code>Document</code> and several commands that together 61 * make up a basic editor, like cut / copy + paste. 62 * 63 * @author original author unknown 64 * @author Roman Kennke (roman@kennke.org) 65 * @author Robert Schuster (robertschuster@fsfe.org) 66 */ 67 public class DefaultEditorKit extends EditorKit 68 { 69 static class SelectionPreviousWordAction 70 extends TextAction 71 { SelectionPreviousWordAction()72 SelectionPreviousWordAction() 73 { 74 super(selectionPreviousWordAction); 75 } 76 actionPerformed(ActionEvent event)77 public void actionPerformed(ActionEvent event) 78 { 79 try 80 { 81 JTextComponent t = getTextComponent(event); 82 83 if (t != null) 84 { 85 int offs = Utilities.getPreviousWord(t, t.getCaretPosition()); 86 87 Caret c = t.getCaret(); 88 c.moveDot(offs); 89 c.setMagicCaretPosition(t.modelToView(offs).getLocation()); 90 } 91 } 92 catch(BadLocationException ble) 93 { 94 // Can't happen. 95 } 96 } 97 } 98 99 static class SelectionNextWordAction 100 extends TextAction 101 { SelectionNextWordAction()102 SelectionNextWordAction() 103 { 104 super(selectionNextWordAction); 105 } 106 actionPerformed(ActionEvent event)107 public void actionPerformed(ActionEvent event) 108 { 109 try 110 { 111 JTextComponent t = getTextComponent(event); 112 113 if (t != null) 114 { 115 int offs = Utilities.getNextWord(t, t.getCaretPosition()); 116 117 Caret c = t.getCaret(); 118 c.moveDot(offs); 119 c.setMagicCaretPosition(t.modelToView(offs).getLocation()); 120 } 121 } 122 catch(BadLocationException ble) 123 { 124 // Can't happen. 125 } 126 } 127 } 128 129 static class SelectionBeginWordAction extends TextAction 130 { SelectionBeginWordAction()131 SelectionBeginWordAction() 132 { 133 super(selectionBeginWordAction); 134 } 135 actionPerformed(ActionEvent event)136 public void actionPerformed(ActionEvent event) 137 { 138 try 139 { 140 JTextComponent t = getTextComponent(event); 141 142 if (t != null) 143 { 144 int offs = Utilities.getWordStart(t, t.getCaretPosition()); 145 146 Caret c = t.getCaret(); 147 c.moveDot(offs); 148 c.setMagicCaretPosition(t.modelToView(offs).getLocation()); 149 } 150 } 151 catch(BadLocationException ble) 152 { 153 // Can't happen. 154 } 155 } 156 } 157 158 static class SelectionEndWordAction extends TextAction 159 { SelectionEndWordAction()160 SelectionEndWordAction() 161 { 162 super(selectionEndWordAction); 163 } 164 actionPerformed(ActionEvent event)165 public void actionPerformed(ActionEvent event) 166 { 167 try 168 { 169 JTextComponent t = getTextComponent(event); 170 171 if (t != null) 172 { 173 int offs = Utilities.getWordEnd(t, t.getCaretPosition()); 174 175 Caret c = t.getCaret(); 176 c.moveDot(offs); 177 c.setMagicCaretPosition(t.modelToView(offs).getLocation()); 178 } 179 } 180 catch(BadLocationException ble) 181 { 182 // Can't happen. 183 } 184 } 185 } 186 187 static class BeginWordAction extends TextAction 188 { BeginWordAction()189 BeginWordAction() 190 { 191 super(beginWordAction); 192 } 193 actionPerformed(ActionEvent event)194 public void actionPerformed(ActionEvent event) 195 { 196 try 197 { 198 JTextComponent t = getTextComponent(event); 199 200 if (t != null) 201 { 202 int offs = Utilities.getWordStart(t, t.getCaretPosition()); 203 204 Caret c = t.getCaret(); 205 c.setDot(offs); 206 c.setMagicCaretPosition(t.modelToView(offs).getLocation()); 207 } 208 } 209 catch(BadLocationException ble) 210 { 211 // Can't happen. 212 } 213 } 214 } 215 216 static class EndWordAction extends TextAction 217 { EndWordAction()218 EndWordAction() 219 { 220 super(endWordAction); 221 } 222 actionPerformed(ActionEvent event)223 public void actionPerformed(ActionEvent event) 224 { 225 try 226 { 227 JTextComponent t = getTextComponent(event); 228 229 if (t != null) 230 { 231 int offs = Utilities.getWordEnd(t, t.getCaretPosition()); 232 233 Caret c = t.getCaret(); 234 c.setDot(offs); 235 c.setMagicCaretPosition(t.modelToView(offs).getLocation()); 236 } 237 } 238 catch(BadLocationException ble) 239 { 240 // Can't happen. 241 } 242 } 243 } 244 245 static class PreviousWordAction 246 extends TextAction 247 { PreviousWordAction()248 PreviousWordAction() 249 { 250 super(previousWordAction); 251 } 252 actionPerformed(ActionEvent event)253 public void actionPerformed(ActionEvent event) 254 { 255 try 256 { 257 JTextComponent t = getTextComponent(event); 258 259 if (t != null) 260 { 261 int offs = Utilities.getPreviousWord(t, t.getCaretPosition()); 262 263 Caret c = t.getCaret(); 264 c.setDot(offs); 265 c.setMagicCaretPosition(t.modelToView(offs).getLocation()); 266 } 267 } 268 catch(BadLocationException ble) 269 { 270 // Can't happen. 271 } 272 } 273 } 274 275 static class NextWordAction 276 extends TextAction 277 { NextWordAction()278 NextWordAction() 279 { 280 super(nextWordAction); 281 } 282 actionPerformed(ActionEvent event)283 public void actionPerformed(ActionEvent event) 284 { 285 try 286 { 287 JTextComponent t = getTextComponent(event); 288 289 if (t != null) 290 { 291 int offs = Utilities.getNextWord(t, t.getCaretPosition()); 292 293 Caret c = t.getCaret(); 294 c.setDot(offs); 295 c.setMagicCaretPosition(t.modelToView(offs).getLocation()); 296 } 297 } 298 catch(BadLocationException ble) 299 { 300 // Can't happen. 301 } 302 } 303 } 304 305 static class SelectAllAction 306 extends TextAction 307 { SelectAllAction()308 SelectAllAction() 309 { 310 super(selectAllAction); 311 } 312 actionPerformed(ActionEvent event)313 public void actionPerformed(ActionEvent event) 314 { 315 JTextComponent t = getTextComponent(event); 316 if (t != null) 317 { 318 int offs = t.getDocument().getLength(); 319 Caret c = t.getCaret(); 320 c.setDot(0); 321 c.moveDot(offs); 322 try 323 { 324 c.setMagicCaretPosition(t.modelToView(offs).getLocation()); 325 } 326 catch(BadLocationException ble) 327 { 328 // Can't happen. 329 } 330 } 331 } 332 } 333 334 static class SelectionBeginAction 335 extends TextAction 336 { SelectionBeginAction()337 SelectionBeginAction() 338 { 339 super(selectionBeginAction); 340 } 341 actionPerformed(ActionEvent event)342 public void actionPerformed(ActionEvent event) 343 { 344 JTextComponent t = getTextComponent(event); 345 if (t != null) 346 { 347 Caret c = t.getCaret(); 348 c.moveDot(0); 349 try 350 { 351 c.setMagicCaretPosition(t.modelToView(0).getLocation()); 352 } 353 catch(BadLocationException ble) 354 { 355 // Can't happen. 356 } 357 } 358 } 359 } 360 361 static class SelectionEndAction 362 extends TextAction 363 { SelectionEndAction()364 SelectionEndAction() 365 { 366 super(selectionEndAction); 367 } 368 actionPerformed(ActionEvent event)369 public void actionPerformed(ActionEvent event) 370 { 371 JTextComponent t = getTextComponent(event); 372 if (t != null) 373 { 374 int offs = t.getDocument().getLength(); 375 Caret c = t.getCaret(); 376 c.moveDot(offs); 377 try 378 { 379 c.setMagicCaretPosition(t.modelToView(offs).getLocation()); 380 } 381 catch(BadLocationException ble) 382 { 383 // Can't happen. 384 } 385 } 386 } 387 } 388 389 static class SelectionBeginLineAction 390 extends TextAction 391 { 392 SelectionBeginLineAction()393 SelectionBeginLineAction() 394 { 395 super(selectionBeginLineAction); 396 } 397 actionPerformed(ActionEvent event)398 public void actionPerformed(ActionEvent event) 399 { 400 JTextComponent t = getTextComponent(event); 401 if (t != null) 402 { 403 Caret c = t.getCaret(); 404 try 405 { 406 int offs = Utilities.getRowStart(t, c.getDot()); 407 c.setMagicCaretPosition(t.modelToView(offs).getLocation()); 408 } 409 catch(BadLocationException ble) 410 { 411 // Can't happen. 412 } 413 } 414 } 415 } 416 417 static class SelectionEndLineAction 418 extends TextAction 419 { SelectionEndLineAction()420 SelectionEndLineAction() 421 { 422 super(selectionEndLineAction); 423 } 424 actionPerformed(ActionEvent event)425 public void actionPerformed(ActionEvent event) 426 { 427 JTextComponent t = getTextComponent(event); 428 if (t != null) 429 { 430 Caret c = t.getCaret(); 431 try 432 { 433 int offs = Utilities.getRowEnd(t, c.getDot()); 434 c.setMagicCaretPosition(t.modelToView(offs).getLocation()); 435 } 436 catch(BadLocationException ble) 437 { 438 // Can't happen. 439 } 440 } 441 } 442 } 443 444 static class SelectLineAction extends TextAction 445 { SelectLineAction()446 SelectLineAction() 447 { 448 super(selectLineAction); 449 } 450 actionPerformed(ActionEvent event)451 public void actionPerformed(ActionEvent event) 452 { 453 JTextComponent t = getTextComponent(event); 454 if (t != null) 455 { 456 Caret c = t.getCaret(); 457 try 458 { 459 int offs1 = Utilities.getRowStart(t, c.getDot()); 460 int offs2 = Utilities.getRowEnd(t, c.getDot()); 461 c.setDot(offs2); 462 c.moveDot(offs1); 463 c.setMagicCaretPosition(t.modelToView(offs2).getLocation()); 464 } 465 catch(BadLocationException ble) 466 { 467 // Can't happen. 468 } 469 } 470 } 471 } 472 473 static class SelectWordAction extends TextAction 474 { SelectWordAction()475 SelectWordAction() 476 { 477 super(selectWordAction); 478 } 479 actionPerformed(ActionEvent event)480 public void actionPerformed(ActionEvent event) 481 { 482 JTextComponent t = getTextComponent(event); 483 if (t != null) 484 { 485 Caret c = t.getCaret(); 486 int dot = c.getDot(); 487 try 488 { 489 int wordStart = Utilities.getWordStart(t, dot); 490 491 if (dot == wordStart) 492 { 493 // Current cursor position is on the first character in a word. 494 c.setDot(wordStart); 495 c.moveDot(Utilities.getWordEnd(t, wordStart)); 496 } 497 else 498 { 499 // Current cursor position is not on the first character 500 // in a word. 501 int nextWord = Utilities.getNextWord(t, dot); 502 int previousWord = Utilities.getPreviousWord(t, dot); 503 int previousWordEnd = Utilities.getWordEnd(t, previousWord); 504 505 // Cursor position is in the space between two words. In such a 506 // situation just select the space. 507 if (dot >= previousWordEnd && dot <= nextWord) 508 { 509 c.setDot(previousWordEnd); 510 c.moveDot(nextWord); 511 } 512 else 513 { 514 // Cursor position is inside a word. Just select it then. 515 c.setDot(previousWord); 516 c.moveDot(previousWordEnd); 517 } 518 } 519 520 // If the position was updated change the magic caret position 521 // as well. 522 if (c.getDot() != dot) 523 c.setMagicCaretPosition(t.modelToView(c.getDot()).getLocation()); 524 } 525 catch(BadLocationException ble) 526 { 527 // Can't happen. 528 } 529 } 530 } 531 } 532 533 static class SelectionDownAction 534 extends TextAction.VerticalMovementAction 535 { SelectionDownAction()536 SelectionDownAction() 537 { 538 super(selectionDownAction, SwingConstants.SOUTH); 539 } 540 actionPerformedImpl(Caret c, int offs)541 protected void actionPerformedImpl(Caret c, int offs) 542 { 543 c.moveDot(offs); 544 } 545 546 } 547 548 static class SelectionUpAction 549 extends TextAction.VerticalMovementAction 550 { SelectionUpAction()551 SelectionUpAction() 552 { 553 super(selectionUpAction, SwingConstants.NORTH); 554 } 555 actionPerformedImpl(Caret c, int offs)556 protected void actionPerformedImpl(Caret c, int offs) 557 { 558 c.moveDot(offs); 559 } 560 561 } 562 563 static class SelectionForwardAction 564 extends TextAction.HorizontalMovementAction 565 { SelectionForwardAction()566 SelectionForwardAction() 567 { 568 super(selectionForwardAction, SwingConstants.EAST); 569 } 570 actionPerformedImpl(Caret c, int offs)571 protected void actionPerformedImpl(Caret c, int offs) 572 { 573 c.moveDot(offs); 574 } 575 } 576 577 static class SelectionBackwardAction 578 extends TextAction.HorizontalMovementAction 579 { SelectionBackwardAction()580 SelectionBackwardAction() 581 { 582 super(selectionBackwardAction, SwingConstants.WEST); 583 } 584 actionPerformedImpl(Caret c, int offs)585 protected void actionPerformedImpl(Caret c, int offs) 586 { 587 c.moveDot(offs); 588 } 589 } 590 591 static class DownAction 592 extends TextAction.VerticalMovementAction 593 { DownAction()594 DownAction() 595 { 596 super(downAction, SwingConstants.SOUTH); 597 } 598 actionPerformedImpl(Caret c, int offs)599 protected void actionPerformedImpl(Caret c, int offs) 600 { 601 c.setDot(offs); 602 } 603 } 604 605 static class UpAction 606 extends TextAction.VerticalMovementAction 607 { UpAction()608 UpAction() 609 { 610 super(upAction, SwingConstants.NORTH); 611 } 612 actionPerformedImpl(Caret c, int offs)613 protected void actionPerformedImpl(Caret c, int offs) 614 { 615 c.setDot(offs); 616 } 617 618 } 619 620 static class ForwardAction 621 extends TextAction.HorizontalMovementAction 622 { ForwardAction()623 ForwardAction() 624 { 625 super(forwardAction, SwingConstants.EAST); 626 } 627 actionPerformedImpl(Caret c, int offs)628 protected void actionPerformedImpl(Caret c, int offs) 629 { 630 c.setDot(offs); 631 } 632 633 } 634 635 static class BackwardAction 636 extends TextAction.HorizontalMovementAction 637 { BackwardAction()638 BackwardAction() 639 { 640 super(backwardAction, SwingConstants.WEST); 641 } 642 actionPerformedImpl(Caret c, int offs)643 protected void actionPerformedImpl(Caret c, int offs) 644 { 645 c.setDot(offs); 646 } 647 648 } 649 650 static class DeletePrevCharAction 651 extends TextAction 652 { DeletePrevCharAction()653 DeletePrevCharAction() 654 { 655 super(deletePrevCharAction); 656 } 657 actionPerformed(ActionEvent event)658 public void actionPerformed(ActionEvent event) 659 { 660 JTextComponent t = getTextComponent(event); 661 if (t != null) 662 { 663 try 664 { 665 int pos = t.getSelectionStart(); 666 int len = t.getSelectionEnd() - pos; 667 668 if (len > 0) 669 t.getDocument().remove(pos, len); 670 else if (pos > 0) 671 { 672 pos--; 673 t.getDocument().remove(pos, 1); 674 Caret c = t.getCaret(); 675 c.setDot(pos); 676 c.setMagicCaretPosition(t.modelToView(pos).getLocation()); 677 } 678 } 679 catch (BadLocationException e) 680 { 681 // FIXME: we're not authorized to throw this.. swallow it? 682 } 683 } 684 } 685 } 686 687 static class DeleteNextCharAction 688 extends TextAction 689 { DeleteNextCharAction()690 DeleteNextCharAction() 691 { 692 super(deleteNextCharAction); 693 } 694 actionPerformed(ActionEvent event)695 public void actionPerformed(ActionEvent event) 696 { 697 JTextComponent t = getTextComponent(event); 698 if (t != null) 699 { 700 try 701 { 702 int pos = t.getSelectionStart(); 703 int len = t.getSelectionEnd() - pos; 704 705 if (len > 0) 706 t.getDocument().remove(pos, len); 707 else if (pos < t.getDocument().getLength()) 708 t.getDocument().remove(pos, 1); 709 710 Caret c = t.getCaret(); 711 c.setDot(pos); 712 c.setMagicCaretPosition(t.modelToView(pos).getLocation()); 713 } 714 catch (BadLocationException e) 715 { 716 // FIXME: we're not authorized to throw this.. swallow it? 717 } 718 } 719 } 720 } 721 722 static class EndLineAction 723 extends TextAction 724 { EndLineAction()725 EndLineAction() 726 { 727 super(endLineAction); 728 } 729 actionPerformed(ActionEvent event)730 public void actionPerformed(ActionEvent event) 731 { 732 JTextComponent t = getTextComponent(event); 733 if (t != null) 734 { 735 try 736 { 737 int offs = Utilities.getRowEnd(t, t.getCaretPosition()); 738 if (offs > -1) 739 { 740 Caret c = t.getCaret(); 741 c.setDot(offs); 742 c.setMagicCaretPosition(t.modelToView(offs).getLocation()); 743 } 744 } 745 catch (BadLocationException ble) 746 { 747 // Nothing to do here 748 } 749 } 750 } 751 } 752 753 static class BeginLineAction 754 extends TextAction 755 { BeginLineAction()756 BeginLineAction() 757 { 758 super(beginLineAction); 759 } 760 actionPerformed(ActionEvent event)761 public void actionPerformed(ActionEvent event) 762 { 763 JTextComponent t = getTextComponent(event); 764 if (t != null) 765 { 766 try 767 { 768 int offs = Utilities.getRowStart(t, t.getCaretPosition()); 769 if (offs > -1) 770 { 771 Caret c = t.getCaret(); 772 c.setDot(offs); 773 c.setMagicCaretPosition(t.modelToView(offs).getLocation()); 774 } 775 } 776 catch (BadLocationException ble) 777 { 778 // Do nothing here. 779 } 780 } 781 } 782 } 783 784 static class BeginAction extends TextAction 785 { 786 BeginAction()787 BeginAction() 788 { 789 super(beginAction); 790 } 791 actionPerformed(ActionEvent event)792 public void actionPerformed(ActionEvent event) 793 { 794 JTextComponent t = getTextComponent(event); 795 if (t != null) 796 { 797 Caret c = t.getCaret(); 798 c.setDot(0); 799 try 800 { 801 c.setMagicCaretPosition(t.modelToView(0).getLocation()); 802 } 803 catch(BadLocationException ble) 804 { 805 // Can't happen. 806 } 807 } 808 } 809 } 810 811 static class EndAction extends TextAction 812 { 813 EndAction()814 EndAction() 815 { 816 super(endAction); 817 } 818 actionPerformed(ActionEvent event)819 public void actionPerformed(ActionEvent event) 820 { 821 JTextComponent t = getTextComponent(event); 822 if (t != null) 823 { 824 int offs = t.getDocument().getLength(); 825 Caret c = t.getCaret(); 826 c.setDot(offs); 827 try 828 { 829 c.setMagicCaretPosition(t.modelToView(offs).getLocation()); 830 } 831 catch(BadLocationException ble) 832 { 833 // Can't happen. 834 } 835 } 836 } 837 } 838 839 /** 840 * Creates a beep on the PC speaker. 841 * 842 * @see Toolkit#beep() 843 */ 844 public static class BeepAction extends TextAction 845 { 846 /** 847 * Creates a new <code>BeepAction</code>. 848 */ BeepAction()849 public BeepAction() 850 { 851 super(beepAction); 852 } 853 854 /** 855 * Performs the <code>Action</code>. 856 * 857 * @param event the action event describing the user action 858 */ actionPerformed(ActionEvent event)859 public void actionPerformed(ActionEvent event) 860 { 861 Toolkit.getDefaultToolkit().beep(); 862 } 863 } 864 865 /** 866 * Copies the selected content into the system clipboard. 867 * 868 * @see Toolkit#getSystemClipboard() 869 * @see CutAction 870 * @see PasteAction 871 */ 872 public static class CopyAction extends TextAction 873 { 874 875 /** 876 * Create a new <code>CopyAction</code>. 877 */ CopyAction()878 public CopyAction() 879 { 880 super(copyAction); 881 } 882 883 /** 884 * Performs the <code>Action</code>. 885 * 886 * @param event the action event describing the user action 887 */ actionPerformed(ActionEvent event)888 public void actionPerformed(ActionEvent event) 889 { 890 JTextComponent target = getTextComponent(event); 891 if (target != null) 892 target.copy(); 893 } 894 } 895 896 897 /** 898 * Copies the selected content into the system clipboard and deletes the 899 * selection. 900 * 901 * @see Toolkit#getSystemClipboard() 902 * @see CopyAction 903 * @see PasteAction 904 */ 905 public static class CutAction extends TextAction 906 { 907 908 /** 909 * Create a new <code>CutAction</code>. 910 */ CutAction()911 public CutAction() 912 { 913 super(cutAction); 914 } 915 916 /** 917 * Performs the <code>Action</code>. 918 * 919 * @param event the action event describing the user action 920 */ actionPerformed(ActionEvent event)921 public void actionPerformed(ActionEvent event) 922 { 923 JTextComponent target = getTextComponent(event); 924 if (target != null) 925 target.cut(); 926 } 927 } 928 929 /** 930 * Copies content from the system clipboard into the editor. 931 * 932 * @see Toolkit#getSystemClipboard() 933 * @see CopyAction 934 * @see CutAction 935 */ 936 public static class PasteAction extends TextAction 937 { 938 939 /** 940 * Create a new <code>PasteAction</code>. 941 */ PasteAction()942 public PasteAction() 943 { 944 super(pasteAction); 945 } 946 947 /** 948 * Performs the <code>Action</code>. 949 * 950 * @param event the action event describing the user action 951 */ actionPerformed(ActionEvent event)952 public void actionPerformed(ActionEvent event) 953 { 954 JTextComponent target = getTextComponent(event); 955 if (target != null) 956 target.paste(); 957 } 958 } 959 960 /** 961 * This action is executed as default action when a KEY_TYPED 962 * event is received and no keymap entry exists for that. The purpose 963 * of this action is to filter out a couple of characters. This includes 964 * the control characters and characters with the ALT-modifier. 965 * 966 * If an event does not get filtered, it is inserted into the document 967 * of the text component. If there is some text selected in the text 968 * component, this text will be replaced. 969 */ 970 public static class DefaultKeyTypedAction 971 extends TextAction 972 { 973 974 /** 975 * Creates a new <code>DefaultKeyTypedAction</code>. 976 */ DefaultKeyTypedAction()977 public DefaultKeyTypedAction() 978 { 979 super(defaultKeyTypedAction); 980 } 981 982 /** 983 * Performs the <code>Action</code>. 984 * 985 * @param event the action event describing the user action 986 */ actionPerformed(ActionEvent event)987 public void actionPerformed(ActionEvent event) 988 { 989 // first we filter the following events: 990 // - control characters 991 // - key events with the ALT modifier 992 JTextComponent target = getTextComponent(event); 993 if ((target != null) && (event != null)) 994 { 995 if ((target.isEditable()) && (target.isEnabled())) 996 { 997 String content = event.getActionCommand(); 998 int mod = event.getModifiers(); 999 if ((content != null) && (content.length() > 0) 1000 && (mod & ActionEvent.ALT_MASK) == 0 1001 && (mod & ActionEvent.CTRL_MASK) == 0) 1002 { 1003 char c = content.charAt(0); 1004 if ((c >= 0x20) && (c != 0x7F)) 1005 { 1006 target.replaceSelection(content); 1007 } 1008 } 1009 } 1010 } 1011 } 1012 } 1013 1014 /** 1015 * This action inserts a newline character into the document 1016 * of the text component. This is typically triggered by hitting 1017 * ENTER on the keyboard. 1018 */ 1019 public static class InsertBreakAction extends TextAction 1020 { 1021 1022 /** 1023 * Creates a new <code>InsertBreakAction</code>. 1024 */ InsertBreakAction()1025 public InsertBreakAction() 1026 { 1027 super(insertBreakAction); 1028 } 1029 1030 /** 1031 * Performs the <code>Action</code>. 1032 * 1033 * @param event the action event describing the user action 1034 */ actionPerformed(ActionEvent event)1035 public void actionPerformed(ActionEvent event) 1036 { 1037 JTextComponent t = getTextComponent(event); 1038 if (t != null) 1039 t.replaceSelection("\n"); 1040 } 1041 } 1042 1043 /** 1044 * Places content into the associated editor. If there currently is a 1045 * selection, this selection is replaced. 1046 */ 1047 // FIXME: Figure out what this Action is supposed to do. Obviously text 1048 // that is entered by the user is inserted through DefaultKeyTypedAction. 1049 public static class InsertContentAction extends TextAction 1050 { 1051 1052 /** 1053 * Creates a new <code>InsertContentAction</code>. 1054 */ InsertContentAction()1055 public InsertContentAction() 1056 { 1057 super(insertContentAction); 1058 } 1059 1060 /** 1061 * Performs the <code>Action</code>. 1062 * 1063 * @param event the action event describing the user action 1064 */ actionPerformed(ActionEvent event)1065 public void actionPerformed(ActionEvent event) 1066 { 1067 // FIXME: Figure out what this Action is supposed to do. Obviously text 1068 // that is entered by the user is inserted through DefaultKeyTypedAction. 1069 } 1070 } 1071 1072 /** 1073 * Inserts a TAB character into the text editor. 1074 */ 1075 public static class InsertTabAction extends TextAction 1076 { 1077 1078 /** 1079 * Creates a new <code>TabAction</code>. 1080 */ InsertTabAction()1081 public InsertTabAction() 1082 { 1083 super(insertTabAction); 1084 } 1085 1086 /** 1087 * Performs the <code>Action</code>. 1088 * 1089 * @param event the action event describing the user action 1090 */ actionPerformed(ActionEvent event)1091 public void actionPerformed(ActionEvent event) 1092 { 1093 JTextComponent t = getTextComponent(event); 1094 if (t != null) 1095 t.replaceSelection("\t"); 1096 } 1097 } 1098 1099 /** 1100 * The serial version of DefaultEditorKit. 1101 */ 1102 private static final long serialVersionUID = 9017245433028523428L; 1103 1104 /** 1105 * The name of the <code>Action</code> that moves the caret one character 1106 * backwards. 1107 * 1108 * @see #getActions() 1109 */ 1110 public static final String backwardAction = "caret-backward"; 1111 1112 /** 1113 * The name of the <code>Action</code> that creates a beep in the speaker. 1114 * 1115 * @see #getActions() 1116 */ 1117 public static final String beepAction = "beep"; 1118 1119 /** 1120 * The name of the <code>Action</code> that moves the caret to the beginning 1121 * of the <code>Document</code>. 1122 * 1123 * @see #getActions() 1124 */ 1125 public static final String beginAction = "caret-begin"; 1126 1127 /** 1128 * The name of the <code>Action</code> that moves the caret to the beginning 1129 * of the current line. 1130 * 1131 * @see #getActions() 1132 */ 1133 public static final String beginLineAction = "caret-begin-line"; 1134 1135 /** 1136 * The name of the <code>Action</code> that moves the caret to the beginning 1137 * of the current paragraph. 1138 * 1139 * @see #getActions() 1140 */ 1141 public static final String beginParagraphAction = "caret-begin-paragraph"; 1142 1143 /** 1144 * The name of the <code>Action</code> that moves the caret to the beginning 1145 * of the current word. 1146 * 1147 * @see #getActions() 1148 */ 1149 public static final String beginWordAction = "caret-begin-word"; 1150 1151 /** 1152 * The name of the <code>Action</code> that copies the selected content 1153 * into the system clipboard. 1154 * 1155 * @see #getActions() 1156 */ 1157 public static final String copyAction = "copy-to-clipboard"; 1158 1159 /** 1160 * The name of the <code>Action</code> that copies the selected content 1161 * into the system clipboard and removes the selection. 1162 * 1163 * @see #getActions() 1164 */ 1165 public static final String cutAction = "cut-to-clipboard"; 1166 1167 /** 1168 * The name of the <code>Action</code> that is performed by default if 1169 * a key is typed and there is no keymap entry. 1170 * 1171 * @see #getActions() 1172 */ 1173 public static final String defaultKeyTypedAction = "default-typed"; 1174 1175 /** 1176 * The name of the <code>Action</code> that deletes the character that 1177 * follows the current caret position. 1178 * 1179 * @see #getActions() 1180 */ 1181 public static final String deleteNextCharAction = "delete-next"; 1182 1183 /** 1184 * The name of the <code>Action</code> that deletes the character that 1185 * precedes the current caret position. 1186 * 1187 * @see #getActions() 1188 */ 1189 public static final String deletePrevCharAction = "delete-previous"; 1190 1191 /** 1192 * The name of the <code>Action</code> that moves the caret one line down. 1193 * 1194 * @see #getActions() 1195 */ 1196 public static final String downAction = "caret-down"; 1197 1198 /** 1199 * The name of the <code>Action</code> that moves the caret to the end 1200 * of the <code>Document</code>. 1201 * 1202 * @see #getActions() 1203 */ 1204 public static final String endAction = "caret-end"; 1205 1206 /** 1207 * The name of the <code>Action</code> that moves the caret to the end 1208 * of the current line. 1209 * 1210 * @see #getActions() 1211 */ 1212 public static final String endLineAction = "caret-end-line"; 1213 1214 /** 1215 * When a document is read and an CRLF is encountered, then we add a property 1216 * with this name and a value of "\r\n". 1217 */ 1218 public static final String EndOfLineStringProperty = "__EndOfLine__"; 1219 1220 /** 1221 * The name of the <code>Action</code> that moves the caret to the end 1222 * of the current paragraph. 1223 * 1224 * @see #getActions() 1225 */ 1226 public static final String endParagraphAction = "caret-end-paragraph"; 1227 1228 /** 1229 * The name of the <code>Action</code> that moves the caret to the end 1230 * of the current word. 1231 * 1232 * @see #getActions() 1233 */ 1234 public static final String endWordAction = "caret-end-word"; 1235 1236 /** 1237 * The name of the <code>Action</code> that moves the caret one character 1238 * forward. 1239 * 1240 * @see #getActions() 1241 */ 1242 public static final String forwardAction = "caret-forward"; 1243 1244 /** 1245 * The name of the <code>Action</code> that inserts a line break. 1246 * 1247 * @see #getActions() 1248 */ 1249 public static final String insertBreakAction = "insert-break"; 1250 1251 /** 1252 * The name of the <code>Action</code> that inserts some content. 1253 * 1254 * @see #getActions() 1255 */ 1256 public static final String insertContentAction = "insert-content"; 1257 1258 /** 1259 * The name of the <code>Action</code> that inserts a TAB. 1260 * 1261 * @see #getActions() 1262 */ 1263 public static final String insertTabAction = "insert-tab"; 1264 1265 /** 1266 * The name of the <code>Action</code> that moves the caret to the beginning 1267 * of the next word. 1268 * 1269 * @see #getActions() 1270 */ 1271 public static final String nextWordAction = "caret-next-word"; 1272 1273 /** 1274 * The name of the <code>Action</code> that moves the caret one page down. 1275 * 1276 * @see #getActions() 1277 */ 1278 public static final String pageDownAction = "page-down"; 1279 1280 /** 1281 * The name of the <code>Action</code> that moves the caret one page up. 1282 * 1283 * @see #getActions() 1284 */ 1285 public static final String pageUpAction = "page-up"; 1286 1287 /** 1288 * The name of the <code>Action</code> that copies content from the system 1289 * clipboard into the document. 1290 * 1291 * @see #getActions() 1292 */ 1293 public static final String pasteAction = "paste-from-clipboard"; 1294 1295 /** 1296 * The name of the <code>Action</code> that moves the caret to the beginning 1297 * of the previous word. 1298 * 1299 * @see #getActions() 1300 */ 1301 public static final String previousWordAction = "caret-previous-word"; 1302 1303 /** 1304 * The name of the <code>Action</code> that sets the editor in read only 1305 * mode. 1306 * 1307 * @see #getActions() 1308 */ 1309 public static final String readOnlyAction = "set-read-only"; 1310 1311 /** 1312 * The name of the <code>Action</code> that selects the whole document. 1313 * 1314 * @see #getActions() 1315 */ 1316 public static final String selectAllAction = "select-all"; 1317 1318 /** 1319 * The name of the <code>Action</code> that moves the caret one character 1320 * backwards, possibly extending the current selection. 1321 * 1322 * @see #getActions() 1323 */ 1324 public static final String selectionBackwardAction = "selection-backward"; 1325 1326 /** 1327 * The name of the <code>Action</code> that moves the caret to the beginning 1328 * of the document, possibly extending the current selection. 1329 * 1330 * @see #getActions() 1331 */ 1332 public static final String selectionBeginAction = "selection-begin"; 1333 1334 /** 1335 * The name of the <code>Action</code> that moves the caret to the beginning 1336 * of the current line, possibly extending the current selection. 1337 * 1338 * @see #getActions() 1339 */ 1340 public static final String selectionBeginLineAction = "selection-begin-line"; 1341 1342 /** 1343 * The name of the <code>Action</code> that moves the caret to the beginning 1344 * of the current paragraph, possibly extending the current selection. 1345 * 1346 * @see #getActions() 1347 */ 1348 public static final String selectionBeginParagraphAction = 1349 "selection-begin-paragraph"; 1350 1351 /** 1352 * The name of the <code>Action</code> that moves the caret to the beginning 1353 * of the current word, possibly extending the current selection. 1354 * 1355 * @see #getActions() 1356 */ 1357 public static final String selectionBeginWordAction = "selection-begin-word"; 1358 1359 /** 1360 * The name of the <code>Action</code> that moves the caret one line down, 1361 * possibly extending the current selection. 1362 * 1363 * @see #getActions() 1364 */ 1365 public static final String selectionDownAction = "selection-down"; 1366 1367 /** 1368 * The name of the <code>Action</code> that moves the caret to the end 1369 * of the document, possibly extending the current selection. 1370 * 1371 * @see #getActions() 1372 */ 1373 public static final String selectionEndAction = "selection-end"; 1374 1375 /** 1376 * The name of the <code>Action</code> that moves the caret to the end 1377 * of the current line, possibly extending the current selection. 1378 * 1379 * @see #getActions() 1380 */ 1381 public static final String selectionEndLineAction = "selection-end-line"; 1382 1383 /** 1384 * The name of the <code>Action</code> that moves the caret to the end 1385 * of the current paragraph, possibly extending the current selection. 1386 * 1387 * @see #getActions() 1388 */ 1389 public static final String selectionEndParagraphAction = 1390 "selection-end-paragraph"; 1391 1392 /** 1393 * The name of the <code>Action</code> that moves the caret to the end 1394 * of the current word, possibly extending the current selection. 1395 * 1396 * @see #getActions() 1397 */ 1398 public static final String selectionEndWordAction = "selection-end-word"; 1399 1400 /** 1401 * The name of the <code>Action</code> that moves the caret one character 1402 * forwards, possibly extending the current selection. 1403 * 1404 * @see #getActions() 1405 */ 1406 public static final String selectionForwardAction = "selection-forward"; 1407 1408 /** 1409 * The name of the <code>Action</code> that moves the caret to the beginning 1410 * of the next word, possibly extending the current selection. 1411 * 1412 * @see #getActions() 1413 */ 1414 public static final String selectionNextWordAction = "selection-next-word"; 1415 1416 /** 1417 * The name of the <code>Action</code> that moves the caret to the beginning 1418 * of the previous word, possibly extending the current selection. 1419 * 1420 * @see #getActions() 1421 */ 1422 public static final String selectionPreviousWordAction = 1423 "selection-previous-word"; 1424 1425 /** 1426 * The name of the <code>Action</code> that moves the caret one line up, 1427 * possibly extending the current selection. 1428 * 1429 * @see #getActions() 1430 */ 1431 public static final String selectionUpAction = "selection-up"; 1432 1433 /** 1434 * The name of the <code>Action</code> that selects the line around the 1435 * caret. 1436 * 1437 * @see #getActions() 1438 */ 1439 public static final String selectLineAction = "select-line"; 1440 1441 /** 1442 * The name of the <code>Action</code> that selects the paragraph around the 1443 * caret. 1444 * 1445 * @see #getActions() 1446 */ 1447 public static final String selectParagraphAction = "select-paragraph"; 1448 1449 /** 1450 * The name of the <code>Action</code> that selects the word around the 1451 * caret. 1452 * 1453 * @see #getActions() 1454 */ 1455 public static final String selectWordAction = "select-word"; 1456 1457 /** 1458 * The name of the <code>Action</code> that moves the caret one line up. 1459 * 1460 * @see #getActions() 1461 */ 1462 public static final String upAction = "caret-up"; 1463 1464 /** 1465 * The name of the <code>Action</code> that sets the editor in read-write 1466 * mode. 1467 * 1468 * @see #getActions() 1469 */ 1470 public static final String writableAction = "set-writable"; 1471 1472 /** 1473 * Creates a new <code>DefaultEditorKit</code>. 1474 */ DefaultEditorKit()1475 public DefaultEditorKit() 1476 { 1477 // Nothing to do here. 1478 } 1479 1480 /** 1481 * The <code>Action</code>s that are supported by the 1482 * <code>DefaultEditorKit</code>. 1483 */ 1484 private static Action[] defaultActions = 1485 new Action[] { 1486 // These classes are public because they are so in the RI. 1487 new BeepAction(), 1488 new CopyAction(), 1489 new CutAction(), 1490 new DefaultKeyTypedAction(), 1491 new InsertBreakAction(), 1492 new InsertContentAction(), 1493 new InsertTabAction(), 1494 new PasteAction(), 1495 1496 // These are (package-)private inner classes. 1497 new DeleteNextCharAction(), 1498 new DeletePrevCharAction(), 1499 1500 new BeginLineAction(), 1501 new SelectionBeginLineAction(), 1502 1503 new EndLineAction(), 1504 new SelectionEndLineAction(), 1505 1506 new BackwardAction(), 1507 new SelectionBackwardAction(), 1508 1509 new ForwardAction(), 1510 new SelectionForwardAction(), 1511 1512 new UpAction(), 1513 new SelectionUpAction(), 1514 1515 new DownAction(), 1516 new SelectionDownAction(), 1517 1518 new NextWordAction(), 1519 new SelectionNextWordAction(), 1520 1521 new PreviousWordAction(), 1522 new SelectionPreviousWordAction(), 1523 1524 new BeginAction(), 1525 new SelectionBeginAction(), 1526 1527 new EndAction(), 1528 new SelectionEndAction(), 1529 1530 new BeginWordAction(), 1531 new SelectionBeginWordAction(), 1532 1533 new EndWordAction(), 1534 new SelectionEndWordAction(), 1535 1536 new SelectAllAction(), 1537 new SelectLineAction(), 1538 new SelectWordAction() 1539 }; 1540 1541 /** 1542 * Creates the <code>Caret</code> for this <code>EditorKit</code>. This 1543 * returns a {@link DefaultCaret} in this case. 1544 * 1545 * @return the <code>Caret</code> for this <code>EditorKit</code> 1546 */ createCaret()1547 public Caret createCaret() 1548 { 1549 return new DefaultCaret(); 1550 } 1551 1552 /** 1553 * Creates the default {@link Document} that this <code>EditorKit</code> 1554 * supports. This is a {@link PlainDocument} in this case. 1555 * 1556 * @return the default {@link Document} that this <code>EditorKit</code> 1557 * supports 1558 */ createDefaultDocument()1559 public Document createDefaultDocument() 1560 { 1561 return new PlainDocument(); 1562 } 1563 1564 /** 1565 * Returns the <code>Action</code>s supported by this <code>EditorKit</code>. 1566 * 1567 * @return the <code>Action</code>s supported by this <code>EditorKit</code> 1568 */ getActions()1569 public Action[] getActions() 1570 { 1571 return defaultActions; 1572 } 1573 1574 /** 1575 * Returns the content type that this <code>EditorKit</code> supports. 1576 * The <code>DefaultEditorKit</code> supports the content type 1577 * <code>text/plain</code>. 1578 * 1579 * @return the content type that this <code>EditorKit</code> supports 1580 */ getContentType()1581 public String getContentType() 1582 { 1583 return "text/plain"; 1584 } 1585 1586 /** 1587 * Returns a {@link ViewFactory} that is able to create {@link View}s for 1588 * the <code>Element</code>s that are used in this <code>EditorKit</code>'s 1589 * model. This returns null which lets the UI of the text component supply 1590 * <code>View</code>s. 1591 * 1592 * @return a {@link ViewFactory} that is able to create {@link View}s for 1593 * the <code>Element</code>s that are used in this 1594 * <code>EditorKit</code>'s model 1595 */ getViewFactory()1596 public ViewFactory getViewFactory() 1597 { 1598 return null; 1599 } 1600 1601 /** 1602 * Reads a document of the supported content type from an {@link InputStream} 1603 * into the actual {@link Document} object. 1604 * 1605 * @param in the stream from which to read the document 1606 * @param document the document model into which the content is read 1607 * @param offset the offset inside to document where the content is inserted 1608 * 1609 * @throws BadLocationException if <code>offset</code> is an invalid location 1610 * inside <code>document</code> 1611 * @throws IOException if something goes wrong while reading from 1612 * <code>in</code> 1613 */ read(InputStream in, Document document, int offset)1614 public void read(InputStream in, Document document, int offset) 1615 throws BadLocationException, IOException 1616 { 1617 read(new InputStreamReader(in), document, offset); 1618 } 1619 1620 /** 1621 * Reads a document of the supported content type from a {@link Reader} 1622 * into the actual {@link Document} object. 1623 * 1624 * @param in the reader from which to read the document 1625 * @param document the document model into which the content is read 1626 * @param offset the offset inside to document where the content is inserted 1627 * 1628 * @throws BadLocationException if <code>offset</code> is an invalid location 1629 * inside <code>document</code> 1630 * @throws IOException if something goes wrong while reading from 1631 * <code>in</code> 1632 */ read(Reader in, Document document, int offset)1633 public void read(Reader in, Document document, int offset) 1634 throws BadLocationException, IOException 1635 { 1636 BufferedReader reader = new BufferedReader(in); 1637 1638 String line; 1639 CPStringBuilder content = new CPStringBuilder(); 1640 1641 while ((line = reader.readLine()) != null) 1642 { 1643 content.append(line); 1644 content.append("\n"); 1645 } 1646 1647 document.insertString(offset, content.substring(0, content.length() - 1), 1648 SimpleAttributeSet.EMPTY); 1649 } 1650 1651 /** 1652 * Writes the <code>Document</code> (or a fragment of the 1653 * <code>Document</code>) to an {@link OutputStream} in the 1654 * supported content type format. 1655 * 1656 * @param out the stream to write to 1657 * @param document the document that should be written out 1658 * @param offset the beginning offset from where to write 1659 * @param len the length of the fragment to write 1660 * 1661 * @throws BadLocationException if <code>offset</code> or 1662 * <code>offset + len</code>is an invalid location inside 1663 * <code>document</code> 1664 * @throws IOException if something goes wrong while writing to 1665 * <code>out</code> 1666 */ write(OutputStream out, Document document, int offset, int len)1667 public void write(OutputStream out, Document document, int offset, int len) 1668 throws BadLocationException, IOException 1669 { 1670 write(new OutputStreamWriter(out), document, offset, len); 1671 } 1672 1673 /** 1674 * Writes the <code>Document</code> (or a fragment of the 1675 * <code>Document</code>) to a {@link Writer} in the 1676 * supported content type format. 1677 * 1678 * @param out the writer to write to 1679 * @param document the document that should be written out 1680 * @param offset the beginning offset from where to write 1681 * @param len the length of the fragment to write 1682 * 1683 * @throws BadLocationException if <code>offset</code> is an 1684 * invalid location inside <code>document</code>. 1685 * @throws IOException if something goes wrong while writing to 1686 * <code>out</code> 1687 */ write(Writer out, Document document, int offset, int len)1688 public void write(Writer out, Document document, int offset, int len) 1689 throws BadLocationException, IOException 1690 { 1691 // Throw a BLE if offset is invalid 1692 if (offset < 0 || offset > document.getLength()) 1693 throw new BadLocationException("Tried to write to invalid location", 1694 offset); 1695 1696 // If they gave an overly large len, just adjust it 1697 if (offset + len > document.getLength()) 1698 len = document.getLength() - offset; 1699 1700 out.write(document.getText(offset, len)); 1701 } 1702 } 1703