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