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