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