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 // Variation Selector and base char should be deleted. 1077 if ((dot > 2 && isVariationSelector(c0, c1)) || 1078 (isVariationSelector(c1))) { 1079 String targetChars = doc.getText(0, dot); 1080 int pre = targetChars.codePointBefore(dot - delChars); 1081 if (isBaseChar(pre)){ 1082 if (pre >= 0x10000){ 1083 delChars += 2; 1084 }else{ 1085 delChars += 1; 1086 } 1087 } 1088 } 1089 } 1090 1091 doc.remove(dot - delChars, delChars); 1092 beep = false; 1093 } 1094 } catch (BadLocationException bl) { 1095 } 1096 } 1097 if (beep) { 1098 UIManager.getLookAndFeel().provideErrorFeedback(target); 1099 } 1100 } 1101 } 1102 1103 /* 1104 * Deletes the character of content that follows the 1105 * current caret position. 1106 * @see DefaultEditorKit#deleteNextCharAction 1107 * @see DefaultEditorKit#getActions 1108 */ 1109 @SuppressWarnings("serial") // Superclass is not serializable across versions 1110 static class DeleteNextCharAction extends TextAction { 1111 1112 /* Create this object with the appropriate identifier. */ 1113 DeleteNextCharAction() { 1114 super(deleteNextCharAction); 1115 } 1116 1117 /** The operation to perform when this action is triggered. */ 1118 public void actionPerformed(ActionEvent e) { 1119 JTextComponent target = getTextComponent(e); 1120 boolean beep = true; 1121 if ((target != null) && (target.isEditable())) { 1122 try { 1123 Document doc = target.getDocument(); 1124 Caret caret = target.getCaret(); 1125 int dot = caret.getDot(); 1126 int mark = caret.getMark(); 1127 if (dot != mark) { 1128 doc.remove(Math.min(dot, mark), Math.abs(dot - mark)); 1129 beep = false; 1130 } else if (dot < doc.getLength()) { 1131 int delChars = 1; 1132 1133 if (dot < doc.getLength() - 1) { 1134 String dotChars = doc.getText(dot, 2); 1135 char c0 = dotChars.charAt(0); 1136 char c1 = dotChars.charAt(1); 1137 int baseChar = (int)c0; 1138 1139 if (c0 >= '\uD800' && c0 <= '\uDBFF' && 1140 c1 >= '\uDC00' && c1 <= '\uDFFF') { 1141 delChars = 2; 1142 baseChar = (c0-0xD800)*0x400 + c1-0xDC00 + 0x10000; 1143 } 1144 1145 // Variation Selector and base char should be deleted. 1146 if (isBaseChar(baseChar) && 1147 dot < doc.getLength() - delChars) { 1148 String nextChar = doc.getText(dot+delChars, 1); 1149 char c2 = nextChar.charAt(0); 1150 if (isVariationSelector(c2)) { 1151 delChars += 1; 1152 }else if (dot < doc.getLength() - delChars - 1) { 1153 nextChar = doc.getText(dot + delChars + 1, 1); 1154 char c3 = nextChar.charAt(0); 1155 if (isVariationSelector(c2,c3)) { 1156 delChars += 2; 1157 } 1158 } 1159 } 1160 } 1161 1162 doc.remove(dot, delChars); 1163 beep = false; 1164 } 1165 } catch (BadLocationException bl) { 1166 } 1167 } 1168 if (beep) { 1169 UIManager.getLookAndFeel().provideErrorFeedback(target); 1170 } 1171 } 1172 } 1173 1174 1175 /* 1176 * Deletes the word that precedes/follows the beginning of the selection. 1177 * @see DefaultEditorKit#getActions 1178 */ 1179 @SuppressWarnings("serial") // Superclass is not serializable across versions 1180 static class DeleteWordAction extends TextAction { 1181 DeleteWordAction(String name) { 1182 super(name); 1183 assert (name == deletePrevWordAction) 1184 || (name == deleteNextWordAction); 1185 } 1186 /** 1187 * The operation to perform when this action is triggered. 1188 * 1189 * @param e the action event 1190 */ 1191 public void actionPerformed(ActionEvent e) { 1192 final JTextComponent target = getTextComponent(e); 1193 if ((target != null) && (e != null)) { 1194 if ((! target.isEditable()) || (! target.isEnabled())) { 1195 UIManager.getLookAndFeel().provideErrorFeedback(target); 1196 return; 1197 } 1198 boolean beep = true; 1199 try { 1200 final int start = target.getSelectionStart(); 1201 final Element line = 1202 Utilities.getParagraphElement(target, start); 1203 int end; 1204 if (deleteNextWordAction == getValue(Action.NAME)) { 1205 end = Utilities. 1206 getNextWordInParagraph(target, line, start, false); 1207 if (end == java.text.BreakIterator.DONE) { 1208 //last word in the paragraph 1209 final int endOfLine = line.getEndOffset(); 1210 if (start == endOfLine - 1) { 1211 //for last position remove last \n 1212 end = endOfLine; 1213 } else { 1214 //remove to the end of the paragraph 1215 end = endOfLine - 1; 1216 } 1217 } 1218 } else { 1219 end = Utilities. 1220 getPrevWordInParagraph(target, line, start); 1221 if (end == java.text.BreakIterator.DONE) { 1222 //there is no previous word in the paragraph 1223 final int startOfLine = line.getStartOffset(); 1224 if (start == startOfLine) { 1225 //for first position remove previous \n 1226 end = startOfLine - 1; 1227 } else { 1228 //remove to the start of the paragraph 1229 end = startOfLine; 1230 } 1231 } 1232 } 1233 int offs = Math.min(start, end); 1234 int len = Math.abs(end - start); 1235 if (offs >= 0) { 1236 target.getDocument().remove(offs, len); 1237 beep = false; 1238 } 1239 } catch (BadLocationException ignore) { 1240 } 1241 if (beep) { 1242 UIManager.getLookAndFeel().provideErrorFeedback(target); 1243 } 1244 } 1245 } 1246 } 1247 1248 1249 /* 1250 * Sets the editor into read-only mode. 1251 * @see DefaultEditorKit#readOnlyAction 1252 * @see DefaultEditorKit#getActions 1253 */ 1254 @SuppressWarnings("serial") // Superclass is not serializable across versions 1255 static class ReadOnlyAction extends TextAction { 1256 1257 /* Create this object with the appropriate identifier. */ 1258 ReadOnlyAction() { 1259 super(readOnlyAction); 1260 } 1261 1262 /** 1263 * The operation to perform when this action is triggered. 1264 * 1265 * @param e the action event 1266 */ 1267 public void actionPerformed(ActionEvent e) { 1268 JTextComponent target = getTextComponent(e); 1269 if (target != null) { 1270 target.setEditable(false); 1271 } 1272 } 1273 } 1274 1275 /* 1276 * Sets the editor into writeable mode. 1277 * @see DefaultEditorKit#writableAction 1278 * @see DefaultEditorKit#getActions 1279 */ 1280 @SuppressWarnings("serial") // Superclass is not serializable across versions 1281 static class WritableAction extends TextAction { 1282 1283 /* Create this object with the appropriate identifier. */ 1284 WritableAction() { 1285 super(writableAction); 1286 } 1287 1288 /** 1289 * The operation to perform when this action is triggered. 1290 * 1291 * @param e the action event 1292 */ 1293 public void actionPerformed(ActionEvent e) { 1294 JTextComponent target = getTextComponent(e); 1295 if (target != null) { 1296 target.setEditable(true); 1297 } 1298 } 1299 } 1300 1301 /** 1302 * Cuts the selected region and place its contents 1303 * into the system clipboard. 1304 * <p> 1305 * <strong>Warning:</strong> 1306 * Serialized objects of this class will not be compatible with 1307 * future Swing releases. The current serialization support is 1308 * appropriate for short term storage or RMI between applications running 1309 * the same version of Swing. As of 1.4, support for long term storage 1310 * of all JavaBeans™ 1311 * has been added to the <code>java.beans</code> package. 1312 * Please see {@link java.beans.XMLEncoder}. 1313 * 1314 * @see DefaultEditorKit#cutAction 1315 * @see DefaultEditorKit#getActions 1316 */ 1317 @SuppressWarnings("serial") // Same-version serialization only 1318 public static class CutAction extends TextAction { 1319 1320 /** Create this object with the appropriate identifier. */ 1321 public CutAction() { 1322 super(cutAction); 1323 } 1324 1325 /** 1326 * The operation to perform when this action is triggered. 1327 * 1328 * @param e the action event 1329 */ 1330 public void actionPerformed(ActionEvent e) { 1331 JTextComponent target = getTextComponent(e); 1332 if (target != null) { 1333 target.cut(); 1334 } 1335 } 1336 } 1337 1338 /** 1339 * Copies the selected region and place its contents 1340 * into the system clipboard. 1341 * <p> 1342 * <strong>Warning:</strong> 1343 * Serialized objects of this class will not be compatible with 1344 * future Swing releases. The current serialization support is 1345 * appropriate for short term storage or RMI between applications running 1346 * the same version of Swing. As of 1.4, support for long term storage 1347 * of all JavaBeans™ 1348 * has been added to the <code>java.beans</code> package. 1349 * Please see {@link java.beans.XMLEncoder}. 1350 * 1351 * @see DefaultEditorKit#copyAction 1352 * @see DefaultEditorKit#getActions 1353 */ 1354 @SuppressWarnings("serial") // Same-version serialization only 1355 public static class CopyAction extends TextAction { 1356 1357 /** Create this object with the appropriate identifier. */ 1358 public CopyAction() { 1359 super(copyAction); 1360 } 1361 1362 /** 1363 * The operation to perform when this action is triggered. 1364 * 1365 * @param e the action event 1366 */ 1367 public void actionPerformed(ActionEvent e) { 1368 JTextComponent target = getTextComponent(e); 1369 if (target != null) { 1370 target.copy(); 1371 } 1372 } 1373 } 1374 1375 /** 1376 * Pastes the contents of the system clipboard into the 1377 * selected region, or before the caret if nothing is 1378 * selected. 1379 * <p> 1380 * <strong>Warning:</strong> 1381 * Serialized objects of this class will not be compatible with 1382 * future Swing releases. The current serialization support is 1383 * appropriate for short term storage or RMI between applications running 1384 * the same version of Swing. As of 1.4, support for long term storage 1385 * of all JavaBeans™ 1386 * has been added to the <code>java.beans</code> package. 1387 * Please see {@link java.beans.XMLEncoder}. 1388 * 1389 * @see DefaultEditorKit#pasteAction 1390 * @see DefaultEditorKit#getActions 1391 */ 1392 @SuppressWarnings("serial") // Same-version serialization only 1393 public static class PasteAction extends TextAction { 1394 1395 /** Create this object with the appropriate identifier. */ 1396 public PasteAction() { 1397 super(pasteAction); 1398 } 1399 1400 /** 1401 * The operation to perform when this action is triggered. 1402 * 1403 * @param e the action event 1404 */ 1405 public void actionPerformed(ActionEvent e) { 1406 JTextComponent target = getTextComponent(e); 1407 if (target != null) { 1408 target.paste(); 1409 } 1410 } 1411 } 1412 1413 /** 1414 * Creates a beep. 1415 * <p> 1416 * <strong>Warning:</strong> 1417 * Serialized objects of this class will not be compatible with 1418 * future Swing releases. The current serialization support is 1419 * appropriate for short term storage or RMI between applications running 1420 * the same version of Swing. As of 1.4, support for long term storage 1421 * of all JavaBeans™ 1422 * has been added to the <code>java.beans</code> package. 1423 * Please see {@link java.beans.XMLEncoder}. 1424 * 1425 * @see DefaultEditorKit#beepAction 1426 * @see DefaultEditorKit#getActions 1427 */ 1428 @SuppressWarnings("serial") // Same-version serialization only 1429 public static class BeepAction extends TextAction { 1430 1431 /** Create this object with the appropriate identifier. */ 1432 public BeepAction() { 1433 super(beepAction); 1434 } 1435 1436 /** 1437 * The operation to perform when this action is triggered. 1438 * 1439 * @param e the action event 1440 */ 1441 public void actionPerformed(ActionEvent e) { 1442 JTextComponent target = getTextComponent(e); 1443 UIManager.getLookAndFeel().provideErrorFeedback(target); 1444 } 1445 } 1446 1447 /** 1448 * Scrolls up/down vertically. The select version of this action extends 1449 * the selection, instead of simply moving the caret. 1450 * 1451 * @see DefaultEditorKit#pageUpAction 1452 * @see DefaultEditorKit#pageDownAction 1453 * @see DefaultEditorKit#getActions 1454 */ 1455 @SuppressWarnings("serial") // Superclass is not serializable across versions 1456 static class VerticalPageAction extends TextAction { 1457 1458 /** Create this object with the appropriate identifier. */ 1459 public VerticalPageAction(String nm, int direction, boolean select) { 1460 super(nm); 1461 this.select = select; 1462 this.direction = direction; 1463 } 1464 1465 /** The operation to perform when this action is triggered. */ 1466 @SuppressWarnings("deprecation") 1467 public void actionPerformed(ActionEvent e) { 1468 JTextComponent target = getTextComponent(e); 1469 if (target != null) { 1470 Rectangle visible = target.getVisibleRect(); 1471 Rectangle newVis = new Rectangle(visible); 1472 int selectedIndex = target.getCaretPosition(); 1473 int scrollAmount = direction * 1474 target.getScrollableBlockIncrement( 1475 visible, SwingConstants.VERTICAL, direction); 1476 int initialY = visible.y; 1477 Caret caret = target.getCaret(); 1478 Point magicPosition = caret.getMagicCaretPosition(); 1479 1480 if (selectedIndex != -1) { 1481 try { 1482 Rectangle dotBounds = target.modelToView( 1483 selectedIndex); 1484 int x = (magicPosition != null) ? magicPosition.x : 1485 dotBounds.x; 1486 int h = dotBounds.height; 1487 if (h > 0) { 1488 // We want to scroll by a multiple of caret height, 1489 // rounding towards lower integer 1490 scrollAmount = scrollAmount / h * h; 1491 } 1492 newVis.y = constrainY(target, 1493 initialY + scrollAmount, visible.height); 1494 1495 int newIndex; 1496 1497 if (visible.contains(dotBounds.x, dotBounds.y)) { 1498 // Dot is currently visible, base the new 1499 // location off the old, or 1500 newIndex = target.viewToModel( 1501 new Point(x, constrainY(target, 1502 dotBounds.y + scrollAmount, 0))); 1503 } 1504 else { 1505 // Dot isn't visible, choose the top or the bottom 1506 // for the new location. 1507 if (direction == -1) { 1508 newIndex = target.viewToModel(new Point( 1509 x, newVis.y)); 1510 } 1511 else { 1512 newIndex = target.viewToModel(new Point( 1513 x, newVis.y + visible.height)); 1514 } 1515 } 1516 newIndex = constrainOffset(target, newIndex); 1517 if (newIndex != selectedIndex) { 1518 // Make sure the new visible location contains 1519 // the location of dot, otherwise Caret will 1520 // cause an additional scroll. 1521 int newY = getAdjustedY(target, newVis, newIndex); 1522 1523 if (direction == -1 && newY <= initialY || direction == 1 && newY >= initialY) { 1524 // Change index and correct newVis.y only if won't cause scrolling upward 1525 newVis.y = newY; 1526 1527 if (select) { 1528 target.moveCaretPosition(newIndex); 1529 } else { 1530 target.setCaretPosition(newIndex); 1531 } 1532 } 1533 } else { 1534 // If the caret index is same as the visible offset 1535 // then correct newVis.y so that it won't cause 1536 // unnecessary scrolling upward/downward when 1537 // page-down/page-up is received after ctrl-END/ctrl-HOME 1538 if (direction == -1 && newVis.y <= initialY || 1539 direction == 1 && newVis.y >= initialY) { 1540 newVis.y = initialY; 1541 } 1542 } 1543 } catch (BadLocationException ble) { } 1544 } else { 1545 newVis.y = constrainY(target, 1546 initialY + scrollAmount, visible.height); 1547 } 1548 if (magicPosition != null) { 1549 caret.setMagicCaretPosition(magicPosition); 1550 } 1551 target.scrollRectToVisible(newVis); 1552 } 1553 } 1554 1555 /** 1556 * Makes sure <code>y</code> is a valid location in 1557 * <code>target</code>. 1558 */ 1559 private int constrainY(JTextComponent target, int y, int vis) { 1560 if (y < 0) { 1561 y = 0; 1562 } 1563 else if (y + vis > target.getHeight()) { 1564 y = Math.max(0, target.getHeight() - vis); 1565 } 1566 return y; 1567 } 1568 1569 /** 1570 * Ensures that <code>offset</code> is a valid offset into the 1571 * model for <code>text</code>. 1572 */ 1573 private int constrainOffset(JTextComponent text, int offset) { 1574 Document doc = text.getDocument(); 1575 1576 if ((offset != 0) && (offset > doc.getLength())) { 1577 offset = doc.getLength(); 1578 } 1579 if (offset < 0) { 1580 offset = 0; 1581 } 1582 return offset; 1583 } 1584 1585 /** 1586 * Returns adjustsed {@code y} position that indicates the location to scroll to 1587 * after selecting <code>index</code>. 1588 */ 1589 @SuppressWarnings("deprecation") 1590 private int getAdjustedY(JTextComponent text, Rectangle visible, int index) { 1591 int result = visible.y; 1592 1593 try { 1594 Rectangle dotBounds = text.modelToView(index); 1595 1596 if (dotBounds.y < visible.y) { 1597 result = dotBounds.y; 1598 } else { 1599 if ((dotBounds.y > visible.y + visible.height) || 1600 (dotBounds.y + dotBounds.height > visible.y + visible.height)) { 1601 result = dotBounds.y + dotBounds.height - visible.height; 1602 } 1603 } 1604 } catch (BadLocationException ble) { 1605 } 1606 1607 return result; 1608 } 1609 1610 /** 1611 * Adjusts the Rectangle to contain the bounds of the character at 1612 * <code>index</code> in response to a page up. 1613 */ 1614 private boolean select; 1615 1616 /** 1617 * Direction to scroll, 1 is down, -1 is up. 1618 */ 1619 private int direction; 1620 } 1621 1622 1623 /** 1624 * Pages one view to the left or right. 1625 */ 1626 @SuppressWarnings("serial") // Superclass is not serializable across versions 1627 static class PageAction extends TextAction { 1628 1629 /** Create this object with the appropriate identifier. */ 1630 public PageAction(String nm, boolean left, boolean select) { 1631 super(nm); 1632 this.select = select; 1633 this.left = left; 1634 } 1635 1636 /** The operation to perform when this action is triggered. */ 1637 @SuppressWarnings("deprecation") 1638 public void actionPerformed(ActionEvent e) { 1639 JTextComponent target = getTextComponent(e); 1640 if (target != null) { 1641 int selectedIndex; 1642 Rectangle visible = new Rectangle(); 1643 target.computeVisibleRect(visible); 1644 if (left) { 1645 visible.x = Math.max(0, visible.x - visible.width); 1646 } 1647 else { 1648 visible.x += visible.width; 1649 } 1650 1651 selectedIndex = target.getCaretPosition(); 1652 if(selectedIndex != -1) { 1653 if (left) { 1654 selectedIndex = target.viewToModel 1655 (new Point(visible.x, visible.y)); 1656 } 1657 else { 1658 selectedIndex = target.viewToModel 1659 (new Point(visible.x + visible.width - 1, 1660 visible.y + visible.height - 1)); 1661 } 1662 Document doc = target.getDocument(); 1663 if ((selectedIndex != 0) && 1664 (selectedIndex > (doc.getLength()-1))) { 1665 selectedIndex = doc.getLength()-1; 1666 } 1667 else if(selectedIndex < 0) { 1668 selectedIndex = 0; 1669 } 1670 if (select) 1671 target.moveCaretPosition(selectedIndex); 1672 else 1673 target.setCaretPosition(selectedIndex); 1674 } 1675 } 1676 } 1677 1678 private boolean select; 1679 private boolean left; 1680 } 1681 1682 @SuppressWarnings("serial") // Superclass is not serializable across versions 1683 static class DumpModelAction extends TextAction { 1684 1685 DumpModelAction() { 1686 super("dump-model"); 1687 } 1688 1689 public void actionPerformed(ActionEvent e) { 1690 JTextComponent target = getTextComponent(e); 1691 if (target != null) { 1692 Document d = target.getDocument(); 1693 if (d instanceof AbstractDocument) { 1694 ((AbstractDocument) d).dump(System.err); 1695 } 1696 } 1697 } 1698 } 1699 1700 /* 1701 * Action to move the selection by way of the 1702 * getNextVisualPositionFrom method. Constructor indicates direction 1703 * to use. 1704 */ 1705 @SuppressWarnings("serial") // Superclass is not serializable across versions 1706 static class NextVisualPositionAction extends TextAction { 1707 1708 /** 1709 * Create this action with the appropriate identifier. 1710 * @param nm the name of the action, Action.NAME. 1711 * @param select whether to extend the selection when 1712 * changing the caret position. 1713 */ 1714 NextVisualPositionAction(String nm, boolean select, int direction) { 1715 super(nm); 1716 this.select = select; 1717 this.direction = direction; 1718 } 1719 1720 /** The operation to perform when this action is triggered. */ 1721 @SuppressWarnings("deprecation") 1722 public void actionPerformed(ActionEvent e) { 1723 JTextComponent target = getTextComponent(e); 1724 if (target != null) { 1725 Caret caret = target.getCaret(); 1726 DefaultCaret bidiCaret = (caret instanceof DefaultCaret) ? 1727 (DefaultCaret)caret : null; 1728 int dot = caret.getDot(); 1729 Position.Bias[] bias = new Position.Bias[1]; 1730 Point magicPosition = caret.getMagicCaretPosition(); 1731 1732 try { 1733 if(magicPosition == null && 1734 (direction == SwingConstants.NORTH || 1735 direction == SwingConstants.SOUTH)) { 1736 Rectangle r = (bidiCaret != null) ? 1737 target.getUI().modelToView(target, dot, 1738 bidiCaret.getDotBias()) : 1739 target.modelToView(dot); 1740 magicPosition = new Point(r.x, r.y); 1741 } 1742 1743 NavigationFilter filter = target.getNavigationFilter(); 1744 1745 if (filter != null) { 1746 dot = filter.getNextVisualPositionFrom 1747 (target, dot, (bidiCaret != null) ? 1748 bidiCaret.getDotBias() : 1749 Position.Bias.Forward, direction, bias); 1750 } 1751 else { 1752 dot = target.getUI().getNextVisualPositionFrom 1753 (target, dot, (bidiCaret != null) ? 1754 bidiCaret.getDotBias() : 1755 Position.Bias.Forward, direction, bias); 1756 } 1757 if(bias[0] == null) { 1758 bias[0] = Position.Bias.Forward; 1759 } 1760 if(bidiCaret != null) { 1761 if (select) { 1762 bidiCaret.moveDot(dot, bias[0]); 1763 } else { 1764 bidiCaret.setDot(dot, bias[0]); 1765 } 1766 } 1767 else { 1768 if (select) { 1769 caret.moveDot(dot); 1770 } else { 1771 caret.setDot(dot); 1772 } 1773 } 1774 if(magicPosition != null && 1775 (direction == SwingConstants.NORTH || 1776 direction == SwingConstants.SOUTH)) { 1777 target.getCaret().setMagicCaretPosition(magicPosition); 1778 } 1779 } catch (BadLocationException ex) { 1780 } 1781 } 1782 } 1783 1784 private boolean select; 1785 private int direction; 1786 } 1787 1788 /* 1789 * Position the caret to the beginning of the word. 1790 * @see DefaultEditorKit#beginWordAction 1791 * @see DefaultEditorKit#selectBeginWordAction 1792 * @see DefaultEditorKit#getActions 1793 */ 1794 @SuppressWarnings("serial") // Superclass is not serializable across versions 1795 static class BeginWordAction extends TextAction { 1796 1797 /** 1798 * Create this action with the appropriate identifier. 1799 * @param nm the name of the action, Action.NAME. 1800 * @param select whether to extend the selection when 1801 * changing the caret position. 1802 */ 1803 BeginWordAction(String nm, boolean select) { 1804 super(nm); 1805 this.select = select; 1806 } 1807 1808 /** The operation to perform when this action is triggered. */ 1809 public void actionPerformed(ActionEvent e) { 1810 JTextComponent target = getTextComponent(e); 1811 if (target != null) { 1812 try { 1813 int offs = target.getCaretPosition(); 1814 int begOffs = Utilities.getWordStart(target, offs); 1815 if (select) { 1816 target.moveCaretPosition(begOffs); 1817 } else { 1818 target.setCaretPosition(begOffs); 1819 } 1820 } catch (BadLocationException bl) { 1821 UIManager.getLookAndFeel().provideErrorFeedback(target); 1822 } 1823 } 1824 } 1825 1826 private boolean select; 1827 } 1828 1829 /* 1830 * Position the caret to the end of the word. 1831 * @see DefaultEditorKit#endWordAction 1832 * @see DefaultEditorKit#selectEndWordAction 1833 * @see DefaultEditorKit#getActions 1834 */ 1835 @SuppressWarnings("serial") // Superclass is not serializable across versions 1836 static class EndWordAction extends TextAction { 1837 1838 /** 1839 * Create this action with the appropriate identifier. 1840 * @param nm the name of the action, Action.NAME. 1841 * @param select whether to extend the selection when 1842 * changing the caret position. 1843 */ 1844 EndWordAction(String nm, boolean select) { 1845 super(nm); 1846 this.select = select; 1847 } 1848 1849 /** The operation to perform when this action is triggered. */ 1850 public void actionPerformed(ActionEvent e) { 1851 JTextComponent target = getTextComponent(e); 1852 if (target != null) { 1853 try { 1854 int offs = target.getCaretPosition(); 1855 int endOffs = Utilities.getWordEnd(target, offs); 1856 if (select) { 1857 target.moveCaretPosition(endOffs); 1858 } else { 1859 target.setCaretPosition(endOffs); 1860 } 1861 } catch (BadLocationException bl) { 1862 UIManager.getLookAndFeel().provideErrorFeedback(target); 1863 } 1864 } 1865 } 1866 1867 private boolean select; 1868 } 1869 1870 /* 1871 * Position the caret to the beginning of the previous word. 1872 * @see DefaultEditorKit#previousWordAction 1873 * @see DefaultEditorKit#selectPreviousWordAction 1874 * @see DefaultEditorKit#getActions 1875 */ 1876 @SuppressWarnings("serial") // Superclass is not serializable across versions 1877 static class PreviousWordAction extends TextAction { 1878 1879 /** 1880 * Create this action with the appropriate identifier. 1881 * @param nm the name of the action, Action.NAME. 1882 * @param select whether to extend the selection when 1883 * changing the caret position. 1884 */ 1885 PreviousWordAction(String nm, boolean select) { 1886 super(nm); 1887 this.select = select; 1888 } 1889 1890 /** The operation to perform when this action is triggered. */ 1891 public void actionPerformed(ActionEvent e) { 1892 JTextComponent target = getTextComponent(e); 1893 if (target != null) { 1894 int offs = target.getCaretPosition(); 1895 boolean failed = false; 1896 try { 1897 Element curPara = 1898 Utilities.getParagraphElement(target, offs); 1899 offs = Utilities.getPreviousWord(target, offs); 1900 if(offs < curPara.getStartOffset()) { 1901 // we should first move to the end of the 1902 // previous paragraph (bug #4278839) 1903 offs = Utilities.getParagraphElement(target, offs). 1904 getEndOffset() - 1; 1905 } 1906 } catch (BadLocationException bl) { 1907 if (offs != 0) { 1908 offs = 0; 1909 } 1910 else { 1911 failed = true; 1912 } 1913 } 1914 if (!failed) { 1915 if (select) { 1916 target.moveCaretPosition(offs); 1917 } else { 1918 target.setCaretPosition(offs); 1919 } 1920 } 1921 else { 1922 UIManager.getLookAndFeel().provideErrorFeedback(target); 1923 } 1924 } 1925 } 1926 1927 private boolean select; 1928 } 1929 1930 /* 1931 * Position the caret to the next of the word. 1932 * @see DefaultEditorKit#nextWordAction 1933 * @see DefaultEditorKit#selectNextWordAction 1934 * @see DefaultEditorKit#getActions 1935 */ 1936 @SuppressWarnings("serial") // Superclass is not serializable across versions 1937 static class NextWordAction extends TextAction { 1938 1939 /** 1940 * Create this action with the appropriate identifier. 1941 * @param nm the name of the action, Action.NAME. 1942 * @param select whether to extend the selection when 1943 * changing the caret position. 1944 */ 1945 NextWordAction(String nm, boolean select) { 1946 super(nm); 1947 this.select = select; 1948 } 1949 1950 /** The operation to perform when this action is triggered. */ 1951 public void actionPerformed(ActionEvent e) { 1952 JTextComponent target = getTextComponent(e); 1953 if (target != null) { 1954 int offs = target.getCaretPosition(); 1955 boolean failed = false; 1956 int oldOffs = offs; 1957 Element curPara = 1958 Utilities.getParagraphElement(target, offs); 1959 try { 1960 offs = Utilities.getNextWord(target, offs); 1961 if(offs >= curPara.getEndOffset() && 1962 oldOffs != curPara.getEndOffset() - 1) { 1963 // we should first move to the end of current 1964 // paragraph (bug #4278839) 1965 offs = curPara.getEndOffset() - 1; 1966 } 1967 } catch (BadLocationException bl) { 1968 int end = target.getDocument().getLength(); 1969 if (offs != end) { 1970 if(oldOffs != curPara.getEndOffset() - 1) { 1971 offs = curPara.getEndOffset() - 1; 1972 } else { 1973 offs = end; 1974 } 1975 } 1976 else { 1977 failed = true; 1978 } 1979 } 1980 if (!failed) { 1981 if (select) { 1982 target.moveCaretPosition(offs); 1983 } else { 1984 target.setCaretPosition(offs); 1985 } 1986 } 1987 else { 1988 UIManager.getLookAndFeel().provideErrorFeedback(target); 1989 } 1990 } 1991 } 1992 1993 private boolean select; 1994 } 1995 1996 /* 1997 * Position the caret to the beginning of the line. 1998 * @see DefaultEditorKit#beginLineAction 1999 * @see DefaultEditorKit#selectBeginLineAction 2000 * @see DefaultEditorKit#getActions 2001 */ 2002 @SuppressWarnings("serial") // Superclass is not serializable across versions 2003 static class BeginLineAction extends TextAction { 2004 2005 /** 2006 * Create this action with the appropriate identifier. 2007 * @param nm the name of the action, Action.NAME. 2008 * @param select whether to extend the selection when 2009 * changing the caret position. 2010 */ 2011 BeginLineAction(String nm, boolean select) { 2012 super(nm); 2013 this.select = select; 2014 } 2015 2016 /** The operation to perform when this action is triggered. */ 2017 public void actionPerformed(ActionEvent e) { 2018 JTextComponent target = getTextComponent(e); 2019 if (target != null) { 2020 try { 2021 int offs = target.getCaretPosition(); 2022 int begOffs = Utilities.getRowStart(target, offs); 2023 if (select) { 2024 target.moveCaretPosition(begOffs); 2025 } else { 2026 target.setCaretPosition(begOffs); 2027 } 2028 } catch (BadLocationException bl) { 2029 UIManager.getLookAndFeel().provideErrorFeedback(target); 2030 } 2031 } 2032 } 2033 2034 private boolean select; 2035 } 2036 2037 /* 2038 * Position the caret to the end of the line. 2039 * @see DefaultEditorKit#endLineAction 2040 * @see DefaultEditorKit#selectEndLineAction 2041 * @see DefaultEditorKit#getActions 2042 */ 2043 @SuppressWarnings("serial") // Superclass is not serializable across versions 2044 static class EndLineAction extends TextAction { 2045 2046 /** 2047 * Create this action with the appropriate identifier. 2048 * @param nm the name of the action, Action.NAME. 2049 * @param select whether to extend the selection when 2050 * changing the caret position. 2051 */ 2052 EndLineAction(String nm, boolean select) { 2053 super(nm); 2054 this.select = select; 2055 } 2056 2057 /** The operation to perform when this action is triggered. */ 2058 public void actionPerformed(ActionEvent e) { 2059 JTextComponent target = getTextComponent(e); 2060 if (target != null) { 2061 try { 2062 int offs = target.getCaretPosition(); 2063 int endOffs = Utilities.getRowEnd(target, offs); 2064 if (select) { 2065 target.moveCaretPosition(endOffs); 2066 } else { 2067 target.setCaretPosition(endOffs); 2068 } 2069 } catch (BadLocationException bl) { 2070 UIManager.getLookAndFeel().provideErrorFeedback(target); 2071 } 2072 } 2073 } 2074 2075 private boolean select; 2076 } 2077 2078 /* 2079 * Position the caret to the beginning of the paragraph. 2080 * @see DefaultEditorKit#beginParagraphAction 2081 * @see DefaultEditorKit#selectBeginParagraphAction 2082 * @see DefaultEditorKit#getActions 2083 */ 2084 @SuppressWarnings("serial") // Superclass is not serializable across versions 2085 static class BeginParagraphAction extends TextAction { 2086 2087 /** 2088 * Create this action with the appropriate identifier. 2089 * @param nm the name of the action, Action.NAME. 2090 * @param select whether to extend the selection when 2091 * changing the caret position. 2092 */ 2093 BeginParagraphAction(String nm, boolean select) { 2094 super(nm); 2095 this.select = select; 2096 } 2097 2098 /** The operation to perform when this action is triggered. */ 2099 public void actionPerformed(ActionEvent e) { 2100 JTextComponent target = getTextComponent(e); 2101 if (target != null) { 2102 int offs = target.getCaretPosition(); 2103 Element elem = Utilities.getParagraphElement(target, offs); 2104 offs = elem.getStartOffset(); 2105 if (select) { 2106 target.moveCaretPosition(offs); 2107 } else { 2108 target.setCaretPosition(offs); 2109 } 2110 } 2111 } 2112 2113 private boolean select; 2114 } 2115 2116 /* 2117 * Position the caret to the end of the paragraph. 2118 * @see DefaultEditorKit#endParagraphAction 2119 * @see DefaultEditorKit#selectEndParagraphAction 2120 * @see DefaultEditorKit#getActions 2121 */ 2122 @SuppressWarnings("serial") // Superclass is not serializable across versions 2123 static class EndParagraphAction extends TextAction { 2124 2125 /** 2126 * Create this action with the appropriate identifier. 2127 * @param nm the name of the action, Action.NAME. 2128 * @param select whether to extend the selection when 2129 * changing the caret position. 2130 */ 2131 EndParagraphAction(String nm, boolean select) { 2132 super(nm); 2133 this.select = select; 2134 } 2135 2136 /** The operation to perform when this action is triggered. */ 2137 public void actionPerformed(ActionEvent e) { 2138 JTextComponent target = getTextComponent(e); 2139 if (target != null) { 2140 int offs = target.getCaretPosition(); 2141 Element elem = Utilities.getParagraphElement(target, offs); 2142 offs = Math.min(target.getDocument().getLength(), 2143 elem.getEndOffset()); 2144 if (select) { 2145 target.moveCaretPosition(offs); 2146 } else { 2147 target.setCaretPosition(offs); 2148 } 2149 } 2150 } 2151 2152 private boolean select; 2153 } 2154 2155 /* 2156 * Move the caret to the beginning of the document. 2157 * @see DefaultEditorKit#beginAction 2158 * @see DefaultEditorKit#getActions 2159 */ 2160 @SuppressWarnings("serial") // Superclass is not serializable across versions 2161 static class BeginAction extends TextAction { 2162 2163 /* Create this object with the appropriate identifier. */ 2164 BeginAction(String nm, boolean select) { 2165 super(nm); 2166 this.select = select; 2167 } 2168 2169 /** The operation to perform when this action is triggered. */ 2170 public void actionPerformed(ActionEvent e) { 2171 JTextComponent target = getTextComponent(e); 2172 if (target != null) { 2173 if (select) { 2174 target.moveCaretPosition(0); 2175 } else { 2176 target.setCaretPosition(0); 2177 } 2178 } 2179 } 2180 2181 private boolean select; 2182 } 2183 2184 /* 2185 * Move the caret to the end of the document. 2186 * @see DefaultEditorKit#endAction 2187 * @see DefaultEditorKit#getActions 2188 */ 2189 @SuppressWarnings("serial") // Superclass is not serializable across versions 2190 static class EndAction extends TextAction { 2191 2192 /* Create this object with the appropriate identifier. */ 2193 EndAction(String nm, boolean select) { 2194 super(nm); 2195 this.select = select; 2196 } 2197 2198 /** The operation to perform when this action is triggered. */ 2199 public void actionPerformed(ActionEvent e) { 2200 JTextComponent target = getTextComponent(e); 2201 if (target != null) { 2202 Document doc = target.getDocument(); 2203 int dot = doc.getLength(); 2204 if (select) { 2205 target.moveCaretPosition(dot); 2206 } else { 2207 target.setCaretPosition(dot); 2208 } 2209 } 2210 } 2211 2212 private boolean select; 2213 } 2214 2215 /* 2216 * Select the word around the caret 2217 * @see DefaultEditorKit#endAction 2218 * @see DefaultEditorKit#getActions 2219 */ 2220 @SuppressWarnings("serial") // Superclass is not serializable across versions 2221 static class SelectWordAction extends TextAction { 2222 2223 /** 2224 * Create this action with the appropriate identifier. 2225 */ 2226 SelectWordAction() { 2227 super(selectWordAction); 2228 start = new BeginWordAction("pigdog", false); 2229 end = new EndWordAction("pigdog", true); 2230 } 2231 2232 /** The operation to perform when this action is triggered. */ 2233 public void actionPerformed(ActionEvent e) { 2234 start.actionPerformed(e); 2235 end.actionPerformed(e); 2236 } 2237 2238 private Action start; 2239 private Action end; 2240 } 2241 2242 /* 2243 * Select the line around the caret 2244 * @see DefaultEditorKit#endAction 2245 * @see DefaultEditorKit#getActions 2246 */ 2247 @SuppressWarnings("serial") // Superclass is not serializable across versions 2248 static class SelectLineAction extends TextAction { 2249 2250 /** 2251 * Create this action with the appropriate identifier. 2252 */ 2253 SelectLineAction() { 2254 super(selectLineAction); 2255 start = new BeginLineAction("pigdog", false); 2256 end = new EndLineAction("pigdog", true); 2257 } 2258 2259 /** The operation to perform when this action is triggered. */ 2260 public void actionPerformed(ActionEvent e) { 2261 start.actionPerformed(e); 2262 end.actionPerformed(e); 2263 } 2264 2265 private Action start; 2266 private Action end; 2267 } 2268 2269 /* 2270 * Select the paragraph around the caret 2271 * @see DefaultEditorKit#endAction 2272 * @see DefaultEditorKit#getActions 2273 */ 2274 @SuppressWarnings("serial") // Superclass is not serializable across versions 2275 static class SelectParagraphAction extends TextAction { 2276 2277 /** 2278 * Create this action with the appropriate identifier. 2279 */ 2280 SelectParagraphAction() { 2281 super(selectParagraphAction); 2282 start = new BeginParagraphAction("pigdog", false); 2283 end = new EndParagraphAction("pigdog", true); 2284 } 2285 2286 /** The operation to perform when this action is triggered. */ 2287 public void actionPerformed(ActionEvent e) { 2288 start.actionPerformed(e); 2289 end.actionPerformed(e); 2290 } 2291 2292 private Action start; 2293 private Action end; 2294 } 2295 2296 /* 2297 * Select the entire document 2298 * @see DefaultEditorKit#endAction 2299 * @see DefaultEditorKit#getActions 2300 */ 2301 @SuppressWarnings("serial") // Superclass is not serializable across versions 2302 static class SelectAllAction extends TextAction { 2303 2304 /** 2305 * Create this action with the appropriate identifier. 2306 */ 2307 SelectAllAction() { 2308 super(selectAllAction); 2309 } 2310 2311 /** The operation to perform when this action is triggered. */ 2312 public void actionPerformed(ActionEvent e) { 2313 JTextComponent target = getTextComponent(e); 2314 if (target != null) { 2315 Document doc = target.getDocument(); 2316 target.setCaretPosition(0); 2317 target.moveCaretPosition(doc.getLength()); 2318 } 2319 } 2320 2321 } 2322 2323 /* 2324 * Remove the selection, if any. 2325 * @see DefaultEditorKit#unselectAction 2326 * @see DefaultEditorKit#getActions 2327 */ 2328 @SuppressWarnings("serial") // Superclass is not serializable across versions 2329 static class UnselectAction extends TextAction { 2330 2331 /** 2332 * Create this action with the appropriate identifier. 2333 */ 2334 UnselectAction() { 2335 super(unselectAction); 2336 } 2337 2338 /** The operation to perform when this action is triggered. */ 2339 public void actionPerformed(ActionEvent e) { 2340 JTextComponent target = getTextComponent(e); 2341 if (target != null) { 2342 target.setCaretPosition(target.getCaretPosition()); 2343 } 2344 } 2345 2346 } 2347 2348 /* 2349 * Toggles the ComponentOrientation of the text component. 2350 * @see DefaultEditorKit#toggleComponentOrientationAction 2351 * @see DefaultEditorKit#getActions 2352 */ 2353 @SuppressWarnings("serial") // Superclass is not serializable across versions 2354 static class ToggleComponentOrientationAction extends TextAction { 2355 2356 /** 2357 * Create this action with the appropriate identifier. 2358 */ 2359 ToggleComponentOrientationAction() { 2360 super(toggleComponentOrientationAction); 2361 } 2362 2363 /** The operation to perform when this action is triggered. */ 2364 public void actionPerformed(ActionEvent e) { 2365 JTextComponent target = getTextComponent(e); 2366 if (target != null) { 2367 ComponentOrientation last = target.getComponentOrientation(); 2368 ComponentOrientation next; 2369 if( last == ComponentOrientation.RIGHT_TO_LEFT ) 2370 next = ComponentOrientation.LEFT_TO_RIGHT; 2371 else 2372 next = ComponentOrientation.RIGHT_TO_LEFT; 2373 target.setComponentOrientation(next); 2374 target.repaint(); 2375 } 2376 } 2377 } 2378 2379 }