History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/text/DefaultEditorKit.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/text/DefaultEditorKit.java+2303−0
@@ -0,0 +1,2303 @@
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 */
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 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}