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; 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 } 1500 } catch (BadLocationException ble) { } 1501 } else { 1502 newVis.y = constrainY(target, 1503 initialY + scrollAmount, visible.height); 1504 } 1505 if (magicPosition != null) { 1506 caret.setMagicCaretPosition(magicPosition); 1507 } 1508 target.scrollRectToVisible(newVis); 1509 } 1510 } 1511 1512 /** 1513 * Makes sure <code>y</code> is a valid location in 1514 * <code>target</code>. 1515 */ 1516 private int constrainY(JTextComponent target, int y, int vis) { 1517 if (y < 0) { 1518 y = 0; 1519 } 1520 else if (y + vis > target.getHeight()) { 1521 y = Math.max(0, target.getHeight() - vis); 1522 } 1523 return y; 1524 } 1525 1526 /** 1527 * Ensures that <code>offset</code> is a valid offset into the 1528 * model for <code>text</code>. 1529 */ 1530 private int constrainOffset(JTextComponent text, int offset) { 1531 Document doc = text.getDocument(); 1532 1533 if ((offset != 0) && (offset > doc.getLength())) { 1534 offset = doc.getLength(); 1535 } 1536 if (offset < 0) { 1537 offset = 0; 1538 } 1539 return offset; 1540 } 1541 1542 /** 1543 * Returns adjustsed {@code y} position that indicates the location to scroll to 1544 * after selecting <code>index</code>. 1545 */ 1546 @SuppressWarnings("deprecation") 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 @SuppressWarnings("deprecation") 1595 public void actionPerformed(ActionEvent e) { 1596 JTextComponent target = getTextComponent(e); 1597 if (target != null) { 1598 int selectedIndex; 1599 Rectangle visible = new Rectangle(); 1600 target.computeVisibleRect(visible); 1601 if (left) { 1602 visible.x = Math.max(0, visible.x - visible.width); 1603 } 1604 else { 1605 visible.x += visible.width; 1606 } 1607 1608 selectedIndex = target.getCaretPosition(); 1609 if(selectedIndex != -1) { 1610 if (left) { 1611 selectedIndex = target.viewToModel 1612 (new Point(visible.x, visible.y)); 1613 } 1614 else { 1615 selectedIndex = target.viewToModel 1616 (new Point(visible.x + visible.width - 1, 1617 visible.y + visible.height - 1)); 1618 } 1619 Document doc = target.getDocument(); 1620 if ((selectedIndex != 0) && 1621 (selectedIndex > (doc.getLength()-1))) { 1622 selectedIndex = doc.getLength()-1; 1623 } 1624 else if(selectedIndex < 0) { 1625 selectedIndex = 0; 1626 } 1627 if (select) 1628 target.moveCaretPosition(selectedIndex); 1629 else 1630 target.setCaretPosition(selectedIndex); 1631 } 1632 } 1633 } 1634 1635 private boolean select; 1636 private boolean left; 1637 } 1638 1639 @SuppressWarnings("serial") // Superclass is not serializable across versions 1640 static class DumpModelAction extends TextAction { 1641 1642 DumpModelAction() { 1643 super("dump-model"); 1644 } 1645 1646 public void actionPerformed(ActionEvent e) { 1647 JTextComponent target = getTextComponent(e); 1648 if (target != null) { 1649 Document d = target.getDocument(); 1650 if (d instanceof AbstractDocument) { 1651 ((AbstractDocument) d).dump(System.err); 1652 } 1653 } 1654 } 1655 } 1656 1657 /* 1658 * Action to move the selection by way of the 1659 * getNextVisualPositionFrom method. Constructor indicates direction 1660 * to use. 1661 */ 1662 @SuppressWarnings("serial") // Superclass is not serializable across versions 1663 static class NextVisualPositionAction extends TextAction { 1664 1665 /** 1666 * Create this action with the appropriate identifier. 1667 * @param nm the name of the action, Action.NAME. 1668 * @param select whether to extend the selection when 1669 * changing the caret position. 1670 */ 1671 NextVisualPositionAction(String nm, boolean select, int direction) { 1672 super(nm); 1673 this.select = select; 1674 this.direction = direction; 1675 } 1676 1677 /** The operation to perform when this action is triggered. */ 1678 @SuppressWarnings("deprecation") 1679 public void actionPerformed(ActionEvent e) { 1680 JTextComponent target = getTextComponent(e); 1681 if (target != null) { 1682 Caret caret = target.getCaret(); 1683 DefaultCaret bidiCaret = (caret instanceof DefaultCaret) ? 1684 (DefaultCaret)caret : null; 1685 int dot = caret.getDot(); 1686 Position.Bias[] bias = new Position.Bias[1]; 1687 Point magicPosition = caret.getMagicCaretPosition(); 1688 1689 try { 1690 if(magicPosition == null && 1691 (direction == SwingConstants.NORTH || 1692 direction == SwingConstants.SOUTH)) { 1693 Rectangle r = (bidiCaret != null) ? 1694 target.getUI().modelToView(target, dot, 1695 bidiCaret.getDotBias()) : 1696 target.modelToView(dot); 1697 magicPosition = new Point(r.x, r.y); 1698 } 1699 1700 NavigationFilter filter = target.getNavigationFilter(); 1701 1702 if (filter != null) { 1703 dot = filter.getNextVisualPositionFrom 1704 (target, dot, (bidiCaret != null) ? 1705 bidiCaret.getDotBias() : 1706 Position.Bias.Forward, direction, bias); 1707 } 1708 else { 1709 dot = target.getUI().getNextVisualPositionFrom 1710 (target, dot, (bidiCaret != null) ? 1711 bidiCaret.getDotBias() : 1712 Position.Bias.Forward, direction, bias); 1713 } 1714 if(bias[0] == null) { 1715 bias[0] = Position.Bias.Forward; 1716 } 1717 if(bidiCaret != null) { 1718 if (select) { 1719 bidiCaret.moveDot(dot, bias[0]); 1720 } else { 1721 bidiCaret.setDot(dot, bias[0]); 1722 } 1723 } 1724 else { 1725 if (select) { 1726 caret.moveDot(dot); 1727 } else { 1728 caret.setDot(dot); 1729 } 1730 } 1731 if(magicPosition != null && 1732 (direction == SwingConstants.NORTH || 1733 direction == SwingConstants.SOUTH)) { 1734 target.getCaret().setMagicCaretPosition(magicPosition); 1735 } 1736 } catch (BadLocationException ex) { 1737 } 1738 } 1739 } 1740 1741 private boolean select; 1742 private int direction; 1743 } 1744 1745 /* 1746 * Position the caret to the beginning of the word. 1747 * @see DefaultEditorKit#beginWordAction 1748 * @see DefaultEditorKit#selectBeginWordAction 1749 * @see DefaultEditorKit#getActions 1750 */ 1751 @SuppressWarnings("serial") // Superclass is not serializable across versions 1752 static class BeginWordAction extends TextAction { 1753 1754 /** 1755 * Create this action with the appropriate identifier. 1756 * @param nm the name of the action, Action.NAME. 1757 * @param select whether to extend the selection when 1758 * changing the caret position. 1759 */ 1760 BeginWordAction(String nm, boolean select) { 1761 super(nm); 1762 this.select = select; 1763 } 1764 1765 /** The operation to perform when this action is triggered. */ 1766 public void actionPerformed(ActionEvent e) { 1767 JTextComponent target = getTextComponent(e); 1768 if (target != null) { 1769 try { 1770 int offs = target.getCaretPosition(); 1771 int begOffs = Utilities.getWordStart(target, offs); 1772 if (select) { 1773 target.moveCaretPosition(begOffs); 1774 } else { 1775 target.setCaretPosition(begOffs); 1776 } 1777 } catch (BadLocationException bl) { 1778 UIManager.getLookAndFeel().provideErrorFeedback(target); 1779 } 1780 } 1781 } 1782 1783 private boolean select; 1784 } 1785 1786 /* 1787 * Position the caret to the end of the word. 1788 * @see DefaultEditorKit#endWordAction 1789 * @see DefaultEditorKit#selectEndWordAction 1790 * @see DefaultEditorKit#getActions 1791 */ 1792 @SuppressWarnings("serial") // Superclass is not serializable across versions 1793 static class EndWordAction extends TextAction { 1794 1795 /** 1796 * Create this action with the appropriate identifier. 1797 * @param nm the name of the action, Action.NAME. 1798 * @param select whether to extend the selection when 1799 * changing the caret position. 1800 */ 1801 EndWordAction(String nm, boolean select) { 1802 super(nm); 1803 this.select = select; 1804 } 1805 1806 /** The operation to perform when this action is triggered. */ 1807 public void actionPerformed(ActionEvent e) { 1808 JTextComponent target = getTextComponent(e); 1809 if (target != null) { 1810 try { 1811 int offs = target.getCaretPosition(); 1812 int endOffs = Utilities.getWordEnd(target, offs); 1813 if (select) { 1814 target.moveCaretPosition(endOffs); 1815 } else { 1816 target.setCaretPosition(endOffs); 1817 } 1818 } catch (BadLocationException bl) { 1819 UIManager.getLookAndFeel().provideErrorFeedback(target); 1820 } 1821 } 1822 } 1823 1824 private boolean select; 1825 } 1826 1827 /* 1828 * Position the caret to the beginning of the previous word. 1829 * @see DefaultEditorKit#previousWordAction 1830 * @see DefaultEditorKit#selectPreviousWordAction 1831 * @see DefaultEditorKit#getActions 1832 */ 1833 @SuppressWarnings("serial") // Superclass is not serializable across versions 1834 static class PreviousWordAction extends TextAction { 1835 1836 /** 1837 * Create this action with the appropriate identifier. 1838 * @param nm the name of the action, Action.NAME. 1839 * @param select whether to extend the selection when 1840 * changing the caret position. 1841 */ 1842 PreviousWordAction(String nm, boolean select) { 1843 super(nm); 1844 this.select = select; 1845 } 1846 1847 /** The operation to perform when this action is triggered. */ 1848 public void actionPerformed(ActionEvent e) { 1849 JTextComponent target = getTextComponent(e); 1850 if (target != null) { 1851 int offs = target.getCaretPosition(); 1852 boolean failed = false; 1853 try { 1854 Element curPara = 1855 Utilities.getParagraphElement(target, offs); 1856 offs = Utilities.getPreviousWord(target, offs); 1857 if(offs < curPara.getStartOffset()) { 1858 // we should first move to the end of the 1859 // previous paragraph (bug #4278839) 1860 offs = Utilities.getParagraphElement(target, offs). 1861 getEndOffset() - 1; 1862 } 1863 } catch (BadLocationException bl) { 1864 if (offs != 0) { 1865 offs = 0; 1866 } 1867 else { 1868 failed = true; 1869 } 1870 } 1871 if (!failed) { 1872 if (select) { 1873 target.moveCaretPosition(offs); 1874 } else { 1875 target.setCaretPosition(offs); 1876 } 1877 } 1878 else { 1879 UIManager.getLookAndFeel().provideErrorFeedback(target); 1880 } 1881 } 1882 } 1883 1884 private boolean select; 1885 } 1886 1887 /* 1888 * Position the caret to the next of the word. 1889 * @see DefaultEditorKit#nextWordAction 1890 * @see DefaultEditorKit#selectNextWordAction 1891 * @see DefaultEditorKit#getActions 1892 */ 1893 @SuppressWarnings("serial") // Superclass is not serializable across versions 1894 static class NextWordAction extends TextAction { 1895 1896 /** 1897 * Create this action with the appropriate identifier. 1898 * @param nm the name of the action, Action.NAME. 1899 * @param select whether to extend the selection when 1900 * changing the caret position. 1901 */ 1902 NextWordAction(String nm, boolean select) { 1903 super(nm); 1904 this.select = select; 1905 } 1906 1907 /** The operation to perform when this action is triggered. */ 1908 public void actionPerformed(ActionEvent e) { 1909 JTextComponent target = getTextComponent(e); 1910 if (target != null) { 1911 int offs = target.getCaretPosition(); 1912 boolean failed = false; 1913 int oldOffs = offs; 1914 Element curPara = 1915 Utilities.getParagraphElement(target, offs); 1916 try { 1917 offs = Utilities.getNextWord(target, offs); 1918 if(offs >= curPara.getEndOffset() && 1919 oldOffs != curPara.getEndOffset() - 1) { 1920 // we should first move to the end of current 1921 // paragraph (bug #4278839) 1922 offs = curPara.getEndOffset() - 1; 1923 } 1924 } catch (BadLocationException bl) { 1925 int end = target.getDocument().getLength(); 1926 if (offs != end) { 1927 if(oldOffs != curPara.getEndOffset() - 1) { 1928 offs = curPara.getEndOffset() - 1; 1929 } else { 1930 offs = end; 1931 } 1932 } 1933 else { 1934 failed = true; 1935 } 1936 } 1937 if (!failed) { 1938 if (select) { 1939 target.moveCaretPosition(offs); 1940 } else { 1941 target.setCaretPosition(offs); 1942 } 1943 } 1944 else { 1945 UIManager.getLookAndFeel().provideErrorFeedback(target); 1946 } 1947 } 1948 } 1949 1950 private boolean select; 1951 } 1952 1953 /* 1954 * Position the caret to the beginning of the line. 1955 * @see DefaultEditorKit#beginLineAction 1956 * @see DefaultEditorKit#selectBeginLineAction 1957 * @see DefaultEditorKit#getActions 1958 */ 1959 @SuppressWarnings("serial") // Superclass is not serializable across versions 1960 static class BeginLineAction extends TextAction { 1961 1962 /** 1963 * Create this action with the appropriate identifier. 1964 * @param nm the name of the action, Action.NAME. 1965 * @param select whether to extend the selection when 1966 * changing the caret position. 1967 */ 1968 BeginLineAction(String nm, boolean select) { 1969 super(nm); 1970 this.select = select; 1971 } 1972 1973 /** The operation to perform when this action is triggered. */ 1974 public void actionPerformed(ActionEvent e) { 1975 JTextComponent target = getTextComponent(e); 1976 if (target != null) { 1977 try { 1978 int offs = target.getCaretPosition(); 1979 int begOffs = Utilities.getRowStart(target, offs); 1980 if (select) { 1981 target.moveCaretPosition(begOffs); 1982 } else { 1983 target.setCaretPosition(begOffs); 1984 } 1985 } catch (BadLocationException bl) { 1986 UIManager.getLookAndFeel().provideErrorFeedback(target); 1987 } 1988 } 1989 } 1990 1991 private boolean select; 1992 } 1993 1994 /* 1995 * Position the caret to the end of the line. 1996 * @see DefaultEditorKit#endLineAction 1997 * @see DefaultEditorKit#selectEndLineAction 1998 * @see DefaultEditorKit#getActions 1999 */ 2000 @SuppressWarnings("serial") // Superclass is not serializable across versions 2001 static class EndLineAction extends TextAction { 2002 2003 /** 2004 * Create this action with the appropriate identifier. 2005 * @param nm the name of the action, Action.NAME. 2006 * @param select whether to extend the selection when 2007 * changing the caret position. 2008 */ 2009 EndLineAction(String nm, boolean select) { 2010 super(nm); 2011 this.select = select; 2012 } 2013 2014 /** The operation to perform when this action is triggered. */ 2015 public void actionPerformed(ActionEvent e) { 2016 JTextComponent target = getTextComponent(e); 2017 if (target != null) { 2018 try { 2019 int offs = target.getCaretPosition(); 2020 int endOffs = Utilities.getRowEnd(target, offs); 2021 if (select) { 2022 target.moveCaretPosition(endOffs); 2023 } else { 2024 target.setCaretPosition(endOffs); 2025 } 2026 } catch (BadLocationException bl) { 2027 UIManager.getLookAndFeel().provideErrorFeedback(target); 2028 } 2029 } 2030 } 2031 2032 private boolean select; 2033 } 2034 2035 /* 2036 * Position the caret to the beginning of the paragraph. 2037 * @see DefaultEditorKit#beginParagraphAction 2038 * @see DefaultEditorKit#selectBeginParagraphAction 2039 * @see DefaultEditorKit#getActions 2040 */ 2041 @SuppressWarnings("serial") // Superclass is not serializable across versions 2042 static class BeginParagraphAction extends TextAction { 2043 2044 /** 2045 * Create this action with the appropriate identifier. 2046 * @param nm the name of the action, Action.NAME. 2047 * @param select whether to extend the selection when 2048 * changing the caret position. 2049 */ 2050 BeginParagraphAction(String nm, boolean select) { 2051 super(nm); 2052 this.select = select; 2053 } 2054 2055 /** The operation to perform when this action is triggered. */ 2056 public void actionPerformed(ActionEvent e) { 2057 JTextComponent target = getTextComponent(e); 2058 if (target != null) { 2059 int offs = target.getCaretPosition(); 2060 Element elem = Utilities.getParagraphElement(target, offs); 2061 offs = elem.getStartOffset(); 2062 if (select) { 2063 target.moveCaretPosition(offs); 2064 } else { 2065 target.setCaretPosition(offs); 2066 } 2067 } 2068 } 2069 2070 private boolean select; 2071 } 2072 2073 /* 2074 * Position the caret to the end of the paragraph. 2075 * @see DefaultEditorKit#endParagraphAction 2076 * @see DefaultEditorKit#selectEndParagraphAction 2077 * @see DefaultEditorKit#getActions 2078 */ 2079 @SuppressWarnings("serial") // Superclass is not serializable across versions 2080 static class EndParagraphAction extends TextAction { 2081 2082 /** 2083 * Create this action with the appropriate identifier. 2084 * @param nm the name of the action, Action.NAME. 2085 * @param select whether to extend the selection when 2086 * changing the caret position. 2087 */ 2088 EndParagraphAction(String nm, boolean select) { 2089 super(nm); 2090 this.select = select; 2091 } 2092 2093 /** The operation to perform when this action is triggered. */ 2094 public void actionPerformed(ActionEvent e) { 2095 JTextComponent target = getTextComponent(e); 2096 if (target != null) { 2097 int offs = target.getCaretPosition(); 2098 Element elem = Utilities.getParagraphElement(target, offs); 2099 offs = Math.min(target.getDocument().getLength(), 2100 elem.getEndOffset()); 2101 if (select) { 2102 target.moveCaretPosition(offs); 2103 } else { 2104 target.setCaretPosition(offs); 2105 } 2106 } 2107 } 2108 2109 private boolean select; 2110 } 2111 2112 /* 2113 * Move the caret to the beginning of the document. 2114 * @see DefaultEditorKit#beginAction 2115 * @see DefaultEditorKit#getActions 2116 */ 2117 @SuppressWarnings("serial") // Superclass is not serializable across versions 2118 static class BeginAction extends TextAction { 2119 2120 /* Create this object with the appropriate identifier. */ 2121 BeginAction(String nm, boolean select) { 2122 super(nm); 2123 this.select = select; 2124 } 2125 2126 /** The operation to perform when this action is triggered. */ 2127 public void actionPerformed(ActionEvent e) { 2128 JTextComponent target = getTextComponent(e); 2129 if (target != null) { 2130 if (select) { 2131 target.moveCaretPosition(0); 2132 } else { 2133 target.setCaretPosition(0); 2134 } 2135 } 2136 } 2137 2138 private boolean select; 2139 } 2140 2141 /* 2142 * Move the caret to the end of the document. 2143 * @see DefaultEditorKit#endAction 2144 * @see DefaultEditorKit#getActions 2145 */ 2146 @SuppressWarnings("serial") // Superclass is not serializable across versions 2147 static class EndAction extends TextAction { 2148 2149 /* Create this object with the appropriate identifier. */ 2150 EndAction(String nm, boolean select) { 2151 super(nm); 2152 this.select = select; 2153 } 2154 2155 /** The operation to perform when this action is triggered. */ 2156 public void actionPerformed(ActionEvent e) { 2157 JTextComponent target = getTextComponent(e); 2158 if (target != null) { 2159 Document doc = target.getDocument(); 2160 int dot = doc.getLength(); 2161 if (select) { 2162 target.moveCaretPosition(dot); 2163 } else { 2164 target.setCaretPosition(dot); 2165 } 2166 } 2167 } 2168 2169 private boolean select; 2170 } 2171 2172 /* 2173 * Select the word around the caret 2174 * @see DefaultEditorKit#endAction 2175 * @see DefaultEditorKit#getActions 2176 */ 2177 @SuppressWarnings("serial") // Superclass is not serializable across versions 2178 static class SelectWordAction extends TextAction { 2179 2180 /** 2181 * Create this action with the appropriate identifier. 2182 */ 2183 SelectWordAction() { 2184 super(selectWordAction); 2185 start = new BeginWordAction("pigdog", false); 2186 end = new EndWordAction("pigdog", true); 2187 } 2188 2189 /** The operation to perform when this action is triggered. */ 2190 public void actionPerformed(ActionEvent e) { 2191 start.actionPerformed(e); 2192 end.actionPerformed(e); 2193 } 2194 2195 private Action start; 2196 private Action end; 2197 } 2198 2199 /* 2200 * Select the line around the caret 2201 * @see DefaultEditorKit#endAction 2202 * @see DefaultEditorKit#getActions 2203 */ 2204 @SuppressWarnings("serial") // Superclass is not serializable across versions 2205 static class SelectLineAction extends TextAction { 2206 2207 /** 2208 * Create this action with the appropriate identifier. 2209 */ 2210 SelectLineAction() { 2211 super(selectLineAction); 2212 start = new BeginLineAction("pigdog", false); 2213 end = new EndLineAction("pigdog", true); 2214 } 2215 2216 /** The operation to perform when this action is triggered. */ 2217 public void actionPerformed(ActionEvent e) { 2218 start.actionPerformed(e); 2219 end.actionPerformed(e); 2220 } 2221 2222 private Action start; 2223 private Action end; 2224 } 2225 2226 /* 2227 * Select the paragraph around the caret 2228 * @see DefaultEditorKit#endAction 2229 * @see DefaultEditorKit#getActions 2230 */ 2231 @SuppressWarnings("serial") // Superclass is not serializable across versions 2232 static class SelectParagraphAction extends TextAction { 2233 2234 /** 2235 * Create this action with the appropriate identifier. 2236 */ 2237 SelectParagraphAction() { 2238 super(selectParagraphAction); 2239 start = new BeginParagraphAction("pigdog", false); 2240 end = new EndParagraphAction("pigdog", true); 2241 } 2242 2243 /** The operation to perform when this action is triggered. */ 2244 public void actionPerformed(ActionEvent e) { 2245 start.actionPerformed(e); 2246 end.actionPerformed(e); 2247 } 2248 2249 private Action start; 2250 private Action end; 2251 } 2252 2253 /* 2254 * Select the entire document 2255 * @see DefaultEditorKit#endAction 2256 * @see DefaultEditorKit#getActions 2257 */ 2258 @SuppressWarnings("serial") // Superclass is not serializable across versions 2259 static class SelectAllAction extends TextAction { 2260 2261 /** 2262 * Create this action with the appropriate identifier. 2263 */ 2264 SelectAllAction() { 2265 super(selectAllAction); 2266 } 2267 2268 /** The operation to perform when this action is triggered. */ 2269 public void actionPerformed(ActionEvent e) { 2270 JTextComponent target = getTextComponent(e); 2271 if (target != null) { 2272 Document doc = target.getDocument(); 2273 target.setCaretPosition(0); 2274 target.moveCaretPosition(doc.getLength()); 2275 } 2276 } 2277 2278 } 2279 2280 /* 2281 * Remove the selection, if any. 2282 * @see DefaultEditorKit#unselectAction 2283 * @see DefaultEditorKit#getActions 2284 */ 2285 @SuppressWarnings("serial") // Superclass is not serializable across versions 2286 static class UnselectAction extends TextAction { 2287 2288 /** 2289 * Create this action with the appropriate identifier. 2290 */ 2291 UnselectAction() { 2292 super(unselectAction); 2293 } 2294 2295 /** The operation to perform when this action is triggered. */ 2296 public void actionPerformed(ActionEvent e) { 2297 JTextComponent target = getTextComponent(e); 2298 if (target != null) { 2299 target.setCaretPosition(target.getCaretPosition()); 2300 } 2301 } 2302 2303 } 2304 2305 /* 2306 * Toggles the ComponentOrientation of the text component. 2307 * @see DefaultEditorKit#toggleComponentOrientationAction 2308 * @see DefaultEditorKit#getActions 2309 */ 2310 @SuppressWarnings("serial") // Superclass is not serializable across versions 2311 static class ToggleComponentOrientationAction extends TextAction { 2312 2313 /** 2314 * Create this action with the appropriate identifier. 2315 */ 2316 ToggleComponentOrientationAction() { 2317 super(toggleComponentOrientationAction); 2318 } 2319 2320 /** The operation to perform when this action is triggered. */ 2321 public void actionPerformed(ActionEvent e) { 2322 JTextComponent target = getTextComponent(e); 2323 if (target != null) { 2324 ComponentOrientation last = target.getComponentOrientation(); 2325 ComponentOrientation next; 2326 if( last == ComponentOrientation.RIGHT_TO_LEFT ) 2327 next = ComponentOrientation.LEFT_TO_RIGHT; 2328 else 2329 next = ComponentOrientation.RIGHT_TO_LEFT; 2330 target.setComponentOrientation(next); 2331 target.repaint(); 2332 } 2333 } 2334 } 2335 2336 }