1 /* 2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package javax.swing.text; 26 27 import sun.awt.SunToolkit; 28 29 import java.io.*; 30 import java.awt.*; 31 import java.awt.event.ActionEvent; 32 import java.text.*; 33 import javax.swing.Action; 34 import javax.swing.KeyStroke; 35 import javax.swing.SwingConstants; 36 import javax.swing.UIManager; 37 38 /** 39 * This is the set of things needed by a text component 40 * to be a reasonably functioning editor for some <em>type</em> 41 * of text document. This implementation provides a default 42 * implementation which treats text as plain text and 43 * provides a minimal set of actions for a simple editor. 44 * 45 * <dl> 46 * <dt><b>Newlines</b> 47 * <dd> 48 * There are two properties which deal with newlines. The 49 * system property, <code>line.separator</code>, is defined to be 50 * platform-dependent, either "\n", "\r", or "\r\n". There is also 51 * a property defined in <code>DefaultEditorKit</code>, called 52 * <a href=#EndOfLineStringProperty><code>EndOfLineStringProperty</code></a>, 53 * which is defined automatically when a document is loaded, to be 54 * the first occurrence of any of the newline characters. 55 * When a document is loaded, <code>EndOfLineStringProperty</code> 56 * is set appropriately, and when the document is written back out, the 57 * <code>EndOfLineStringProperty</code> is used. But while the document 58 * is in memory, the "\n" character is used to define a 59 * newline, regardless of how the newline is defined when 60 * the document is on disk. Therefore, for searching purposes, 61 * "\n" should always be used. When a new document is created, 62 * and the <code>EndOfLineStringProperty</code> has not been defined, 63 * it will use the System property when writing out the 64 * document. 65 * <p>Note that <code>EndOfLineStringProperty</code> is set 66 * on the <code>Document</code> using the <code>get/putProperty</code> 67 * methods. Subclasses may override this behavior. 68 * 69 * </dl> 70 * 71 * @author Timothy Prinzing 72 */ 73 public class DefaultEditorKit extends EditorKit { 74 private static final long serialVersionUID = 2948709989644140410L; 75 76 /** 77 * default constructor for DefaultEditorKit 78 */ 79 public DefaultEditorKit() { 80 } 81 82 /** 83 * Gets the MIME type of the data that this 84 * kit represents support for. The default 85 * is <code>text/plain</code>. 86 * 87 * @return the type 88 */ 89 public String getContentType() { 90 return "text/plain"; 91 } 92 93 /** 94 * Fetches a factory that is suitable for producing 95 * views of any models that are produced by this 96 * kit. The default is to have the UI produce the 97 * factory, so this method has no implementation. 98 * 99 * @return the view factory 100 */ 101 public ViewFactory getViewFactory() { 102 return null; 103 } 104 105 /** 106 * Fetches the set of commands that can be used 107 * on a text component that is using a model and 108 * view produced by this kit. 109 * 110 * @return the command list 111 */ 112 public Action[] getActions() { 113 return defaultActions; 114 } 115 116 /** 117 * Fetches a caret that can navigate through views 118 * produced by the associated ViewFactory. 119 * 120 * @return the caret 121 */ 122 public Caret createCaret() { 123 return null; 124 } 125 126 /** 127 * Creates an uninitialized text storage model (PlainDocument) 128 * that is appropriate for this type of editor. 129 * 130 * @return the model 131 */ 132 public Document createDefaultDocument() { 133 return new PlainDocument(); 134 } 135 136 /** 137 * Inserts content from the given stream which is expected 138 * to be in a format appropriate for this kind of content 139 * handler. 140 * 141 * @param in The stream to read from 142 * @param doc The destination for the insertion. 143 * @param pos The location in the document to place the 144 * content >=0. 145 * @exception IOException on any I/O error 146 * @exception BadLocationException if pos represents an invalid 147 * location within the document. 148 */ 149 public void read(InputStream in, Document doc, int pos) 150 throws IOException, BadLocationException { 151 152 read(new InputStreamReader(in), doc, pos); 153 } 154 155 /** 156 * Writes content from a document to the given stream 157 * in a format appropriate for this kind of content handler. 158 * 159 * @param out The stream to write to 160 * @param doc The source for the write. 161 * @param pos The location in the document to fetch the 162 * content >=0. 163 * @param len The amount to write out >=0. 164 * @exception IOException on any I/O error 165 * @exception BadLocationException if pos represents an invalid 166 * location within the document. 167 */ 168 public void write(OutputStream out, Document doc, int pos, int len) 169 throws IOException, BadLocationException { 170 OutputStreamWriter osw = new OutputStreamWriter(out); 171 172 write(osw, doc, pos, len); 173 osw.flush(); 174 } 175 176 /** 177 * Gets the input attributes for the pane. This method exists for 178 * the benefit of StyledEditorKit so that the read method will 179 * pick up the correct attributes to apply to inserted text. 180 * This class's implementation simply returns null. 181 * 182 * @return null 183 */ 184 MutableAttributeSet getInputAttributes() { 185 return null; 186 } 187 188 /** 189 * Inserts content from the given stream, which will be 190 * treated as plain text. 191 * 192 * @param in The stream to read from 193 * @param doc The destination for the insertion. 194 * @param pos The location in the document to place the 195 * content >=0. 196 * @exception IOException on any I/O error 197 * @exception BadLocationException if pos represents an invalid 198 * location within the document. 199 */ 200 public void read(Reader in, Document doc, int pos) 201 throws IOException, BadLocationException { 202 203 char[] buff = new char[4096]; 204 int nch; 205 boolean lastWasCR = false; 206 boolean isCRLF = false; 207 boolean isCR = false; 208 int last; 209 boolean wasEmpty = (doc.getLength() == 0); 210 AttributeSet attr = getInputAttributes(); 211 212 // Read in a block at a time, mapping \r\n to \n, as well as single 213 // \r's to \n's. If a \r\n is encountered, \r\n will be set as the 214 // newline string for the document, if \r is encountered it will 215 // be set as the newline character, otherwise the newline property 216 // for the document will be removed. 217 while ((nch = in.read(buff, 0, buff.length)) != -1) { 218 last = 0; 219 for(int counter = 0; counter < nch; counter++) { 220 switch(buff[counter]) { 221 case '\r': 222 if (lastWasCR) { 223 isCR = true; 224 if (counter == 0) { 225 doc.insertString(pos, "\n", attr); 226 pos++; 227 } 228 else { 229 buff[counter - 1] = '\n'; 230 } 231 } 232 else { 233 lastWasCR = true; 234 } 235 break; 236 case '\n': 237 if (lastWasCR) { 238 if (counter > (last + 1)) { 239 doc.insertString(pos, new String(buff, last, 240 counter - last - 1), attr); 241 pos += (counter - last - 1); 242 } 243 // else nothing to do, can skip \r, next write will 244 // write \n 245 lastWasCR = false; 246 last = counter; 247 isCRLF = true; 248 } 249 break; 250 default: 251 if (lastWasCR) { 252 isCR = true; 253 if (counter == 0) { 254 doc.insertString(pos, "\n", attr); 255 pos++; 256 } 257 else { 258 buff[counter - 1] = '\n'; 259 } 260 lastWasCR = false; 261 } 262 break; 263 } 264 } 265 if (last < nch) { 266 if(lastWasCR) { 267 if (last < (nch - 1)) { 268 doc.insertString(pos, new String(buff, last, 269 nch - last - 1), attr); 270 pos += (nch - last - 1); 271 } 272 } 273 else { 274 doc.insertString(pos, new String(buff, last, 275 nch - last), attr); 276 pos += (nch - last); 277 } 278 } 279 } 280 if (lastWasCR) { 281 doc.insertString(pos, "\n", attr); 282 isCR = true; 283 } 284 if (wasEmpty) { 285 if (isCRLF) { 286 doc.putProperty(EndOfLineStringProperty, "\r\n"); 287 } 288 else if (isCR) { 289 doc.putProperty(EndOfLineStringProperty, "\r"); 290 } 291 else { 292 doc.putProperty(EndOfLineStringProperty, "\n"); 293 } 294 } 295 } 296 297 /** 298 * Writes content from a document to the given stream 299 * as plain text. 300 * 301 * @param out The stream to write to 302 * @param doc The source for the write. 303 * @param pos The location in the document to fetch the 304 * content from >=0. 305 * @param len The amount to write out >=0. 306 * @exception IOException on any I/O error 307 * @exception BadLocationException if pos is not within 0 and 308 * the length of the document. 309 */ 310 public void write(Writer out, Document doc, int pos, int len) 311 throws IOException, BadLocationException { 312 313 if ((pos < 0) || ((pos + len) > doc.getLength())) { 314 throw new BadLocationException("DefaultEditorKit.write", pos); 315 } 316 Segment data = new Segment(); 317 int nleft = len; 318 int offs = pos; 319 Object endOfLineProperty = doc.getProperty(EndOfLineStringProperty); 320 if (endOfLineProperty == null) { 321 try { 322 endOfLineProperty = System.getProperty("line.separator"); 323 } catch (SecurityException se) { } 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 1077 doc.remove(dot - delChars, delChars); 1078 beep = false; 1079 } 1080 } catch (BadLocationException bl) { 1081 } 1082 } 1083 if (beep) { 1084 UIManager.getLookAndFeel().provideErrorFeedback(target); 1085 } 1086 } 1087 } 1088 1089 /* 1090 * Deletes the character of content that follows the 1091 * current caret position. 1092 * @see DefaultEditorKit#deleteNextCharAction 1093 * @see DefaultEditorKit#getActions 1094 */ 1095 @SuppressWarnings("serial") // Superclass is not serializable across versions 1096 static class DeleteNextCharAction extends TextAction { 1097 1098 /* Create this object with the appropriate identifier. */ 1099 DeleteNextCharAction() { 1100 super(deleteNextCharAction); 1101 } 1102 1103 /** The operation to perform when this action is triggered. */ 1104 public void actionPerformed(ActionEvent e) { 1105 JTextComponent target = getTextComponent(e); 1106 boolean beep = true; 1107 if ((target != null) && (target.isEditable())) { 1108 try { 1109 Document doc = target.getDocument(); 1110 Caret caret = target.getCaret(); 1111 int dot = caret.getDot(); 1112 int mark = caret.getMark(); 1113 if (dot != mark) { 1114 doc.remove(Math.min(dot, mark), Math.abs(dot - mark)); 1115 beep = false; 1116 } else if (dot < doc.getLength()) { 1117 int delChars = 1; 1118 1119 if (dot < doc.getLength() - 1) { 1120 String dotChars = doc.getText(dot, 2); 1121 char c0 = dotChars.charAt(0); 1122 char c1 = dotChars.charAt(1); 1123 1124 if (c0 >= '\uD800' && c0 <= '\uDBFF' && 1125 c1 >= '\uDC00' && c1 <= '\uDFFF') { 1126 delChars = 2; 1127 } 1128 } 1129 1130 doc.remove(dot, delChars); 1131 beep = false; 1132 } 1133 } catch (BadLocationException bl) { 1134 } 1135 } 1136 if (beep) { 1137 UIManager.getLookAndFeel().provideErrorFeedback(target); 1138 } 1139 } 1140 } 1141 1142 1143 /* 1144 * Deletes the word that precedes/follows the beginning of the selection. 1145 * @see DefaultEditorKit#getActions 1146 */ 1147 @SuppressWarnings("serial") // Superclass is not serializable across versions 1148 static class DeleteWordAction extends TextAction { 1149 DeleteWordAction(String name) { 1150 super(name); 1151 assert (name == deletePrevWordAction) 1152 || (name == deleteNextWordAction); 1153 } 1154 /** 1155 * The operation to perform when this action is triggered. 1156 * 1157 * @param e the action event 1158 */ 1159 public void actionPerformed(ActionEvent e) { 1160 final JTextComponent target = getTextComponent(e); 1161 if ((target != null) && (e != null)) { 1162 if ((! target.isEditable()) || (! target.isEnabled())) { 1163 UIManager.getLookAndFeel().provideErrorFeedback(target); 1164 return; 1165 } 1166 boolean beep = true; 1167 try { 1168 final int start = target.getSelectionStart(); 1169 final Element line = 1170 Utilities.getParagraphElement(target, start); 1171 int end; 1172 if (deleteNextWordAction == getValue(Action.NAME)) { 1173 end = Utilities. 1174 getNextWordInParagraph(target, line, start, false); 1175 if (end == java.text.BreakIterator.DONE) { 1176 //last word in the paragraph 1177 final int endOfLine = line.getEndOffset(); 1178 if (start == endOfLine - 1) { 1179 //for last position remove last \n 1180 end = endOfLine; 1181 } else { 1182 //remove to the end of the paragraph 1183 end = endOfLine - 1; 1184 } 1185 } 1186 } else { 1187 end = Utilities. 1188 getPrevWordInParagraph(target, line, start); 1189 if (end == java.text.BreakIterator.DONE) { 1190 //there is no previous word in the paragraph 1191 final int startOfLine = line.getStartOffset(); 1192 if (start == startOfLine) { 1193 //for first position remove previous \n 1194 end = startOfLine - 1; 1195 } else { 1196 //remove to the start of the paragraph 1197 end = startOfLine; 1198 } 1199 } 1200 } 1201 int offs = Math.min(start, end); 1202 int len = Math.abs(end - start); 1203 if (offs >= 0) { 1204 target.getDocument().remove(offs, len); 1205 beep = false; 1206 } 1207 } catch (BadLocationException ignore) { 1208 } 1209 if (beep) { 1210 UIManager.getLookAndFeel().provideErrorFeedback(target); 1211 } 1212 } 1213 } 1214 } 1215 1216 1217 /* 1218 * Sets the editor into read-only mode. 1219 * @see DefaultEditorKit#readOnlyAction 1220 * @see DefaultEditorKit#getActions 1221 */ 1222 @SuppressWarnings("serial") // Superclass is not serializable across versions 1223 static class ReadOnlyAction extends TextAction { 1224 1225 /* Create this object with the appropriate identifier. */ 1226 ReadOnlyAction() { 1227 super(readOnlyAction); 1228 } 1229 1230 /** 1231 * The operation to perform when this action is triggered. 1232 * 1233 * @param e the action event 1234 */ 1235 public void actionPerformed(ActionEvent e) { 1236 JTextComponent target = getTextComponent(e); 1237 if (target != null) { 1238 target.setEditable(false); 1239 } 1240 } 1241 } 1242 1243 /* 1244 * Sets the editor into writeable mode. 1245 * @see DefaultEditorKit#writableAction 1246 * @see DefaultEditorKit#getActions 1247 */ 1248 @SuppressWarnings("serial") // Superclass is not serializable across versions 1249 static class WritableAction extends TextAction { 1250 1251 /* Create this object with the appropriate identifier. */ 1252 WritableAction() { 1253 super(writableAction); 1254 } 1255 1256 /** 1257 * The operation to perform when this action is triggered. 1258 * 1259 * @param e the action event 1260 */ 1261 public void actionPerformed(ActionEvent e) { 1262 JTextComponent target = getTextComponent(e); 1263 if (target != null) { 1264 target.setEditable(true); 1265 } 1266 } 1267 } 1268 1269 /** 1270 * Cuts the selected region and place its contents 1271 * into the system clipboard. 1272 * <p> 1273 * <strong>Warning:</strong> 1274 * Serialized objects of this class will not be compatible with 1275 * future Swing releases. The current serialization support is 1276 * appropriate for short term storage or RMI between applications running 1277 * the same version of Swing. As of 1.4, support for long term storage 1278 * of all JavaBeans™ 1279 * has been added to the <code>java.beans</code> package. 1280 * Please see {@link java.beans.XMLEncoder}. 1281 * 1282 * @see DefaultEditorKit#cutAction 1283 * @see DefaultEditorKit#getActions 1284 */ 1285 @SuppressWarnings("serial") // Same-version serialization only 1286 public static class CutAction extends TextAction { 1287 1288 /** Create this object with the appropriate identifier. */ 1289 public CutAction() { 1290 super(cutAction); 1291 } 1292 1293 /** 1294 * The operation to perform when this action is triggered. 1295 * 1296 * @param e the action event 1297 */ 1298 public void actionPerformed(ActionEvent e) { 1299 JTextComponent target = getTextComponent(e); 1300 if (target != null) { 1301 target.cut(); 1302 } 1303 } 1304 } 1305 1306 /** 1307 * Copies the selected region and place its contents 1308 * into the system clipboard. 1309 * <p> 1310 * <strong>Warning:</strong> 1311 * Serialized objects of this class will not be compatible with 1312 * future Swing releases. The current serialization support is 1313 * appropriate for short term storage or RMI between applications running 1314 * the same version of Swing. As of 1.4, support for long term storage 1315 * of all JavaBeans™ 1316 * has been added to the <code>java.beans</code> package. 1317 * Please see {@link java.beans.XMLEncoder}. 1318 * 1319 * @see DefaultEditorKit#copyAction 1320 * @see DefaultEditorKit#getActions 1321 */ 1322 @SuppressWarnings("serial") // Same-version serialization only 1323 public static class CopyAction extends TextAction { 1324 1325 /** Create this object with the appropriate identifier. */ 1326 public CopyAction() { 1327 super(copyAction); 1328 } 1329 1330 /** 1331 * The operation to perform when this action is triggered. 1332 * 1333 * @param e the action event 1334 */ 1335 public void actionPerformed(ActionEvent e) { 1336 JTextComponent target = getTextComponent(e); 1337 if (target != null) { 1338 target.copy(); 1339 } 1340 } 1341 } 1342 1343 /** 1344 * Pastes the contents of the system clipboard into the 1345 * selected region, or before the caret if nothing is 1346 * selected. 1347 * <p> 1348 * <strong>Warning:</strong> 1349 * Serialized objects of this class will not be compatible with 1350 * future Swing releases. The current serialization support is 1351 * appropriate for short term storage or RMI between applications running 1352 * the same version of Swing. As of 1.4, support for long term storage 1353 * of all JavaBeans™ 1354 * has been added to the <code>java.beans</code> package. 1355 * Please see {@link java.beans.XMLEncoder}. 1356 * 1357 * @see DefaultEditorKit#pasteAction 1358 * @see DefaultEditorKit#getActions 1359 */ 1360 @SuppressWarnings("serial") // Same-version serialization only 1361 public static class PasteAction extends TextAction { 1362 1363 /** Create this object with the appropriate identifier. */ 1364 public PasteAction() { 1365 super(pasteAction); 1366 } 1367 1368 /** 1369 * The operation to perform when this action is triggered. 1370 * 1371 * @param e the action event 1372 */ 1373 public void actionPerformed(ActionEvent e) { 1374 JTextComponent target = getTextComponent(e); 1375 if (target != null) { 1376 target.paste(); 1377 } 1378 } 1379 } 1380 1381 /** 1382 * Creates a beep. 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#beepAction 1394 * @see DefaultEditorKit#getActions 1395 */ 1396 @SuppressWarnings("serial") // Same-version serialization only 1397 public static class BeepAction extends TextAction { 1398 1399 /** Create this object with the appropriate identifier. */ 1400 public BeepAction() { 1401 super(beepAction); 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 UIManager.getLookAndFeel().provideErrorFeedback(target); 1412 } 1413 } 1414 1415 /** 1416 * Scrolls up/down vertically. The select version of this action extends 1417 * the selection, instead of simply moving the caret. 1418 * 1419 * @see DefaultEditorKit#pageUpAction 1420 * @see DefaultEditorKit#pageDownAction 1421 * @see DefaultEditorKit#getActions 1422 */ 1423 @SuppressWarnings("serial") // Superclass is not serializable across versions 1424 static class VerticalPageAction extends TextAction { 1425 1426 /** Create this object with the appropriate identifier. */ 1427 public VerticalPageAction(String nm, int direction, boolean select) { 1428 super(nm); 1429 this.select = select; 1430 this.direction = direction; 1431 } 1432 1433 /** The operation to perform when this action is triggered. */ 1434 public void actionPerformed(ActionEvent e) { 1435 JTextComponent target = getTextComponent(e); 1436 if (target != null) { 1437 Rectangle visible = target.getVisibleRect(); 1438 Rectangle newVis = new Rectangle(visible); 1439 int selectedIndex = target.getCaretPosition(); 1440 int scrollAmount = direction * 1441 target.getScrollableBlockIncrement( 1442 visible, SwingConstants.VERTICAL, direction); 1443 int initialY = visible.y; 1444 Caret caret = target.getCaret(); 1445 Point magicPosition = caret.getMagicCaretPosition(); 1446 1447 if (selectedIndex != -1) { 1448 try { 1449 Rectangle dotBounds = target.modelToView( 1450 selectedIndex); 1451 int x = (magicPosition != null) ? magicPosition.x : 1452 dotBounds.x; 1453 int h = dotBounds.height; 1454 if (h > 0) { 1455 // We want to scroll by a multiple of caret height, 1456 // rounding towards lower integer 1457 scrollAmount = scrollAmount / h * h; 1458 } 1459 newVis.y = constrainY(target, 1460 initialY + scrollAmount, visible.height); 1461 1462 int newIndex; 1463 1464 if (visible.contains(dotBounds.x, dotBounds.y)) { 1465 // Dot is currently visible, base the new 1466 // location off the old, or 1467 newIndex = target.viewToModel( 1468 new Point(x, constrainY(target, 1469 dotBounds.y + scrollAmount, 0))); 1470 } 1471 else { 1472 // Dot isn't visible, choose the top or the bottom 1473 // for the new location. 1474 if (direction == -1) { 1475 newIndex = target.viewToModel(new Point( 1476 x, newVis.y)); 1477 } 1478 else { 1479 newIndex = target.viewToModel(new Point( 1480 x, newVis.y + visible.height)); 1481 } 1482 } 1483 newIndex = constrainOffset(target, newIndex); 1484 if (newIndex != selectedIndex) { 1485 // Make sure the new visible location contains 1486 // the location of dot, otherwise Caret will 1487 // cause an additional scroll. 1488 int newY = getAdjustedY(target, newVis, newIndex); 1489 1490 if (direction == -1 && newY <= initialY || direction == 1 && newY >= initialY) { 1491 // Change index and correct newVis.y only if won't cause scrolling upward 1492 newVis.y = newY; 1493 1494 if (select) { 1495 target.moveCaretPosition(newIndex); 1496 } else { 1497 target.setCaretPosition(newIndex); 1498 } 1499 } 1500 } 1501 } catch (BadLocationException ble) { } 1502 } else { 1503 newVis.y = constrainY(target, 1504 initialY + scrollAmount, visible.height); 1505 } 1506 if (magicPosition != null) { 1507 caret.setMagicCaretPosition(magicPosition); 1508 } 1509 target.scrollRectToVisible(newVis); 1510 } 1511 } 1512 1513 /** 1514 * Makes sure <code>y</code> is a valid location in 1515 * <code>target</code>. 1516 */ 1517 private int constrainY(JTextComponent target, int y, int vis) { 1518 if (y < 0) { 1519 y = 0; 1520 } 1521 else if (y + vis > target.getHeight()) { 1522 y = Math.max(0, target.getHeight() - vis); 1523 } 1524 return y; 1525 } 1526 1527 /** 1528 * Ensures that <code>offset</code> is a valid offset into the 1529 * model for <code>text</code>. 1530 */ 1531 private int constrainOffset(JTextComponent text, int offset) { 1532 Document doc = text.getDocument(); 1533 1534 if ((offset != 0) && (offset > doc.getLength())) { 1535 offset = doc.getLength(); 1536 } 1537 if (offset < 0) { 1538 offset = 0; 1539 } 1540 return offset; 1541 } 1542 1543 /** 1544 * Returns adjustsed {@code y} position that indicates the location to scroll to 1545 * after selecting <code>index</code>. 1546 */ 1547 private int getAdjustedY(JTextComponent text, Rectangle visible, int index) { 1548 int result = visible.y; 1549 1550 try { 1551 Rectangle dotBounds = text.modelToView(index); 1552 1553 if (dotBounds.y < visible.y) { 1554 result = dotBounds.y; 1555 } else { 1556 if ((dotBounds.y > visible.y + visible.height) || 1557 (dotBounds.y + dotBounds.height > visible.y + visible.height)) { 1558 result = dotBounds.y + dotBounds.height - visible.height; 1559 } 1560 } 1561 } catch (BadLocationException ble) { 1562 } 1563 1564 return result; 1565 } 1566 1567 /** 1568 * Adjusts the Rectangle to contain the bounds of the character at 1569 * <code>index</code> in response to a page up. 1570 */ 1571 private boolean select; 1572 1573 /** 1574 * Direction to scroll, 1 is down, -1 is up. 1575 */ 1576 private int direction; 1577 } 1578 1579 1580 /** 1581 * Pages one view to the left or right. 1582 */ 1583 @SuppressWarnings("serial") // Superclass is not serializable across versions 1584 static class PageAction extends TextAction { 1585 1586 /** Create this object with the appropriate identifier. */ 1587 public PageAction(String nm, boolean left, boolean select) { 1588 super(nm); 1589 this.select = select; 1590 this.left = left; 1591 } 1592 1593 /** The operation to perform when this action is triggered. */ 1594 public void actionPerformed(ActionEvent e) { 1595 JTextComponent target = getTextComponent(e); 1596 if (target != null) { 1597 int selectedIndex; 1598 Rectangle visible = new Rectangle(); 1599 target.computeVisibleRect(visible); 1600 if (left) { 1601 visible.x = Math.max(0, visible.x - visible.width); 1602 } 1603 else { 1604 visible.x += visible.width; 1605 } 1606 1607 selectedIndex = target.getCaretPosition(); 1608 if(selectedIndex != -1) { 1609 if (left) { 1610 selectedIndex = target.viewToModel 1611 (new Point(visible.x, visible.y)); 1612 } 1613 else { 1614 selectedIndex = target.viewToModel 1615 (new Point(visible.x + visible.width - 1, 1616 visible.y + visible.height - 1)); 1617 } 1618 Document doc = target.getDocument(); 1619 if ((selectedIndex != 0) && 1620 (selectedIndex > (doc.getLength()-1))) { 1621 selectedIndex = doc.getLength()-1; 1622 } 1623 else if(selectedIndex < 0) { 1624 selectedIndex = 0; 1625 } 1626 if (select) 1627 target.moveCaretPosition(selectedIndex); 1628 else 1629 target.setCaretPosition(selectedIndex); 1630 } 1631 } 1632 } 1633 1634 private boolean select; 1635 private boolean left; 1636 } 1637 1638 @SuppressWarnings("serial") // Superclass is not serializable across versions 1639 static class DumpModelAction extends TextAction { 1640 1641 DumpModelAction() { 1642 super("dump-model"); 1643 } 1644 1645 public void actionPerformed(ActionEvent e) { 1646 JTextComponent target = getTextComponent(e); 1647 if (target != null) { 1648 Document d = target.getDocument(); 1649 if (d instanceof AbstractDocument) { 1650 ((AbstractDocument) d).dump(System.err); 1651 } 1652 } 1653 } 1654 } 1655 1656 /* 1657 * Action to move the selection by way of the 1658 * getNextVisualPositionFrom method. Constructor indicates direction 1659 * to use. 1660 */ 1661 @SuppressWarnings("serial") // Superclass is not serializable across versions 1662 static class NextVisualPositionAction extends TextAction { 1663 1664 /** 1665 * Create this action with the appropriate identifier. 1666 * @param nm the name of the action, Action.NAME. 1667 * @param select whether to extend the selection when 1668 * changing the caret position. 1669 */ 1670 NextVisualPositionAction(String nm, boolean select, int direction) { 1671 super(nm); 1672 this.select = select; 1673 this.direction = direction; 1674 } 1675 1676 /** The operation to perform when this action is triggered. */ 1677 public void actionPerformed(ActionEvent e) { 1678 JTextComponent target = getTextComponent(e); 1679 if (target != null) { 1680 Caret caret = target.getCaret(); 1681 DefaultCaret bidiCaret = (caret instanceof DefaultCaret) ? 1682 (DefaultCaret)caret : null; 1683 int dot = caret.getDot(); 1684 Position.Bias[] bias = new Position.Bias[1]; 1685 Point magicPosition = caret.getMagicCaretPosition(); 1686 1687 try { 1688 if(magicPosition == null && 1689 (direction == SwingConstants.NORTH || 1690 direction == SwingConstants.SOUTH)) { 1691 Rectangle r = (bidiCaret != null) ? 1692 target.getUI().modelToView(target, dot, 1693 bidiCaret.getDotBias()) : 1694 target.modelToView(dot); 1695 magicPosition = new Point(r.x, r.y); 1696 } 1697 1698 NavigationFilter filter = target.getNavigationFilter(); 1699 1700 if (filter != null) { 1701 dot = filter.getNextVisualPositionFrom 1702 (target, dot, (bidiCaret != null) ? 1703 bidiCaret.getDotBias() : 1704 Position.Bias.Forward, direction, bias); 1705 } 1706 else { 1707 dot = target.getUI().getNextVisualPositionFrom 1708 (target, dot, (bidiCaret != null) ? 1709 bidiCaret.getDotBias() : 1710 Position.Bias.Forward, direction, bias); 1711 } 1712 if(bias[0] == null) { 1713 bias[0] = Position.Bias.Forward; 1714 } 1715 if(bidiCaret != null) { 1716 if (select) { 1717 bidiCaret.moveDot(dot, bias[0]); 1718 } else { 1719 bidiCaret.setDot(dot, bias[0]); 1720 } 1721 } 1722 else { 1723 if (select) { 1724 caret.moveDot(dot); 1725 } else { 1726 caret.setDot(dot); 1727 } 1728 } 1729 if(magicPosition != null && 1730 (direction == SwingConstants.NORTH || 1731 direction == SwingConstants.SOUTH)) { 1732 target.getCaret().setMagicCaretPosition(magicPosition); 1733 } 1734 } catch (BadLocationException ex) { 1735 } 1736 } 1737 } 1738 1739 private boolean select; 1740 private int direction; 1741 } 1742 1743 /* 1744 * Position the caret to the beginning of the word. 1745 * @see DefaultEditorKit#beginWordAction 1746 * @see DefaultEditorKit#selectBeginWordAction 1747 * @see DefaultEditorKit#getActions 1748 */ 1749 @SuppressWarnings("serial") // Superclass is not serializable across versions 1750 static class BeginWordAction extends TextAction { 1751 1752 /** 1753 * Create this action with the appropriate identifier. 1754 * @param nm the name of the action, Action.NAME. 1755 * @param select whether to extend the selection when 1756 * changing the caret position. 1757 */ 1758 BeginWordAction(String nm, boolean select) { 1759 super(nm); 1760 this.select = select; 1761 } 1762 1763 /** The operation to perform when this action is triggered. */ 1764 public void actionPerformed(ActionEvent e) { 1765 JTextComponent target = getTextComponent(e); 1766 if (target != null) { 1767 try { 1768 int offs = target.getCaretPosition(); 1769 int begOffs = Utilities.getWordStart(target, offs); 1770 if (select) { 1771 target.moveCaretPosition(begOffs); 1772 } else { 1773 target.setCaretPosition(begOffs); 1774 } 1775 } catch (BadLocationException bl) { 1776 UIManager.getLookAndFeel().provideErrorFeedback(target); 1777 } 1778 } 1779 } 1780 1781 private boolean select; 1782 } 1783 1784 /* 1785 * Position the caret to the end of the word. 1786 * @see DefaultEditorKit#endWordAction 1787 * @see DefaultEditorKit#selectEndWordAction 1788 * @see DefaultEditorKit#getActions 1789 */ 1790 @SuppressWarnings("serial") // Superclass is not serializable across versions 1791 static class EndWordAction extends TextAction { 1792 1793 /** 1794 * Create this action with the appropriate identifier. 1795 * @param nm the name of the action, Action.NAME. 1796 * @param select whether to extend the selection when 1797 * changing the caret position. 1798 */ 1799 EndWordAction(String nm, boolean select) { 1800 super(nm); 1801 this.select = select; 1802 } 1803 1804 /** The operation to perform when this action is triggered. */ 1805 public void actionPerformed(ActionEvent e) { 1806 JTextComponent target = getTextComponent(e); 1807 if (target != null) { 1808 try { 1809 int offs = target.getCaretPosition(); 1810 int endOffs = Utilities.getWordEnd(target, offs); 1811 if (select) { 1812 target.moveCaretPosition(endOffs); 1813 } else { 1814 target.setCaretPosition(endOffs); 1815 } 1816 } catch (BadLocationException bl) { 1817 UIManager.getLookAndFeel().provideErrorFeedback(target); 1818 } 1819 } 1820 } 1821 1822 private boolean select; 1823 } 1824 1825 /* 1826 * Position the caret to the beginning of the previous word. 1827 * @see DefaultEditorKit#previousWordAction 1828 * @see DefaultEditorKit#selectPreviousWordAction 1829 * @see DefaultEditorKit#getActions 1830 */ 1831 @SuppressWarnings("serial") // Superclass is not serializable across versions 1832 static class PreviousWordAction extends TextAction { 1833 1834 /** 1835 * Create this action with the appropriate identifier. 1836 * @param nm the name of the action, Action.NAME. 1837 * @param select whether to extend the selection when 1838 * changing the caret position. 1839 */ 1840 PreviousWordAction(String nm, boolean select) { 1841 super(nm); 1842 this.select = select; 1843 } 1844 1845 /** The operation to perform when this action is triggered. */ 1846 public void actionPerformed(ActionEvent e) { 1847 JTextComponent target = getTextComponent(e); 1848 if (target != null) { 1849 int offs = target.getCaretPosition(); 1850 boolean failed = false; 1851 try { 1852 Element curPara = 1853 Utilities.getParagraphElement(target, offs); 1854 offs = Utilities.getPreviousWord(target, offs); 1855 if(offs < curPara.getStartOffset()) { 1856 // we should first move to the end of the 1857 // previous paragraph (bug #4278839) 1858 offs = Utilities.getParagraphElement(target, offs). 1859 getEndOffset() - 1; 1860 } 1861 } catch (BadLocationException bl) { 1862 if (offs != 0) { 1863 offs = 0; 1864 } 1865 else { 1866 failed = true; 1867 } 1868 } 1869 if (!failed) { 1870 if (select) { 1871 target.moveCaretPosition(offs); 1872 } else { 1873 target.setCaretPosition(offs); 1874 } 1875 } 1876 else { 1877 UIManager.getLookAndFeel().provideErrorFeedback(target); 1878 } 1879 } 1880 } 1881 1882 private boolean select; 1883 } 1884 1885 /* 1886 * Position the caret to the next of the word. 1887 * @see DefaultEditorKit#nextWordAction 1888 * @see DefaultEditorKit#selectNextWordAction 1889 * @see DefaultEditorKit#getActions 1890 */ 1891 @SuppressWarnings("serial") // Superclass is not serializable across versions 1892 static class NextWordAction extends TextAction { 1893 1894 /** 1895 * Create this action with the appropriate identifier. 1896 * @param nm the name of the action, Action.NAME. 1897 * @param select whether to extend the selection when 1898 * changing the caret position. 1899 */ 1900 NextWordAction(String nm, boolean select) { 1901 super(nm); 1902 this.select = select; 1903 } 1904 1905 /** The operation to perform when this action is triggered. */ 1906 public void actionPerformed(ActionEvent e) { 1907 JTextComponent target = getTextComponent(e); 1908 if (target != null) { 1909 int offs = target.getCaretPosition(); 1910 boolean failed = false; 1911 int oldOffs = offs; 1912 Element curPara = 1913 Utilities.getParagraphElement(target, offs); 1914 try { 1915 offs = Utilities.getNextWord(target, offs); 1916 if(offs >= curPara.getEndOffset() && 1917 oldOffs != curPara.getEndOffset() - 1) { 1918 // we should first move to the end of current 1919 // paragraph (bug #4278839) 1920 offs = curPara.getEndOffset() - 1; 1921 } 1922 } catch (BadLocationException bl) { 1923 int end = target.getDocument().getLength(); 1924 if (offs != end) { 1925 if(oldOffs != curPara.getEndOffset() - 1) { 1926 offs = curPara.getEndOffset() - 1; 1927 } else { 1928 offs = end; 1929 } 1930 } 1931 else { 1932 failed = true; 1933 } 1934 } 1935 if (!failed) { 1936 if (select) { 1937 target.moveCaretPosition(offs); 1938 } else { 1939 target.setCaretPosition(offs); 1940 } 1941 } 1942 else { 1943 UIManager.getLookAndFeel().provideErrorFeedback(target); 1944 } 1945 } 1946 } 1947 1948 private boolean select; 1949 } 1950 1951 /* 1952 * Position the caret to the beginning of the line. 1953 * @see DefaultEditorKit#beginLineAction 1954 * @see DefaultEditorKit#selectBeginLineAction 1955 * @see DefaultEditorKit#getActions 1956 */ 1957 @SuppressWarnings("serial") // Superclass is not serializable across versions 1958 static class BeginLineAction extends TextAction { 1959 1960 /** 1961 * Create this action with the appropriate identifier. 1962 * @param nm the name of the action, Action.NAME. 1963 * @param select whether to extend the selection when 1964 * changing the caret position. 1965 */ 1966 BeginLineAction(String nm, boolean select) { 1967 super(nm); 1968 this.select = select; 1969 } 1970 1971 /** The operation to perform when this action is triggered. */ 1972 public void actionPerformed(ActionEvent e) { 1973 JTextComponent target = getTextComponent(e); 1974 if (target != null) { 1975 try { 1976 int offs = target.getCaretPosition(); 1977 int begOffs = Utilities.getRowStart(target, offs); 1978 if (select) { 1979 target.moveCaretPosition(begOffs); 1980 } else { 1981 target.setCaretPosition(begOffs); 1982 } 1983 } catch (BadLocationException bl) { 1984 UIManager.getLookAndFeel().provideErrorFeedback(target); 1985 } 1986 } 1987 } 1988 1989 private boolean select; 1990 } 1991 1992 /* 1993 * Position the caret to the end of the line. 1994 * @see DefaultEditorKit#endLineAction 1995 * @see DefaultEditorKit#selectEndLineAction 1996 * @see DefaultEditorKit#getActions 1997 */ 1998 @SuppressWarnings("serial") // Superclass is not serializable across versions 1999 static class EndLineAction extends TextAction { 2000 2001 /** 2002 * Create this action with the appropriate identifier. 2003 * @param nm the name of the action, Action.NAME. 2004 * @param select whether to extend the selection when 2005 * changing the caret position. 2006 */ 2007 EndLineAction(String nm, boolean select) { 2008 super(nm); 2009 this.select = select; 2010 } 2011 2012 /** The operation to perform when this action is triggered. */ 2013 public void actionPerformed(ActionEvent e) { 2014 JTextComponent target = getTextComponent(e); 2015 if (target != null) { 2016 try { 2017 int offs = target.getCaretPosition(); 2018 int endOffs = Utilities.getRowEnd(target, offs); 2019 if (select) { 2020 target.moveCaretPosition(endOffs); 2021 } else { 2022 target.setCaretPosition(endOffs); 2023 } 2024 } catch (BadLocationException bl) { 2025 UIManager.getLookAndFeel().provideErrorFeedback(target); 2026 } 2027 } 2028 } 2029 2030 private boolean select; 2031 } 2032 2033 /* 2034 * Position the caret to the beginning of the paragraph. 2035 * @see DefaultEditorKit#beginParagraphAction 2036 * @see DefaultEditorKit#selectBeginParagraphAction 2037 * @see DefaultEditorKit#getActions 2038 */ 2039 @SuppressWarnings("serial") // Superclass is not serializable across versions 2040 static class BeginParagraphAction extends TextAction { 2041 2042 /** 2043 * Create this action with the appropriate identifier. 2044 * @param nm the name of the action, Action.NAME. 2045 * @param select whether to extend the selection when 2046 * changing the caret position. 2047 */ 2048 BeginParagraphAction(String nm, boolean select) { 2049 super(nm); 2050 this.select = select; 2051 } 2052 2053 /** The operation to perform when this action is triggered. */ 2054 public void actionPerformed(ActionEvent e) { 2055 JTextComponent target = getTextComponent(e); 2056 if (target != null) { 2057 int offs = target.getCaretPosition(); 2058 Element elem = Utilities.getParagraphElement(target, offs); 2059 offs = elem.getStartOffset(); 2060 if (select) { 2061 target.moveCaretPosition(offs); 2062 } else { 2063 target.setCaretPosition(offs); 2064 } 2065 } 2066 } 2067 2068 private boolean select; 2069 } 2070 2071 /* 2072 * Position the caret to the end of the paragraph. 2073 * @see DefaultEditorKit#endParagraphAction 2074 * @see DefaultEditorKit#selectEndParagraphAction 2075 * @see DefaultEditorKit#getActions 2076 */ 2077 @SuppressWarnings("serial") // Superclass is not serializable across versions 2078 static class EndParagraphAction extends TextAction { 2079 2080 /** 2081 * Create this action with the appropriate identifier. 2082 * @param nm the name of the action, Action.NAME. 2083 * @param select whether to extend the selection when 2084 * changing the caret position. 2085 */ 2086 EndParagraphAction(String nm, boolean select) { 2087 super(nm); 2088 this.select = select; 2089 } 2090 2091 /** The operation to perform when this action is triggered. */ 2092 public void actionPerformed(ActionEvent e) { 2093 JTextComponent target = getTextComponent(e); 2094 if (target != null) { 2095 int offs = target.getCaretPosition(); 2096 Element elem = Utilities.getParagraphElement(target, offs); 2097 offs = Math.min(target.getDocument().getLength(), 2098 elem.getEndOffset()); 2099 if (select) { 2100 target.moveCaretPosition(offs); 2101 } else { 2102 target.setCaretPosition(offs); 2103 } 2104 } 2105 } 2106 2107 private boolean select; 2108 } 2109 2110 /* 2111 * Move the caret to the beginning of the document. 2112 * @see DefaultEditorKit#beginAction 2113 * @see DefaultEditorKit#getActions 2114 */ 2115 @SuppressWarnings("serial") // Superclass is not serializable across versions 2116 static class BeginAction extends TextAction { 2117 2118 /* Create this object with the appropriate identifier. */ 2119 BeginAction(String nm, boolean select) { 2120 super(nm); 2121 this.select = select; 2122 } 2123 2124 /** The operation to perform when this action is triggered. */ 2125 public void actionPerformed(ActionEvent e) { 2126 JTextComponent target = getTextComponent(e); 2127 if (target != null) { 2128 if (select) { 2129 target.moveCaretPosition(0); 2130 } else { 2131 target.setCaretPosition(0); 2132 } 2133 } 2134 } 2135 2136 private boolean select; 2137 } 2138 2139 /* 2140 * Move the caret to the end of the document. 2141 * @see DefaultEditorKit#endAction 2142 * @see DefaultEditorKit#getActions 2143 */ 2144 @SuppressWarnings("serial") // Superclass is not serializable across versions 2145 static class EndAction extends TextAction { 2146 2147 /* Create this object with the appropriate identifier. */ 2148 EndAction(String nm, boolean select) { 2149 super(nm); 2150 this.select = select; 2151 } 2152 2153 /** The operation to perform when this action is triggered. */ 2154 public void actionPerformed(ActionEvent e) { 2155 JTextComponent target = getTextComponent(e); 2156 if (target != null) { 2157 Document doc = target.getDocument(); 2158 int dot = doc.getLength(); 2159 if (select) { 2160 target.moveCaretPosition(dot); 2161 } else { 2162 target.setCaretPosition(dot); 2163 } 2164 } 2165 } 2166 2167 private boolean select; 2168 } 2169 2170 /* 2171 * Select the word around the caret 2172 * @see DefaultEditorKit#endAction 2173 * @see DefaultEditorKit#getActions 2174 */ 2175 @SuppressWarnings("serial") // Superclass is not serializable across versions 2176 static class SelectWordAction extends TextAction { 2177 2178 /** 2179 * Create this action with the appropriate identifier. 2180 * @param nm the name of the action, Action.NAME. 2181 * @param select whether to extend the selection when 2182 * changing the caret position. 2183 */ 2184 SelectWordAction() { 2185 super(selectWordAction); 2186 start = new BeginWordAction("pigdog", false); 2187 end = new EndWordAction("pigdog", true); 2188 } 2189 2190 /** The operation to perform when this action is triggered. */ 2191 public void actionPerformed(ActionEvent e) { 2192 start.actionPerformed(e); 2193 end.actionPerformed(e); 2194 } 2195 2196 private Action start; 2197 private Action end; 2198 } 2199 2200 /* 2201 * Select the line around the caret 2202 * @see DefaultEditorKit#endAction 2203 * @see DefaultEditorKit#getActions 2204 */ 2205 @SuppressWarnings("serial") // Superclass is not serializable across versions 2206 static class SelectLineAction extends TextAction { 2207 2208 /** 2209 * Create this action with the appropriate identifier. 2210 * @param nm the name of the action, Action.NAME. 2211 * @param select whether to extend the selection when 2212 * changing the caret position. 2213 */ 2214 SelectLineAction() { 2215 super(selectLineAction); 2216 start = new BeginLineAction("pigdog", false); 2217 end = new EndLineAction("pigdog", true); 2218 } 2219 2220 /** The operation to perform when this action is triggered. */ 2221 public void actionPerformed(ActionEvent e) { 2222 start.actionPerformed(e); 2223 end.actionPerformed(e); 2224 } 2225 2226 private Action start; 2227 private Action end; 2228 } 2229 2230 /* 2231 * Select the paragraph around the caret 2232 * @see DefaultEditorKit#endAction 2233 * @see DefaultEditorKit#getActions 2234 */ 2235 @SuppressWarnings("serial") // Superclass is not serializable across versions 2236 static class SelectParagraphAction extends TextAction { 2237 2238 /** 2239 * Create this action with the appropriate identifier. 2240 * @param nm the name of the action, Action.NAME. 2241 * @param select whether to extend the selection when 2242 * changing the caret position. 2243 */ 2244 SelectParagraphAction() { 2245 super(selectParagraphAction); 2246 start = new BeginParagraphAction("pigdog", false); 2247 end = new EndParagraphAction("pigdog", true); 2248 } 2249 2250 /** The operation to perform when this action is triggered. */ 2251 public void actionPerformed(ActionEvent e) { 2252 start.actionPerformed(e); 2253 end.actionPerformed(e); 2254 } 2255 2256 private Action start; 2257 private Action end; 2258 } 2259 2260 /* 2261 * Select the entire document 2262 * @see DefaultEditorKit#endAction 2263 * @see DefaultEditorKit#getActions 2264 */ 2265 @SuppressWarnings("serial") // Superclass is not serializable across versions 2266 static class SelectAllAction extends TextAction { 2267 2268 /** 2269 * Create this action with the appropriate identifier. 2270 * @param nm the name of the action, Action.NAME. 2271 * @param select whether to extend the selection when 2272 * changing the caret position. 2273 */ 2274 SelectAllAction() { 2275 super(selectAllAction); 2276 } 2277 2278 /** The operation to perform when this action is triggered. */ 2279 public void actionPerformed(ActionEvent e) { 2280 JTextComponent target = getTextComponent(e); 2281 if (target != null) { 2282 Document doc = target.getDocument(); 2283 target.setCaretPosition(0); 2284 target.moveCaretPosition(doc.getLength()); 2285 } 2286 } 2287 2288 } 2289 2290 /* 2291 * Remove the selection, if any. 2292 * @see DefaultEditorKit#unselectAction 2293 * @see DefaultEditorKit#getActions 2294 */ 2295 @SuppressWarnings("serial") // Superclass is not serializable across versions 2296 static class UnselectAction extends TextAction { 2297 2298 /** 2299 * Create this action with the appropriate identifier. 2300 */ 2301 UnselectAction() { 2302 super(unselectAction); 2303 } 2304 2305 /** The operation to perform when this action is triggered. */ 2306 public void actionPerformed(ActionEvent e) { 2307 JTextComponent target = getTextComponent(e); 2308 if (target != null) { 2309 target.setCaretPosition(target.getCaretPosition()); 2310 } 2311 } 2312 2313 } 2314 2315 /* 2316 * Toggles the ComponentOrientation of the text component. 2317 * @see DefaultEditorKit#toggleComponentOrientationAction 2318 * @see DefaultEditorKit#getActions 2319 */ 2320 @SuppressWarnings("serial") // Superclass is not serializable across versions 2321 static class ToggleComponentOrientationAction extends TextAction { 2322 2323 /** 2324 * Create this action with the appropriate identifier. 2325 */ 2326 ToggleComponentOrientationAction() { 2327 super(toggleComponentOrientationAction); 2328 } 2329 2330 /** The operation to perform when this action is triggered. */ 2331 public void actionPerformed(ActionEvent e) { 2332 JTextComponent target = getTextComponent(e); 2333 if (target != null) { 2334 ComponentOrientation last = target.getComponentOrientation(); 2335 ComponentOrientation next; 2336 if( last == ComponentOrientation.RIGHT_TO_LEFT ) 2337 next = ComponentOrientation.LEFT_TO_RIGHT; 2338 else 2339 next = ComponentOrientation.RIGHT_TO_LEFT; 2340 target.setComponentOrientation(next); 2341 target.repaint(); 2342 } 2343 } 2344 } 2345 2346 }