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