1 /* 2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package javax.swing.text; 26 27 import sun.awt.SunToolkit; 28 29 import java.io.*; 30 import java.awt.*; 31 import java.awt.event.ActionEvent; 32 import java.text.*; 33 import javax.swing.Action; 34 import javax.swing.KeyStroke; 35 import javax.swing.SwingConstants; 36 import javax.swing.UIManager; 37 38 /** 39 * This is the set of things needed by a text component 40 * to be a reasonably functioning editor for some <em>type</em> 41 * of text document. This implementation provides a default 42 * implementation which treats text as plain text and 43 * provides a minimal set of actions for a simple editor. 44 * 45 * <dl> 46 * <dt><b>Newlines</b> 47 * <dd> 48 * There are two properties which deal with newlines. The 49 * system property, <code>line.separator</code>, is defined to be 50 * platform-dependent, either "\n", "\r", or "\r\n". There is also 51 * a property defined in <code>DefaultEditorKit</code>, called 52 * <a href=#EndOfLineStringProperty><code>EndOfLineStringProperty</code></a>, 53 * which is defined automatically when a document is loaded, to be 54 * the first occurrence of any of the newline characters. 55 * When a document is loaded, <code>EndOfLineStringProperty</code> 56 * is set appropriately, and when the document is written back out, the 57 * <code>EndOfLineStringProperty</code> is used. But while the document 58 * is in memory, the "\n" character is used to define a 59 * newline, regardless of how the newline is defined when 60 * the document is on disk. Therefore, for searching purposes, 61 * "\n" should always be used. When a new document is created, 62 * and the <code>EndOfLineStringProperty</code> has not been defined, 63 * it will use the System property when writing out the 64 * document. 65 * <p>Note that <code>EndOfLineStringProperty</code> is set 66 * on the <code>Document</code> using the <code>get/putProperty</code> 67 * methods. Subclasses may override this behavior. 68 * 69 * </dl> 70 * 71 * @author Timothy Prinzing 72 */ 73 public class DefaultEditorKit extends EditorKit { 74 75 /** 76 * default constructor for DefaultEditorKit 77 */ 78 public DefaultEditorKit() { 79 } 80 81 /** 82 * Gets the MIME type of the data that this 83 * kit represents support for. The default 84 * is <code>text/plain</code>. 85 * 86 * @return the type 87 */ 88 public String getContentType() { 89 return "text/plain"; 90 } 91 92 /** 93 * Fetches a factory that is suitable for producing 94 * views of any models that are produced by this 95 * kit. The default is to have the UI produce the 96 * factory, so this method has no implementation. 97 * 98 * @return the view factory 99 */ 100 public ViewFactory getViewFactory() { 101 return null; 102 } 103 104 /** 105 * Fetches the set of commands that can be used 106 * on a text component that is using a model and 107 * view produced by this kit. 108 * 109 * @return the command list 110 */ 111 public Action[] getActions() { 112 return defaultActions; 113 } 114 115 /** 116 * Fetches a caret that can navigate through views 117 * produced by the associated ViewFactory. 118 * 119 * @return the caret 120 */ 121 public Caret createCaret() { 122 return null; 123 } 124 125 /** 126 * Creates an uninitialized text storage model (PlainDocument) 127 * that is appropriate for this type of editor. 128 * 129 * @return the model 130 */ 131 public Document createDefaultDocument() { 132 return new PlainDocument(); 133 } 134 135 /** 136 * Inserts content from the given stream which is expected 137 * to be in a format appropriate for this kind of content 138 * handler. 139 * 140 * @param in The stream to read from 141 * @param doc The destination for the insertion. 142 * @param pos The location in the document to place the 143 * content >=0. 144 * @exception IOException on any I/O error 145 * @exception BadLocationException if pos represents an invalid 146 * location within the document. 147 */ 148 public void read(InputStream in, Document doc, int pos) 149 throws IOException, BadLocationException { 150 151 read(new InputStreamReader(in), doc, pos); 152 } 153 154 /** 155 * Writes content from a document to the given stream 156 * in a format appropriate for this kind of content handler. 157 * 158 * @param out The stream to write to 159 * @param doc The source for the write. 160 * @param pos The location in the document to fetch the 161 * content >=0. 162 * @param len The amount to write out >=0. 163 * @exception IOException on any I/O error 164 * @exception BadLocationException if pos represents an invalid 165 * location within the document. 166 */ 167 public void write(OutputStream out, Document doc, int pos, int len) 168 throws IOException, BadLocationException { 169 OutputStreamWriter osw = new OutputStreamWriter(out); 170 171 write(osw, doc, pos, len); 172 osw.flush(); 173 } 174 175 /** 176 * Gets the input attributes for the pane. This method exists for 177 * the benefit of StyledEditorKit so that the read method will 178 * pick up the correct attributes to apply to inserted text. 179 * This class's implementation simply returns null. 180 * 181 * @return null 182 */ 183 MutableAttributeSet getInputAttributes() { 184 return null; 185 } 186 187 /** 188 * Inserts content from the given stream, which will be 189 * treated as plain text. 190 * 191 * @param in The stream to read from 192 * @param doc The destination for the insertion. 193 * @param pos The location in the document to place the 194 * content >=0. 195 * @exception IOException on any I/O error 196 * @exception BadLocationException if pos represents an invalid 197 * location within the document. 198 */ 199 public void read(Reader in, Document doc, int pos) 200 throws IOException, BadLocationException { 201 202 char[] buff = new char[4096]; 203 int nch; 204 boolean lastWasCR = false; 205 boolean isCRLF = false; 206 boolean isCR = false; 207 int last; 208 boolean wasEmpty = (doc.getLength() == 0); 209 AttributeSet attr = getInputAttributes(); 210 211 // Read in a block at a time, mapping \r\n to \n, as well as single 212 // \r's to \n's. If a \r\n is encountered, \r\n will be set as the 213 // newline string for the document, if \r is encountered it will 214 // be set as the newline character, otherwise the newline property 215 // for the document will be removed. 216 while ((nch = in.read(buff, 0, buff.length)) != -1) { 217 last = 0; 218 for(int counter = 0; counter < nch; counter++) { 219 switch(buff[counter]) { 220 case '\r': 221 if (lastWasCR) { 222 isCR = true; 223 if (counter == 0) { 224 doc.insertString(pos, "\n", attr); 225 pos++; 226 } 227 else { 228 buff[counter - 1] = '\n'; 229 } 230 } 231 else { 232 lastWasCR = true; 233 } 234 break; 235 case '\n': 236 if (lastWasCR) { 237 if (counter > (last + 1)) { 238 doc.insertString(pos, new String(buff, last, 239 counter - last - 1), attr); 240 pos += (counter - last - 1); 241 } 242 // else nothing to do, can skip \r, next write will 243 // write \n 244 lastWasCR = false; 245 last = counter; 246 isCRLF = true; 247 } 248 break; 249 default: 250 if (lastWasCR) { 251 isCR = true; 252 if (counter == 0) { 253 doc.insertString(pos, "\n", attr); 254 pos++; 255 } 256 else { 257 buff[counter - 1] = '\n'; 258 } 259 lastWasCR = false; 260 } 261 break; 262 } 263 } 264 if (last < nch) { 265 if(lastWasCR) { 266 if (last < (nch - 1)) { 267 doc.insertString(pos, new String(buff, last, 268 nch - last - 1), attr); 269 pos += (nch - last - 1); 270 } 271 } 272 else { 273 doc.insertString(pos, new String(buff, last, 274 nch - last), attr); 275 pos += (nch - last); 276 } 277 } 278 } 279 if (lastWasCR) { 280 doc.insertString(pos, "\n", attr); 281 isCR = true; 282 } 283 if (wasEmpty) { 284 if (isCRLF) { 285 doc.putProperty(EndOfLineStringProperty, "\r\n"); 286 } 287 else if (isCR) { 288 doc.putProperty(EndOfLineStringProperty, "\r"); 289 } 290 else { 291 doc.putProperty(EndOfLineStringProperty, "\n"); 292 } 293 } 294 } 295 296 /** 297 * Writes content from a document to the given stream 298 * as plain text. 299 * 300 * @param out The stream to write to 301 * @param doc The source for the write. 302 * @param pos The location in the document to fetch the 303 * content from >=0. 304 * @param len The amount to write out >=0. 305 * @exception IOException on any I/O error 306 * @exception BadLocationException if pos is not within 0 and 307 * the length of the document. 308 */ 309 public void write(Writer out, Document doc, int pos, int len) 310 throws IOException, BadLocationException { 311 312 if ((pos < 0) || ((pos + len) > doc.getLength())) { 313 throw new BadLocationException("DefaultEditorKit.write", pos); 314 } 315 Segment data = new Segment(); 316 int nleft = len; 317 int offs = pos; 318 Object endOfLineProperty = doc.getProperty(EndOfLineStringProperty); 319 if (endOfLineProperty == null) { 320 endOfLineProperty = System.lineSeparator(); 321 } 322 String endOfLine; 323 if (endOfLineProperty instanceof String) { 324 endOfLine = (String)endOfLineProperty; 325 } 326 else { 327 endOfLine = null; 328 } 329 if (endOfLineProperty != null && !endOfLine.equals("\n")) { 330 // There is an end of line string that isn't \n, have to iterate 331 // through and find all \n's and translate to end of line string. 332 while (nleft > 0) { 333 int n = Math.min(nleft, 4096); 334 doc.getText(offs, n, data); 335 int last = data.offset; 336 char[] array = data.array; 337 int maxCounter = last + data.count; 338 for (int counter = last; counter < maxCounter; counter++) { 339 if (array[counter] == '\n') { 340 if (counter > last) { 341 out.write(array, last, counter - last); 342 } 343 out.write(endOfLine); 344 last = counter + 1; 345 } 346 } 347 if (maxCounter > last) { 348 out.write(array, last, maxCounter - last); 349 } 350 offs += n; 351 nleft -= n; 352 } 353 } 354 else { 355 // Just write out text, will already have \n, no mapping to 356 // do. 357 while (nleft > 0) { 358 int n = Math.min(nleft, 4096); 359 doc.getText(offs, n, data); 360 out.write(data.array, data.offset, data.count); 361 offs += n; 362 nleft -= n; 363 } 364 } 365 out.flush(); 366 } 367 368 369 /** 370 * When reading a document if a CRLF is encountered a property 371 * with this name is added and the value will be "\r\n". 372 */ 373 public static final String EndOfLineStringProperty = "__EndOfLine__"; 374 375 // --- names of well-known actions --------------------------- 376 377 /** 378 * Name of the action to place content into the associated 379 * document. If there is a selection, it is removed before 380 * the new content is added. 381 * @see #getActions 382 */ 383 public static final String insertContentAction = "insert-content"; 384 385 /** 386 * Name of the action to place a line/paragraph break into 387 * the document. If there is a selection, it is removed before 388 * the break is added. 389 * @see #getActions 390 */ 391 public static final String insertBreakAction = "insert-break"; 392 393 /** 394 * Name of the action to place a tab character into 395 * the document. If there is a selection, it is removed before 396 * the tab is added. 397 * @see #getActions 398 */ 399 public static final String insertTabAction = "insert-tab"; 400 401 /** 402 * Name of the action to delete the character of content that 403 * precedes the current caret position. 404 * @see #getActions 405 */ 406 public static final String deletePrevCharAction = "delete-previous"; 407 408 /** 409 * Name of the action to delete the character of content that 410 * follows the current caret position. 411 * @see #getActions 412 */ 413 public static final String deleteNextCharAction = "delete-next"; 414 415 /** 416 * Name of the action to delete the word that 417 * follows the beginning of the selection. 418 * @see #getActions 419 * @see JTextComponent#getSelectionStart 420 * @since 1.6 421 */ 422 public static final String deleteNextWordAction = "delete-next-word"; 423 424 /** 425 * Name of the action to delete the word that 426 * precedes the beginning of the selection. 427 * @see #getActions 428 * @see JTextComponent#getSelectionStart 429 * @since 1.6 430 */ 431 public static final String deletePrevWordAction = "delete-previous-word"; 432 433 /** 434 * Name of the action to set the editor into read-only 435 * mode. 436 * @see #getActions 437 */ 438 public static final String readOnlyAction = "set-read-only"; 439 440 /** 441 * Name of the action to set the editor into writeable 442 * mode. 443 * @see #getActions 444 */ 445 public static final String writableAction = "set-writable"; 446 447 /** 448 * Name of the action to cut the selected region 449 * and place the contents into the system clipboard. 450 * @see JTextComponent#cut 451 * @see #getActions 452 */ 453 public static final String cutAction = "cut-to-clipboard"; 454 455 /** 456 * Name of the action to copy the selected region 457 * and place the contents into the system clipboard. 458 * @see JTextComponent#copy 459 * @see #getActions 460 */ 461 public static final String copyAction = "copy-to-clipboard"; 462 463 /** 464 * Name of the action to paste the contents of the 465 * system clipboard into the selected region, or before the 466 * caret if nothing is selected. 467 * @see JTextComponent#paste 468 * @see #getActions 469 */ 470 public static final String pasteAction = "paste-from-clipboard"; 471 472 /** 473 * Name of the action to create a beep. 474 * @see #getActions 475 */ 476 public static final String beepAction = "beep"; 477 478 /** 479 * Name of the action to page up vertically. 480 * @see #getActions 481 */ 482 public static final String pageUpAction = "page-up"; 483 484 /** 485 * Name of the action to page down vertically. 486 * @see #getActions 487 */ 488 public static final String pageDownAction = "page-down"; 489 490 /** 491 * Name of the action to page up vertically, and move the 492 * selection. 493 * @see #getActions 494 */ 495 /*public*/ static final String selectionPageUpAction = "selection-page-up"; 496 497 /** 498 * Name of the action to page down vertically, and move the 499 * selection. 500 * @see #getActions 501 */ 502 /*public*/ static final String selectionPageDownAction = "selection-page-down"; 503 504 /** 505 * Name of the action to page left horizontally, and move the 506 * selection. 507 * @see #getActions 508 */ 509 /*public*/ static final String selectionPageLeftAction = "selection-page-left"; 510 511 /** 512 * Name of the action to page right horizontally, and move the 513 * selection. 514 * @see #getActions 515 */ 516 /*public*/ static final String selectionPageRightAction = "selection-page-right"; 517 518 /** 519 * Name of the Action for moving the caret 520 * logically forward one position. 521 * @see #getActions 522 */ 523 public static final String forwardAction = "caret-forward"; 524 525 /** 526 * Name of the Action for moving the caret 527 * logically backward one position. 528 * @see #getActions 529 */ 530 public static final String backwardAction = "caret-backward"; 531 532 /** 533 * Name of the Action for extending the selection 534 * by moving the caret logically forward one position. 535 * @see #getActions 536 */ 537 public static final String selectionForwardAction = "selection-forward"; 538 539 /** 540 * Name of the Action for extending the selection 541 * by moving the caret logically backward one position. 542 * @see #getActions 543 */ 544 public static final String selectionBackwardAction = "selection-backward"; 545 546 /** 547 * Name of the Action for moving the caret 548 * logically upward one position. 549 * @see #getActions 550 */ 551 public static final String upAction = "caret-up"; 552 553 /** 554 * Name of the Action for moving the caret 555 * logically downward one position. 556 * @see #getActions 557 */ 558 public static final String downAction = "caret-down"; 559 560 /** 561 * Name of the Action for moving the caret 562 * logically upward one position, extending the selection. 563 * @see #getActions 564 */ 565 public static final String selectionUpAction = "selection-up"; 566 567 /** 568 * Name of the Action for moving the caret 569 * logically downward one position, extending the selection. 570 * @see #getActions 571 */ 572 public static final String selectionDownAction = "selection-down"; 573 574 /** 575 * Name of the <code>Action</code> for moving the caret 576 * to the beginning of a word. 577 * @see #getActions 578 */ 579 public static final String beginWordAction = "caret-begin-word"; 580 581 /** 582 * Name of the Action for moving the caret 583 * to the end of a word. 584 * @see #getActions 585 */ 586 public static final String endWordAction = "caret-end-word"; 587 588 /** 589 * Name of the <code>Action</code> for moving the caret 590 * to the beginning of a word, extending the selection. 591 * @see #getActions 592 */ 593 public static final String selectionBeginWordAction = "selection-begin-word"; 594 595 /** 596 * Name of the Action for moving the caret 597 * to the end of a word, extending the selection. 598 * @see #getActions 599 */ 600 public static final String selectionEndWordAction = "selection-end-word"; 601 602 /** 603 * Name of the <code>Action</code> for moving the caret to the 604 * beginning of the previous word. 605 * @see #getActions 606 */ 607 public static final String previousWordAction = "caret-previous-word"; 608 609 /** 610 * Name of the <code>Action</code> for moving the caret to the 611 * beginning of the next word. 612 * @see #getActions 613 */ 614 public static final String nextWordAction = "caret-next-word"; 615 616 /** 617 * Name of the <code>Action</code> for moving the selection to the 618 * beginning of the previous word, extending the selection. 619 * @see #getActions 620 */ 621 public static final String selectionPreviousWordAction = "selection-previous-word"; 622 623 /** 624 * Name of the <code>Action</code> for moving the selection to the 625 * beginning of the next word, extending the selection. 626 * @see #getActions 627 */ 628 public static final String selectionNextWordAction = "selection-next-word"; 629 630 /** 631 * Name of the <code>Action</code> for moving the caret 632 * to the beginning of a line. 633 * @see #getActions 634 */ 635 public static final String beginLineAction = "caret-begin-line"; 636 637 /** 638 * Name of the <code>Action</code> for moving the caret 639 * to the end of a line. 640 * @see #getActions 641 */ 642 public static final String endLineAction = "caret-end-line"; 643 644 /** 645 * Name of the <code>Action</code> for moving the caret 646 * to the beginning of a line, extending the selection. 647 * @see #getActions 648 */ 649 public static final String selectionBeginLineAction = "selection-begin-line"; 650 651 /** 652 * Name of the <code>Action</code> for moving the caret 653 * to the end of a line, extending the selection. 654 * @see #getActions 655 */ 656 public static final String selectionEndLineAction = "selection-end-line"; 657 658 /** 659 * Name of the <code>Action</code> for moving the caret 660 * to the beginning of a paragraph. 661 * @see #getActions 662 */ 663 public static final String beginParagraphAction = "caret-begin-paragraph"; 664 665 /** 666 * Name of the <code>Action</code> for moving the caret 667 * to the end of a paragraph. 668 * @see #getActions 669 */ 670 public static final String endParagraphAction = "caret-end-paragraph"; 671 672 /** 673 * Name of the <code>Action</code> for moving the caret 674 * to the beginning of a paragraph, extending the selection. 675 * @see #getActions 676 */ 677 public static final String selectionBeginParagraphAction = "selection-begin-paragraph"; 678 679 /** 680 * Name of the <code>Action</code> for moving the caret 681 * to the end of a paragraph, extending the selection. 682 * @see #getActions 683 */ 684 public static final String selectionEndParagraphAction = "selection-end-paragraph"; 685 686 /** 687 * Name of the <code>Action</code> for moving the caret 688 * to the beginning of the document. 689 * @see #getActions 690 */ 691 public static final String beginAction = "caret-begin"; 692 693 /** 694 * Name of the <code>Action</code> for moving the caret 695 * to the end of the document. 696 * @see #getActions 697 */ 698 public static final String endAction = "caret-end"; 699 700 /** 701 * Name of the <code>Action</code> for moving the caret 702 * to the beginning of the document. 703 * @see #getActions 704 */ 705 public static final String selectionBeginAction = "selection-begin"; 706 707 /** 708 * Name of the Action for moving the caret 709 * to the end of the document. 710 * @see #getActions 711 */ 712 public static final String selectionEndAction = "selection-end"; 713 714 /** 715 * Name of the Action for selecting a word around the caret. 716 * @see #getActions 717 */ 718 public static final String selectWordAction = "select-word"; 719 720 /** 721 * Name of the Action for selecting a line around the caret. 722 * @see #getActions 723 */ 724 public static final String selectLineAction = "select-line"; 725 726 /** 727 * Name of the Action for selecting a paragraph around the caret. 728 * @see #getActions 729 */ 730 public static final String selectParagraphAction = "select-paragraph"; 731 732 /** 733 * Name of the Action for selecting the entire document 734 * @see #getActions 735 */ 736 public static final String selectAllAction = "select-all"; 737 738 /** 739 * Name of the Action for removing selection 740 * @see #getActions 741 */ 742 /*public*/ static final String unselectAction = "unselect"; 743 744 /** 745 * Name of the Action for toggling the component's orientation. 746 * @see #getActions 747 */ 748 /*public*/ static final String toggleComponentOrientationAction 749 = "toggle-componentOrientation"; 750 751 /** 752 * Name of the action that is executed by default if 753 * a <em>key typed event</em> is received and there 754 * is no keymap entry. 755 * @see #getActions 756 */ 757 public static final String defaultKeyTypedAction = "default-typed"; 758 759 // --- Action implementations --------------------------------- 760 761 private static final Action[] defaultActions = { 762 new InsertContentAction(), new DeletePrevCharAction(), 763 new DeleteNextCharAction(), new ReadOnlyAction(), 764 new DeleteWordAction(deletePrevWordAction), 765 new DeleteWordAction(deleteNextWordAction), 766 new WritableAction(), new CutAction(), 767 new CopyAction(), new PasteAction(), 768 new VerticalPageAction(pageUpAction, -1, false), 769 new VerticalPageAction(pageDownAction, 1, false), 770 new VerticalPageAction(selectionPageUpAction, -1, true), 771 new VerticalPageAction(selectionPageDownAction, 1, true), 772 new PageAction(selectionPageLeftAction, true, true), 773 new PageAction(selectionPageRightAction, false, true), 774 new InsertBreakAction(), new BeepAction(), 775 new NextVisualPositionAction(forwardAction, false, 776 SwingConstants.EAST), 777 new NextVisualPositionAction(backwardAction, false, 778 SwingConstants.WEST), 779 new NextVisualPositionAction(selectionForwardAction, true, 780 SwingConstants.EAST), 781 new NextVisualPositionAction(selectionBackwardAction, true, 782 SwingConstants.WEST), 783 new NextVisualPositionAction(upAction, false, 784 SwingConstants.NORTH), 785 new NextVisualPositionAction(downAction, false, 786 SwingConstants.SOUTH), 787 new NextVisualPositionAction(selectionUpAction, true, 788 SwingConstants.NORTH), 789 new NextVisualPositionAction(selectionDownAction, true, 790 SwingConstants.SOUTH), 791 new BeginWordAction(beginWordAction, false), 792 new EndWordAction(endWordAction, false), 793 new BeginWordAction(selectionBeginWordAction, true), 794 new EndWordAction(selectionEndWordAction, true), 795 new PreviousWordAction(previousWordAction, false), 796 new NextWordAction(nextWordAction, false), 797 new PreviousWordAction(selectionPreviousWordAction, true), 798 new NextWordAction(selectionNextWordAction, true), 799 new BeginLineAction(beginLineAction, false), 800 new EndLineAction(endLineAction, false), 801 new BeginLineAction(selectionBeginLineAction, true), 802 new EndLineAction(selectionEndLineAction, true), 803 new BeginParagraphAction(beginParagraphAction, false), 804 new EndParagraphAction(endParagraphAction, false), 805 new BeginParagraphAction(selectionBeginParagraphAction, true), 806 new EndParagraphAction(selectionEndParagraphAction, true), 807 new BeginAction(beginAction, false), 808 new EndAction(endAction, false), 809 new BeginAction(selectionBeginAction, true), 810 new EndAction(selectionEndAction, true), 811 new DefaultKeyTypedAction(), new InsertTabAction(), 812 new SelectWordAction(), new SelectLineAction(), 813 new SelectParagraphAction(), new SelectAllAction(), 814 new UnselectAction(), new ToggleComponentOrientationAction(), 815 new DumpModelAction() 816 }; 817 818 /** 819 * The action that is executed by default if 820 * a <em>key typed event</em> is received and there 821 * is no keymap entry. There is a variation across 822 * different VM's in what gets sent as a <em>key typed</em> 823 * event, and this action tries to filter out the undesired 824 * events. This filters the control characters and those 825 * with the ALT modifier. It allows Control-Alt sequences 826 * through as these form legitimate unicode characters on 827 * some PC keyboards. 828 * <p> 829 * If the event doesn't get filtered, it will try to insert 830 * content into the text editor. The content is fetched 831 * from the command string of the ActionEvent. The text 832 * entry is done through the <code>replaceSelection</code> 833 * method on the target text component. This is the 834 * action that will be fired for most text entry tasks. 835 * <p> 836 * <strong>Warning:</strong> 837 * Serialized objects of this class will not be compatible with 838 * future Swing releases. The current serialization support is 839 * appropriate for short term storage or RMI between applications running 840 * the same version of Swing. As of 1.4, support for long term storage 841 * of all JavaBeans™ 842 * has been added to the <code>java.beans</code> package. 843 * Please see {@link java.beans.XMLEncoder}. 844 * 845 * @see DefaultEditorKit#defaultKeyTypedAction 846 * @see DefaultEditorKit#getActions 847 * @see Keymap#setDefaultAction 848 * @see Keymap#getDefaultAction 849 */ 850 @SuppressWarnings("serial") // Same-version serialization only 851 public static class DefaultKeyTypedAction extends TextAction { 852 853 /** 854 * Creates this object with the appropriate identifier. 855 */ 856 public DefaultKeyTypedAction() { 857 super(defaultKeyTypedAction); 858 } 859 860 /** 861 * The operation to perform when this action is triggered. 862 * 863 * @param e the action event 864 */ 865 public void actionPerformed(ActionEvent e) { 866 JTextComponent target = getTextComponent(e); 867 if ((target != null) && (e != null)) { 868 if ((! target.isEditable()) || (! target.isEnabled())) { 869 return; 870 } 871 String content = e.getActionCommand(); 872 int mod = e.getModifiers(); 873 if ((content != null) && (content.length() > 0)) { 874 boolean isPrintableMask = true; 875 Toolkit tk = Toolkit.getDefaultToolkit(); 876 if (tk instanceof SunToolkit) { 877 isPrintableMask = ((SunToolkit)tk).isPrintableCharacterModifiersMask(mod); 878 } 879 880 if (isPrintableMask) { 881 char c = content.charAt(0); 882 if ((c >= 0x20) && (c != 0x7F)) { 883 target.replaceSelection(content); 884 } 885 } 886 } 887 } 888 } 889 } 890 891 /** 892 * Places content into the associated document. 893 * If there is a selection, it is removed before 894 * the new content is added. 895 * <p> 896 * <strong>Warning:</strong> 897 * Serialized objects of this class will not be compatible with 898 * future Swing releases. The current serialization support is 899 * appropriate for short term storage or RMI between applications running 900 * the same version of Swing. As of 1.4, support for long term storage 901 * of all JavaBeans™ 902 * has been added to the <code>java.beans</code> package. 903 * Please see {@link java.beans.XMLEncoder}. 904 * 905 * @see DefaultEditorKit#insertContentAction 906 * @see DefaultEditorKit#getActions 907 */ 908 @SuppressWarnings("serial") // Same-version serialization only 909 public static class InsertContentAction extends TextAction { 910 911 /** 912 * Creates this object with the appropriate identifier. 913 */ 914 public InsertContentAction() { 915 super(insertContentAction); 916 } 917 918 /** 919 * The operation to perform when this action is triggered. 920 * 921 * @param e the action event 922 */ 923 public void actionPerformed(ActionEvent e) { 924 JTextComponent target = getTextComponent(e); 925 if ((target != null) && (e != null)) { 926 if ((! target.isEditable()) || (! target.isEnabled())) { 927 UIManager.getLookAndFeel().provideErrorFeedback(target); 928 return; 929 } 930 String content = e.getActionCommand(); 931 if (content != null) { 932 target.replaceSelection(content); 933 } else { 934 UIManager.getLookAndFeel().provideErrorFeedback(target); 935 } 936 } 937 } 938 } 939 940 /** 941 * Places a line/paragraph break into the document. 942 * If there is a selection, it is removed before 943 * the break is added. 944 * <p> 945 * <strong>Warning:</strong> 946 * Serialized objects of this class will not be compatible with 947 * future Swing releases. The current serialization support is 948 * appropriate for short term storage or RMI between applications running 949 * the same version of Swing. As of 1.4, support for long term storage 950 * of all JavaBeans™ 951 * has been added to the <code>java.beans</code> package. 952 * Please see {@link java.beans.XMLEncoder}. 953 * 954 * @see DefaultEditorKit#insertBreakAction 955 * @see DefaultEditorKit#getActions 956 */ 957 @SuppressWarnings("serial") // Same-version serialization only 958 public static class InsertBreakAction extends TextAction { 959 960 /** 961 * Creates this object with the appropriate identifier. 962 */ 963 public InsertBreakAction() { 964 super(insertBreakAction); 965 } 966 967 /** 968 * The operation to perform when this action is triggered. 969 * 970 * @param e the action event 971 */ 972 public void actionPerformed(ActionEvent e) { 973 JTextComponent target = getTextComponent(e); 974 if (target != null) { 975 if ((! target.isEditable()) || (! target.isEnabled())) { 976 UIManager.getLookAndFeel().provideErrorFeedback(target); 977 return; 978 } 979 target.replaceSelection("\n"); 980 } 981 } 982 } 983 984 /** 985 * Places a tab character into the document. If there 986 * is a selection, it is removed before the tab is added. 987 * <p> 988 * <strong>Warning:</strong> 989 * Serialized objects of this class will not be compatible with 990 * future Swing releases. The current serialization support is 991 * appropriate for short term storage or RMI between applications running 992 * the same version of Swing. As of 1.4, support for long term storage 993 * of all JavaBeans™ 994 * has been added to the <code>java.beans</code> package. 995 * Please see {@link java.beans.XMLEncoder}. 996 * 997 * @see DefaultEditorKit#insertTabAction 998 * @see DefaultEditorKit#getActions 999 */ 1000 @SuppressWarnings("serial") // Same-version serialization only 1001 public static class InsertTabAction extends TextAction { 1002 1003 /** 1004 * Creates this object with the appropriate identifier. 1005 */ 1006 public InsertTabAction() { 1007 super(insertTabAction); 1008 } 1009 1010 /** 1011 * The operation to perform when this action is triggered. 1012 * 1013 * @param e the action event 1014 */ 1015 public void actionPerformed(ActionEvent e) { 1016 JTextComponent target = getTextComponent(e); 1017 if (target != null) { 1018 if ((! target.isEditable()) || (! target.isEnabled())) { 1019 UIManager.getLookAndFeel().provideErrorFeedback(target); 1020 return; 1021 } 1022 target.replaceSelection("\t"); 1023 } 1024 } 1025 } 1026 1027 /* 1028 * Deletes the character of content that precedes the 1029 * current caret position. 1030 * @see DefaultEditorKit#deletePrevCharAction 1031 * @see DefaultEditorKit#getActions 1032 */ 1033 static class DeletePrevCharAction extends TextAction { 1034 1035 /** 1036 * Creates this object with the appropriate identifier. 1037 */ 1038 DeletePrevCharAction() { 1039 super(deletePrevCharAction); 1040 } 1041 1042 /** 1043 * The operation to perform when this action is triggered. 1044 * 1045 * @param e the action event 1046 */ 1047 public void actionPerformed(ActionEvent e) { 1048 JTextComponent target = getTextComponent(e); 1049 boolean beep = true; 1050 if ((target != null) && (target.isEditable())) { 1051 try { 1052 Document doc = target.getDocument(); 1053 Caret caret = target.getCaret(); 1054 int dot = caret.getDot(); 1055 int mark = caret.getMark(); 1056 if (dot != mark) { 1057 doc.remove(Math.min(dot, mark), Math.abs(dot - mark)); 1058 beep = false; 1059 } else if (dot > 0) { 1060 int delChars = 1; 1061 1062 if (dot > 1) { 1063 String dotChars = doc.getText(dot - 2, 2); 1064 char c0 = dotChars.charAt(0); 1065 char c1 = dotChars.charAt(1); 1066 1067 if (c0 >= '\uD800' && c0 <= '\uDBFF' && 1068 c1 >= '\uDC00' && c1 <= '\uDFFF') { 1069 delChars = 2; 1070 } 1071 } 1072 1073 doc.remove(dot - delChars, delChars); 1074 beep = false; 1075 } 1076 } catch (BadLocationException bl) { 1077 } 1078 } 1079 if (beep) { 1080 UIManager.getLookAndFeel().provideErrorFeedback(target); 1081 } 1082 } 1083 } 1084 1085 /* 1086 * Deletes the character of content that follows the 1087 * current caret position. 1088 * @see DefaultEditorKit#deleteNextCharAction 1089 * @see DefaultEditorKit#getActions 1090 */ 1091 static class DeleteNextCharAction extends TextAction { 1092 1093 /* Create this object with the appropriate identifier. */ 1094 DeleteNextCharAction() { 1095 super(deleteNextCharAction); 1096 } 1097 1098 /** The operation to perform when this action is triggered. */ 1099 public void actionPerformed(ActionEvent e) { 1100 JTextComponent target = getTextComponent(e); 1101 boolean beep = true; 1102 if ((target != null) && (target.isEditable())) { 1103 try { 1104 Document doc = target.getDocument(); 1105 Caret caret = target.getCaret(); 1106 int dot = caret.getDot(); 1107 int mark = caret.getMark(); 1108 if (dot != mark) { 1109 doc.remove(Math.min(dot, mark), Math.abs(dot - mark)); 1110 beep = false; 1111 } else if (dot < doc.getLength()) { 1112 int delChars = 1; 1113 1114 if (dot < doc.getLength() - 1) { 1115 String dotChars = doc.getText(dot, 2); 1116 char c0 = dotChars.charAt(0); 1117 char c1 = dotChars.charAt(1); 1118 1119 if (c0 >= '\uD800' && c0 <= '\uDBFF' && 1120 c1 >= '\uDC00' && c1 <= '\uDFFF') { 1121 delChars = 2; 1122 } 1123 } 1124 1125 doc.remove(dot, delChars); 1126 beep = false; 1127 } 1128 } catch (BadLocationException bl) { 1129 } 1130 } 1131 if (beep) { 1132 UIManager.getLookAndFeel().provideErrorFeedback(target); 1133 } 1134 } 1135 } 1136 1137 1138 /* 1139 * Deletes the word that precedes/follows the beginning of the selection. 1140 * @see DefaultEditorKit#getActions 1141 */ 1142 static class DeleteWordAction extends TextAction { 1143 DeleteWordAction(String name) { 1144 super(name); 1145 assert (name == deletePrevWordAction) 1146 || (name == deleteNextWordAction); 1147 } 1148 /** 1149 * The operation to perform when this action is triggered. 1150 * 1151 * @param e the action event 1152 */ 1153 public void actionPerformed(ActionEvent e) { 1154 final JTextComponent target = getTextComponent(e); 1155 if ((target != null) && (e != null)) { 1156 if ((! target.isEditable()) || (! target.isEnabled())) { 1157 UIManager.getLookAndFeel().provideErrorFeedback(target); 1158 return; 1159 } 1160 boolean beep = true; 1161 try { 1162 final int start = target.getSelectionStart(); 1163 final Element line = 1164 Utilities.getParagraphElement(target, start); 1165 int end; 1166 if (deleteNextWordAction == getValue(Action.NAME)) { 1167 end = Utilities. 1168 getNextWordInParagraph(target, line, start, false); 1169 if (end == java.text.BreakIterator.DONE) { 1170 //last word in the paragraph 1171 final int endOfLine = line.getEndOffset(); 1172 if (start == endOfLine - 1) { 1173 //for last position remove last \n 1174 end = endOfLine; 1175 } else { 1176 //remove to the end of the paragraph 1177 end = endOfLine - 1; 1178 } 1179 } 1180 } else { 1181 end = Utilities. 1182 getPrevWordInParagraph(target, line, start); 1183 if (end == java.text.BreakIterator.DONE) { 1184 //there is no previous word in the paragraph 1185 final int startOfLine = line.getStartOffset(); 1186 if (start == startOfLine) { 1187 //for first position remove previous \n 1188 end = startOfLine - 1; 1189 } else { 1190 //remove to the start of the paragraph 1191 end = startOfLine; 1192 } 1193 } 1194 } 1195 int offs = Math.min(start, end); 1196 int len = Math.abs(end - start); 1197 if (offs >= 0) { 1198 target.getDocument().remove(offs, len); 1199 beep = false; 1200 } 1201 } catch (BadLocationException ignore) { 1202 } 1203 if (beep) { 1204 UIManager.getLookAndFeel().provideErrorFeedback(target); 1205 } 1206 } 1207 } 1208 } 1209 1210 1211 /* 1212 * Sets the editor into read-only mode. 1213 * @see DefaultEditorKit#readOnlyAction 1214 * @see DefaultEditorKit#getActions 1215 */ 1216 static class ReadOnlyAction extends TextAction { 1217 1218 /* Create this object with the appropriate identifier. */ 1219 ReadOnlyAction() { 1220 super(readOnlyAction); 1221 } 1222 1223 /** 1224 * The operation to perform when this action is triggered. 1225 * 1226 * @param e the action event 1227 */ 1228 public void actionPerformed(ActionEvent e) { 1229 JTextComponent target = getTextComponent(e); 1230 if (target != null) { 1231 target.setEditable(false); 1232 } 1233 } 1234 } 1235 1236 /* 1237 * Sets the editor into writeable mode. 1238 * @see DefaultEditorKit#writableAction 1239 * @see DefaultEditorKit#getActions 1240 */ 1241 static class WritableAction extends TextAction { 1242 1243 /* Create this object with the appropriate identifier. */ 1244 WritableAction() { 1245 super(writableAction); 1246 } 1247 1248 /** 1249 * The operation to perform when this action is triggered. 1250 * 1251 * @param e the action event 1252 */ 1253 public void actionPerformed(ActionEvent e) { 1254 JTextComponent target = getTextComponent(e); 1255 if (target != null) { 1256 target.setEditable(true); 1257 } 1258 } 1259 } 1260 1261 /** 1262 * Cuts the selected region and place its contents 1263 * into the system clipboard. 1264 * <p> 1265 * <strong>Warning:</strong> 1266 * Serialized objects of this class will not be compatible with 1267 * future Swing releases. The current serialization support is 1268 * appropriate for short term storage or RMI between applications running 1269 * the same version of Swing. As of 1.4, support for long term storage 1270 * of all JavaBeans™ 1271 * has been added to the <code>java.beans</code> package. 1272 * Please see {@link java.beans.XMLEncoder}. 1273 * 1274 * @see DefaultEditorKit#cutAction 1275 * @see DefaultEditorKit#getActions 1276 */ 1277 @SuppressWarnings("serial") // Same-version serialization only 1278 public static class CutAction extends TextAction { 1279 1280 /** Create this object with the appropriate identifier. */ 1281 public CutAction() { 1282 super(cutAction); 1283 } 1284 1285 /** 1286 * The operation to perform when this action is triggered. 1287 * 1288 * @param e the action event 1289 */ 1290 public void actionPerformed(ActionEvent e) { 1291 JTextComponent target = getTextComponent(e); 1292 if (target != null) { 1293 target.cut(); 1294 } 1295 } 1296 } 1297 1298 /** 1299 * Copies the selected region and place its contents 1300 * into the system clipboard. 1301 * <p> 1302 * <strong>Warning:</strong> 1303 * Serialized objects of this class will not be compatible with 1304 * future Swing releases. The current serialization support is 1305 * appropriate for short term storage or RMI between applications running 1306 * the same version of Swing. As of 1.4, support for long term storage 1307 * of all JavaBeans™ 1308 * has been added to the <code>java.beans</code> package. 1309 * Please see {@link java.beans.XMLEncoder}. 1310 * 1311 * @see DefaultEditorKit#copyAction 1312 * @see DefaultEditorKit#getActions 1313 */ 1314 @SuppressWarnings("serial") // Same-version serialization only 1315 public static class CopyAction extends TextAction { 1316 1317 /** Create this object with the appropriate identifier. */ 1318 public CopyAction() { 1319 super(copyAction); 1320 } 1321 1322 /** 1323 * The operation to perform when this action is triggered. 1324 * 1325 * @param e the action event 1326 */ 1327 public void actionPerformed(ActionEvent e) { 1328 JTextComponent target = getTextComponent(e); 1329 if (target != null) { 1330 target.copy(); 1331 } 1332 } 1333 } 1334 1335 /** 1336 * Pastes the contents of the system clipboard into the 1337 * selected region, or before the caret if nothing is 1338 * selected. 1339 * <p> 1340 * <strong>Warning:</strong> 1341 * Serialized objects of this class will not be compatible with 1342 * future Swing releases. The current serialization support is 1343 * appropriate for short term storage or RMI between applications running 1344 * the same version of Swing. As of 1.4, support for long term storage 1345 * of all JavaBeans™ 1346 * has been added to the <code>java.beans</code> package. 1347 * Please see {@link java.beans.XMLEncoder}. 1348 * 1349 * @see DefaultEditorKit#pasteAction 1350 * @see DefaultEditorKit#getActions 1351 */ 1352 @SuppressWarnings("serial") // Same-version serialization only 1353 public static class PasteAction extends TextAction { 1354 1355 /** Create this object with the appropriate identifier. */ 1356 public PasteAction() { 1357 super(pasteAction); 1358 } 1359 1360 /** 1361 * The operation to perform when this action is triggered. 1362 * 1363 * @param e the action event 1364 */ 1365 public void actionPerformed(ActionEvent e) { 1366 JTextComponent target = getTextComponent(e); 1367 if (target != null) { 1368 target.paste(); 1369 } 1370 } 1371 } 1372 1373 /** 1374 * Creates a beep. 1375 * <p> 1376 * <strong>Warning:</strong> 1377 * Serialized objects of this class will not be compatible with 1378 * future Swing releases. The current serialization support is 1379 * appropriate for short term storage or RMI between applications running 1380 * the same version of Swing. As of 1.4, support for long term storage 1381 * of all JavaBeans™ 1382 * has been added to the <code>java.beans</code> package. 1383 * Please see {@link java.beans.XMLEncoder}. 1384 * 1385 * @see DefaultEditorKit#beepAction 1386 * @see DefaultEditorKit#getActions 1387 */ 1388 @SuppressWarnings("serial") // Same-version serialization only 1389 public static class BeepAction extends TextAction { 1390 1391 /** Create this object with the appropriate identifier. */ 1392 public BeepAction() { 1393 super(beepAction); 1394 } 1395 1396 /** 1397 * The operation to perform when this action is triggered. 1398 * 1399 * @param e the action event 1400 */ 1401 public void actionPerformed(ActionEvent e) { 1402 JTextComponent target = getTextComponent(e); 1403 UIManager.getLookAndFeel().provideErrorFeedback(target); 1404 } 1405 } 1406 1407 /** 1408 * Scrolls up/down vertically. The select version of this action extends 1409 * the selection, instead of simply moving the caret. 1410 * 1411 * @see DefaultEditorKit#pageUpAction 1412 * @see DefaultEditorKit#pageDownAction 1413 * @see DefaultEditorKit#getActions 1414 */ 1415 static class VerticalPageAction extends TextAction { 1416 1417 /** Create this object with the appropriate identifier. */ 1418 public VerticalPageAction(String nm, int direction, boolean select) { 1419 super(nm); 1420 this.select = select; 1421 this.direction = direction; 1422 } 1423 1424 /** The operation to perform when this action is triggered. */ 1425 public void actionPerformed(ActionEvent e) { 1426 JTextComponent target = getTextComponent(e); 1427 if (target != null) { 1428 Rectangle visible = target.getVisibleRect(); 1429 Rectangle newVis = new Rectangle(visible); 1430 int selectedIndex = target.getCaretPosition(); 1431 int scrollAmount = direction * 1432 target.getScrollableBlockIncrement( 1433 visible, SwingConstants.VERTICAL, direction); 1434 int initialY = visible.y; 1435 Caret caret = target.getCaret(); 1436 Point magicPosition = caret.getMagicCaretPosition(); 1437 1438 if (selectedIndex != -1) { 1439 try { 1440 Rectangle dotBounds = target.modelToView( 1441 selectedIndex); 1442 int x = (magicPosition != null) ? magicPosition.x : 1443 dotBounds.x; 1444 int h = dotBounds.height; 1445 if (h > 0) { 1446 // We want to scroll by a multiple of caret height, 1447 // rounding towards lower integer 1448 scrollAmount = scrollAmount / h * h; 1449 } 1450 newVis.y = constrainY(target, 1451 initialY + scrollAmount, visible.height); 1452 1453 int newIndex; 1454 1455 if (visible.contains(dotBounds.x, dotBounds.y)) { 1456 // Dot is currently visible, base the new 1457 // location off the old, or 1458 newIndex = target.viewToModel( 1459 new Point(x, constrainY(target, 1460 dotBounds.y + scrollAmount, 0))); 1461 } 1462 else { 1463 // Dot isn't visible, choose the top or the bottom 1464 // for the new location. 1465 if (direction == -1) { 1466 newIndex = target.viewToModel(new Point( 1467 x, newVis.y)); 1468 } 1469 else { 1470 newIndex = target.viewToModel(new Point( 1471 x, newVis.y + visible.height)); 1472 } 1473 } 1474 newIndex = constrainOffset(target, newIndex); 1475 if (newIndex != selectedIndex) { 1476 // Make sure the new visible location contains 1477 // the location of dot, otherwise Caret will 1478 // cause an additional scroll. 1479 int newY = getAdjustedY(target, newVis, newIndex); 1480 1481 if (direction == -1 && newY <= initialY || direction == 1 && newY >= initialY) { 1482 // Change index and correct newVis.y only if won't cause scrolling upward 1483 newVis.y = newY; 1484 1485 if (select) { 1486 target.moveCaretPosition(newIndex); 1487 } else { 1488 target.setCaretPosition(newIndex); 1489 } 1490 } 1491 } 1492 } catch (BadLocationException ble) { } 1493 } else { 1494 newVis.y = constrainY(target, 1495 initialY + scrollAmount, visible.height); 1496 } 1497 if (magicPosition != null) { 1498 caret.setMagicCaretPosition(magicPosition); 1499 } 1500 target.scrollRectToVisible(newVis); 1501 } 1502 } 1503 1504 /** 1505 * Makes sure <code>y</code> is a valid location in 1506 * <code>target</code>. 1507 */ 1508 private int constrainY(JTextComponent target, int y, int vis) { 1509 if (y < 0) { 1510 y = 0; 1511 } 1512 else if (y + vis > target.getHeight()) { 1513 y = Math.max(0, target.getHeight() - vis); 1514 } 1515 return y; 1516 } 1517 1518 /** 1519 * Ensures that <code>offset</code> is a valid offset into the 1520 * model for <code>text</code>. 1521 */ 1522 private int constrainOffset(JTextComponent text, int offset) { 1523 Document doc = text.getDocument(); 1524 1525 if ((offset != 0) && (offset > doc.getLength())) { 1526 offset = doc.getLength(); 1527 } 1528 if (offset < 0) { 1529 offset = 0; 1530 } 1531 return offset; 1532 } 1533 1534 /** 1535 * Returns adjustsed {@code y} position that indicates the location to scroll to 1536 * after selecting <code>index</code>. 1537 */ 1538 private int getAdjustedY(JTextComponent text, Rectangle visible, int index) { 1539 int result = visible.y; 1540 1541 try { 1542 Rectangle dotBounds = text.modelToView(index); 1543 1544 if (dotBounds.y < visible.y) { 1545 result = dotBounds.y; 1546 } else { 1547 if ((dotBounds.y > visible.y + visible.height) || 1548 (dotBounds.y + dotBounds.height > visible.y + visible.height)) { 1549 result = dotBounds.y + dotBounds.height - visible.height; 1550 } 1551 } 1552 } catch (BadLocationException ble) { 1553 } 1554 1555 return result; 1556 } 1557 1558 /** 1559 * Adjusts the Rectangle to contain the bounds of the character at 1560 * <code>index</code> in response to a page up. 1561 */ 1562 private boolean select; 1563 1564 /** 1565 * Direction to scroll, 1 is down, -1 is up. 1566 */ 1567 private int direction; 1568 } 1569 1570 1571 /** 1572 * Pages one view to the left or right. 1573 */ 1574 static class PageAction extends TextAction { 1575 1576 /** Create this object with the appropriate identifier. */ 1577 public PageAction(String nm, boolean left, boolean select) { 1578 super(nm); 1579 this.select = select; 1580 this.left = left; 1581 } 1582 1583 /** The operation to perform when this action is triggered. */ 1584 public void actionPerformed(ActionEvent e) { 1585 JTextComponent target = getTextComponent(e); 1586 if (target != null) { 1587 int selectedIndex; 1588 Rectangle visible = new Rectangle(); 1589 target.computeVisibleRect(visible); 1590 if (left) { 1591 visible.x = Math.max(0, visible.x - visible.width); 1592 } 1593 else { 1594 visible.x += visible.width; 1595 } 1596 1597 selectedIndex = target.getCaretPosition(); 1598 if(selectedIndex != -1) { 1599 if (left) { 1600 selectedIndex = target.viewToModel 1601 (new Point(visible.x, visible.y)); 1602 } 1603 else { 1604 selectedIndex = target.viewToModel 1605 (new Point(visible.x + visible.width - 1, 1606 visible.y + visible.height - 1)); 1607 } 1608 Document doc = target.getDocument(); 1609 if ((selectedIndex != 0) && 1610 (selectedIndex > (doc.getLength()-1))) { 1611 selectedIndex = doc.getLength()-1; 1612 } 1613 else if(selectedIndex < 0) { 1614 selectedIndex = 0; 1615 } 1616 if (select) 1617 target.moveCaretPosition(selectedIndex); 1618 else 1619 target.setCaretPosition(selectedIndex); 1620 } 1621 } 1622 } 1623 1624 private boolean select; 1625 private boolean left; 1626 } 1627 1628 static class DumpModelAction extends TextAction { 1629 1630 DumpModelAction() { 1631 super("dump-model"); 1632 } 1633 1634 public void actionPerformed(ActionEvent e) { 1635 JTextComponent target = getTextComponent(e); 1636 if (target != null) { 1637 Document d = target.getDocument(); 1638 if (d instanceof AbstractDocument) { 1639 ((AbstractDocument) d).dump(System.err); 1640 } 1641 } 1642 } 1643 } 1644 1645 /* 1646 * Action to move the selection by way of the 1647 * getNextVisualPositionFrom method. Constructor indicates direction 1648 * to use. 1649 */ 1650 static class NextVisualPositionAction extends TextAction { 1651 1652 /** 1653 * Create this action with the appropriate identifier. 1654 * @param nm the name of the action, Action.NAME. 1655 * @param select whether to extend the selection when 1656 * changing the caret position. 1657 */ 1658 NextVisualPositionAction(String nm, boolean select, int direction) { 1659 super(nm); 1660 this.select = select; 1661 this.direction = direction; 1662 } 1663 1664 /** The operation to perform when this action is triggered. */ 1665 public void actionPerformed(ActionEvent e) { 1666 JTextComponent target = getTextComponent(e); 1667 if (target != null) { 1668 Caret caret = target.getCaret(); 1669 DefaultCaret bidiCaret = (caret instanceof DefaultCaret) ? 1670 (DefaultCaret)caret : null; 1671 int dot = caret.getDot(); 1672 Position.Bias[] bias = new Position.Bias[1]; 1673 Point magicPosition = caret.getMagicCaretPosition(); 1674 1675 try { 1676 if(magicPosition == null && 1677 (direction == SwingConstants.NORTH || 1678 direction == SwingConstants.SOUTH)) { 1679 Rectangle r = (bidiCaret != null) ? 1680 target.getUI().modelToView(target, dot, 1681 bidiCaret.getDotBias()) : 1682 target.modelToView(dot); 1683 magicPosition = new Point(r.x, r.y); 1684 } 1685 1686 NavigationFilter filter = target.getNavigationFilter(); 1687 1688 if (filter != null) { 1689 dot = filter.getNextVisualPositionFrom 1690 (target, dot, (bidiCaret != null) ? 1691 bidiCaret.getDotBias() : 1692 Position.Bias.Forward, direction, bias); 1693 } 1694 else { 1695 dot = target.getUI().getNextVisualPositionFrom 1696 (target, dot, (bidiCaret != null) ? 1697 bidiCaret.getDotBias() : 1698 Position.Bias.Forward, direction, bias); 1699 } 1700 if(bias[0] == null) { 1701 bias[0] = Position.Bias.Forward; 1702 } 1703 if(bidiCaret != null) { 1704 if (select) { 1705 bidiCaret.moveDot(dot, bias[0]); 1706 } else { 1707 bidiCaret.setDot(dot, bias[0]); 1708 } 1709 } 1710 else { 1711 if (select) { 1712 caret.moveDot(dot); 1713 } else { 1714 caret.setDot(dot); 1715 } 1716 } 1717 if(magicPosition != null && 1718 (direction == SwingConstants.NORTH || 1719 direction == SwingConstants.SOUTH)) { 1720 target.getCaret().setMagicCaretPosition(magicPosition); 1721 } 1722 } catch (BadLocationException ex) { 1723 } 1724 } 1725 } 1726 1727 private boolean select; 1728 private int direction; 1729 } 1730 1731 /* 1732 * Position the caret to the beginning of the word. 1733 * @see DefaultEditorKit#beginWordAction 1734 * @see DefaultEditorKit#selectBeginWordAction 1735 * @see DefaultEditorKit#getActions 1736 */ 1737 static class BeginWordAction extends TextAction { 1738 1739 /** 1740 * Create this action with the appropriate identifier. 1741 * @param nm the name of the action, Action.NAME. 1742 * @param select whether to extend the selection when 1743 * changing the caret position. 1744 */ 1745 BeginWordAction(String nm, boolean select) { 1746 super(nm); 1747 this.select = select; 1748 } 1749 1750 /** The operation to perform when this action is triggered. */ 1751 public void actionPerformed(ActionEvent e) { 1752 JTextComponent target = getTextComponent(e); 1753 if (target != null) { 1754 try { 1755 int offs = target.getCaretPosition(); 1756 int begOffs = Utilities.getWordStart(target, offs); 1757 if (select) { 1758 target.moveCaretPosition(begOffs); 1759 } else { 1760 target.setCaretPosition(begOffs); 1761 } 1762 } catch (BadLocationException bl) { 1763 UIManager.getLookAndFeel().provideErrorFeedback(target); 1764 } 1765 } 1766 } 1767 1768 private boolean select; 1769 } 1770 1771 /* 1772 * Position the caret to the end of the word. 1773 * @see DefaultEditorKit#endWordAction 1774 * @see DefaultEditorKit#selectEndWordAction 1775 * @see DefaultEditorKit#getActions 1776 */ 1777 static class EndWordAction extends TextAction { 1778 1779 /** 1780 * Create this action with the appropriate identifier. 1781 * @param nm the name of the action, Action.NAME. 1782 * @param select whether to extend the selection when 1783 * changing the caret position. 1784 */ 1785 EndWordAction(String nm, boolean select) { 1786 super(nm); 1787 this.select = select; 1788 } 1789 1790 /** The operation to perform when this action is triggered. */ 1791 public void actionPerformed(ActionEvent e) { 1792 JTextComponent target = getTextComponent(e); 1793 if (target != null) { 1794 try { 1795 int offs = target.getCaretPosition(); 1796 int endOffs = Utilities.getWordEnd(target, offs); 1797 if (select) { 1798 target.moveCaretPosition(endOffs); 1799 } else { 1800 target.setCaretPosition(endOffs); 1801 } 1802 } catch (BadLocationException bl) { 1803 UIManager.getLookAndFeel().provideErrorFeedback(target); 1804 } 1805 } 1806 } 1807 1808 private boolean select; 1809 } 1810 1811 /* 1812 * Position the caret to the beginning of the previous word. 1813 * @see DefaultEditorKit#previousWordAction 1814 * @see DefaultEditorKit#selectPreviousWordAction 1815 * @see DefaultEditorKit#getActions 1816 */ 1817 static class PreviousWordAction extends TextAction { 1818 1819 /** 1820 * Create this action with the appropriate identifier. 1821 * @param nm the name of the action, Action.NAME. 1822 * @param select whether to extend the selection when 1823 * changing the caret position. 1824 */ 1825 PreviousWordAction(String nm, boolean select) { 1826 super(nm); 1827 this.select = select; 1828 } 1829 1830 /** The operation to perform when this action is triggered. */ 1831 public void actionPerformed(ActionEvent e) { 1832 JTextComponent target = getTextComponent(e); 1833 if (target != null) { 1834 int offs = target.getCaretPosition(); 1835 boolean failed = false; 1836 try { 1837 Element curPara = 1838 Utilities.getParagraphElement(target, offs); 1839 offs = Utilities.getPreviousWord(target, offs); 1840 if(offs < curPara.getStartOffset()) { 1841 // we should first move to the end of the 1842 // previous paragraph (bug #4278839) 1843 offs = Utilities.getParagraphElement(target, offs). 1844 getEndOffset() - 1; 1845 } 1846 } catch (BadLocationException bl) { 1847 if (offs != 0) { 1848 offs = 0; 1849 } 1850 else { 1851 failed = true; 1852 } 1853 } 1854 if (!failed) { 1855 if (select) { 1856 target.moveCaretPosition(offs); 1857 } else { 1858 target.setCaretPosition(offs); 1859 } 1860 } 1861 else { 1862 UIManager.getLookAndFeel().provideErrorFeedback(target); 1863 } 1864 } 1865 } 1866 1867 private boolean select; 1868 } 1869 1870 /* 1871 * Position the caret to the next of the word. 1872 * @see DefaultEditorKit#nextWordAction 1873 * @see DefaultEditorKit#selectNextWordAction 1874 * @see DefaultEditorKit#getActions 1875 */ 1876 static class NextWordAction extends TextAction { 1877 1878 /** 1879 * Create this action with the appropriate identifier. 1880 * @param nm the name of the action, Action.NAME. 1881 * @param select whether to extend the selection when 1882 * changing the caret position. 1883 */ 1884 NextWordAction(String nm, boolean select) { 1885 super(nm); 1886 this.select = select; 1887 } 1888 1889 /** The operation to perform when this action is triggered. */ 1890 public void actionPerformed(ActionEvent e) { 1891 JTextComponent target = getTextComponent(e); 1892 if (target != null) { 1893 int offs = target.getCaretPosition(); 1894 boolean failed = false; 1895 int oldOffs = offs; 1896 Element curPara = 1897 Utilities.getParagraphElement(target, offs); 1898 try { 1899 offs = Utilities.getNextWord(target, offs); 1900 if(offs >= curPara.getEndOffset() && 1901 oldOffs != curPara.getEndOffset() - 1) { 1902 // we should first move to the end of current 1903 // paragraph (bug #4278839) 1904 offs = curPara.getEndOffset() - 1; 1905 } 1906 } catch (BadLocationException bl) { 1907 int end = target.getDocument().getLength(); 1908 if (offs != end) { 1909 if(oldOffs != curPara.getEndOffset() - 1) { 1910 offs = curPara.getEndOffset() - 1; 1911 } else { 1912 offs = end; 1913 } 1914 } 1915 else { 1916 failed = true; 1917 } 1918 } 1919 if (!failed) { 1920 if (select) { 1921 target.moveCaretPosition(offs); 1922 } else { 1923 target.setCaretPosition(offs); 1924 } 1925 } 1926 else { 1927 UIManager.getLookAndFeel().provideErrorFeedback(target); 1928 } 1929 } 1930 } 1931 1932 private boolean select; 1933 } 1934 1935 /* 1936 * Position the caret to the beginning of the line. 1937 * @see DefaultEditorKit#beginLineAction 1938 * @see DefaultEditorKit#selectBeginLineAction 1939 * @see DefaultEditorKit#getActions 1940 */ 1941 static class BeginLineAction extends TextAction { 1942 1943 /** 1944 * Create this action with the appropriate identifier. 1945 * @param nm the name of the action, Action.NAME. 1946 * @param select whether to extend the selection when 1947 * changing the caret position. 1948 */ 1949 BeginLineAction(String nm, boolean select) { 1950 super(nm); 1951 this.select = select; 1952 } 1953 1954 /** The operation to perform when this action is triggered. */ 1955 public void actionPerformed(ActionEvent e) { 1956 JTextComponent target = getTextComponent(e); 1957 if (target != null) { 1958 try { 1959 int offs = target.getCaretPosition(); 1960 int begOffs = Utilities.getRowStart(target, offs); 1961 if (select) { 1962 target.moveCaretPosition(begOffs); 1963 } else { 1964 target.setCaretPosition(begOffs); 1965 } 1966 } catch (BadLocationException bl) { 1967 UIManager.getLookAndFeel().provideErrorFeedback(target); 1968 } 1969 } 1970 } 1971 1972 private boolean select; 1973 } 1974 1975 /* 1976 * Position the caret to the end of the line. 1977 * @see DefaultEditorKit#endLineAction 1978 * @see DefaultEditorKit#selectEndLineAction 1979 * @see DefaultEditorKit#getActions 1980 */ 1981 static class EndLineAction extends TextAction { 1982 1983 /** 1984 * Create this action with the appropriate identifier. 1985 * @param nm the name of the action, Action.NAME. 1986 * @param select whether to extend the selection when 1987 * changing the caret position. 1988 */ 1989 EndLineAction(String nm, boolean select) { 1990 super(nm); 1991 this.select = select; 1992 } 1993 1994 /** The operation to perform when this action is triggered. */ 1995 public void actionPerformed(ActionEvent e) { 1996 JTextComponent target = getTextComponent(e); 1997 if (target != null) { 1998 try { 1999 int offs = target.getCaretPosition(); 2000 int endOffs = Utilities.getRowEnd(target, offs); 2001 if (select) { 2002 target.moveCaretPosition(endOffs); 2003 } else { 2004 target.setCaretPosition(endOffs); 2005 } 2006 } catch (BadLocationException bl) { 2007 UIManager.getLookAndFeel().provideErrorFeedback(target); 2008 } 2009 } 2010 } 2011 2012 private boolean select; 2013 } 2014 2015 /* 2016 * Position the caret to the beginning of the paragraph. 2017 * @see DefaultEditorKit#beginParagraphAction 2018 * @see DefaultEditorKit#selectBeginParagraphAction 2019 * @see DefaultEditorKit#getActions 2020 */ 2021 static class BeginParagraphAction extends TextAction { 2022 2023 /** 2024 * Create this action with the appropriate identifier. 2025 * @param nm the name of the action, Action.NAME. 2026 * @param select whether to extend the selection when 2027 * changing the caret position. 2028 */ 2029 BeginParagraphAction(String nm, boolean select) { 2030 super(nm); 2031 this.select = select; 2032 } 2033 2034 /** The operation to perform when this action is triggered. */ 2035 public void actionPerformed(ActionEvent e) { 2036 JTextComponent target = getTextComponent(e); 2037 if (target != null) { 2038 int offs = target.getCaretPosition(); 2039 Element elem = Utilities.getParagraphElement(target, offs); 2040 offs = elem.getStartOffset(); 2041 if (select) { 2042 target.moveCaretPosition(offs); 2043 } else { 2044 target.setCaretPosition(offs); 2045 } 2046 } 2047 } 2048 2049 private boolean select; 2050 } 2051 2052 /* 2053 * Position the caret to the end of the paragraph. 2054 * @see DefaultEditorKit#endParagraphAction 2055 * @see DefaultEditorKit#selectEndParagraphAction 2056 * @see DefaultEditorKit#getActions 2057 */ 2058 static class EndParagraphAction extends TextAction { 2059 2060 /** 2061 * Create this action with the appropriate identifier. 2062 * @param nm the name of the action, Action.NAME. 2063 * @param select whether to extend the selection when 2064 * changing the caret position. 2065 */ 2066 EndParagraphAction(String nm, boolean select) { 2067 super(nm); 2068 this.select = select; 2069 } 2070 2071 /** The operation to perform when this action is triggered. */ 2072 public void actionPerformed(ActionEvent e) { 2073 JTextComponent target = getTextComponent(e); 2074 if (target != null) { 2075 int offs = target.getCaretPosition(); 2076 Element elem = Utilities.getParagraphElement(target, offs); 2077 offs = Math.min(target.getDocument().getLength(), 2078 elem.getEndOffset()); 2079 if (select) { 2080 target.moveCaretPosition(offs); 2081 } else { 2082 target.setCaretPosition(offs); 2083 } 2084 } 2085 } 2086 2087 private boolean select; 2088 } 2089 2090 /* 2091 * Move the caret to the beginning of the document. 2092 * @see DefaultEditorKit#beginAction 2093 * @see DefaultEditorKit#getActions 2094 */ 2095 static class BeginAction extends TextAction { 2096 2097 /* Create this object with the appropriate identifier. */ 2098 BeginAction(String nm, boolean select) { 2099 super(nm); 2100 this.select = select; 2101 } 2102 2103 /** The operation to perform when this action is triggered. */ 2104 public void actionPerformed(ActionEvent e) { 2105 JTextComponent target = getTextComponent(e); 2106 if (target != null) { 2107 if (select) { 2108 target.moveCaretPosition(0); 2109 } else { 2110 target.setCaretPosition(0); 2111 } 2112 } 2113 } 2114 2115 private boolean select; 2116 } 2117 2118 /* 2119 * Move the caret to the end of the document. 2120 * @see DefaultEditorKit#endAction 2121 * @see DefaultEditorKit#getActions 2122 */ 2123 static class EndAction extends TextAction { 2124 2125 /* Create this object with the appropriate identifier. */ 2126 EndAction(String nm, boolean select) { 2127 super(nm); 2128 this.select = select; 2129 } 2130 2131 /** The operation to perform when this action is triggered. */ 2132 public void actionPerformed(ActionEvent e) { 2133 JTextComponent target = getTextComponent(e); 2134 if (target != null) { 2135 Document doc = target.getDocument(); 2136 int dot = doc.getLength(); 2137 if (select) { 2138 target.moveCaretPosition(dot); 2139 } else { 2140 target.setCaretPosition(dot); 2141 } 2142 } 2143 } 2144 2145 private boolean select; 2146 } 2147 2148 /* 2149 * Select the word around the caret 2150 * @see DefaultEditorKit#endAction 2151 * @see DefaultEditorKit#getActions 2152 */ 2153 static class SelectWordAction extends TextAction { 2154 2155 /** 2156 * Create this action with the appropriate identifier. 2157 * @param nm the name of the action, Action.NAME. 2158 * @param select whether to extend the selection when 2159 * changing the caret position. 2160 */ 2161 SelectWordAction() { 2162 super(selectWordAction); 2163 start = new BeginWordAction("pigdog", false); 2164 end = new EndWordAction("pigdog", true); 2165 } 2166 2167 /** The operation to perform when this action is triggered. */ 2168 public void actionPerformed(ActionEvent e) { 2169 start.actionPerformed(e); 2170 end.actionPerformed(e); 2171 } 2172 2173 private Action start; 2174 private Action end; 2175 } 2176 2177 /* 2178 * Select the line around the caret 2179 * @see DefaultEditorKit#endAction 2180 * @see DefaultEditorKit#getActions 2181 */ 2182 static class SelectLineAction extends TextAction { 2183 2184 /** 2185 * Create this action with the appropriate identifier. 2186 * @param nm the name of the action, Action.NAME. 2187 * @param select whether to extend the selection when 2188 * changing the caret position. 2189 */ 2190 SelectLineAction() { 2191 super(selectLineAction); 2192 start = new BeginLineAction("pigdog", false); 2193 end = new EndLineAction("pigdog", true); 2194 } 2195 2196 /** The operation to perform when this action is triggered. */ 2197 public void actionPerformed(ActionEvent e) { 2198 start.actionPerformed(e); 2199 end.actionPerformed(e); 2200 } 2201 2202 private Action start; 2203 private Action end; 2204 } 2205 2206 /* 2207 * Select the paragraph around the caret 2208 * @see DefaultEditorKit#endAction 2209 * @see DefaultEditorKit#getActions 2210 */ 2211 static class SelectParagraphAction extends TextAction { 2212 2213 /** 2214 * Create this action with the appropriate identifier. 2215 * @param nm the name of the action, Action.NAME. 2216 * @param select whether to extend the selection when 2217 * changing the caret position. 2218 */ 2219 SelectParagraphAction() { 2220 super(selectParagraphAction); 2221 start = new BeginParagraphAction("pigdog", false); 2222 end = new EndParagraphAction("pigdog", true); 2223 } 2224 2225 /** The operation to perform when this action is triggered. */ 2226 public void actionPerformed(ActionEvent e) { 2227 start.actionPerformed(e); 2228 end.actionPerformed(e); 2229 } 2230 2231 private Action start; 2232 private Action end; 2233 } 2234 2235 /* 2236 * Select the entire document 2237 * @see DefaultEditorKit#endAction 2238 * @see DefaultEditorKit#getActions 2239 */ 2240 static class SelectAllAction extends TextAction { 2241 2242 /** 2243 * Create this action with the appropriate identifier. 2244 * @param nm the name of the action, Action.NAME. 2245 * @param select whether to extend the selection when 2246 * changing the caret position. 2247 */ 2248 SelectAllAction() { 2249 super(selectAllAction); 2250 } 2251 2252 /** The operation to perform when this action is triggered. */ 2253 public void actionPerformed(ActionEvent e) { 2254 JTextComponent target = getTextComponent(e); 2255 if (target != null) { 2256 Document doc = target.getDocument(); 2257 target.setCaretPosition(0); 2258 target.moveCaretPosition(doc.getLength()); 2259 } 2260 } 2261 2262 } 2263 2264 /* 2265 * Remove the selection, if any. 2266 * @see DefaultEditorKit#unselectAction 2267 * @see DefaultEditorKit#getActions 2268 */ 2269 static class UnselectAction extends TextAction { 2270 2271 /** 2272 * Create this action with the appropriate identifier. 2273 */ 2274 UnselectAction() { 2275 super(unselectAction); 2276 } 2277 2278 /** The operation to perform when this action is triggered. */ 2279 public void actionPerformed(ActionEvent e) { 2280 JTextComponent target = getTextComponent(e); 2281 if (target != null) { 2282 target.setCaretPosition(target.getCaretPosition()); 2283 } 2284 } 2285 2286 } 2287 2288 /* 2289 * Toggles the ComponentOrientation of the text component. 2290 * @see DefaultEditorKit#toggleComponentOrientationAction 2291 * @see DefaultEditorKit#getActions 2292 */ 2293 static class ToggleComponentOrientationAction extends TextAction { 2294 2295 /** 2296 * Create this action with the appropriate identifier. 2297 */ 2298 ToggleComponentOrientationAction() { 2299 super(toggleComponentOrientationAction); 2300 } 2301 2302 /** The operation to perform when this action is triggered. */ 2303 public void actionPerformed(ActionEvent e) { 2304 JTextComponent target = getTextComponent(e); 2305 if (target != null) { 2306 ComponentOrientation last = target.getComponentOrientation(); 2307 ComponentOrientation next; 2308 if( last == ComponentOrientation.RIGHT_TO_LEFT ) 2309 next = ComponentOrientation.LEFT_TO_RIGHT; 2310 else 2311 next = ComponentOrientation.RIGHT_TO_LEFT; 2312 target.setComponentOrientation(next); 2313 target.repaint(); 2314 } 2315 } 2316 } 2317 2318 }