Merge from mainline
[official-gcc.git] / libjava / classpath / javax / swing / text / DefaultEditorKit.java
blob88094b898f7c01f6c1bd973ca6802832042fc60f
1 /* DefaultEditorKit.java --
2 Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing.text;
41 import java.awt.Point;
42 import java.awt.Toolkit;
43 import java.awt.event.ActionEvent;
45 import java.io.BufferedReader;
46 import java.io.IOException;
47 import java.io.InputStream;
48 import java.io.InputStreamReader;
49 import java.io.OutputStream;
50 import java.io.OutputStreamWriter;
51 import java.io.Reader;
52 import java.io.Writer;
54 import javax.swing.Action;
56 /**
57 * The default implementation of {@link EditorKit}. This <code>EditorKit</code>
58 * a plain text <code>Document</code> and several commands that together
59 * make up a basic editor, like cut / copy + paste.
61 * @author original author unknown
62 * @author Roman Kennke (roman@kennke.org)
64 public class DefaultEditorKit extends EditorKit
66 /**
67 * Creates a beep on the PC speaker.
69 * @see Toolkit#beep()
71 public static class BeepAction extends TextAction
73 /**
74 * Creates a new <code>BeepAction</code>.
76 public BeepAction()
78 super(beepAction);
81 /**
82 * Performs the <code>Action</code>.
84 * @param event the action event describing the user action
86 public void actionPerformed(ActionEvent event)
88 Toolkit.getDefaultToolkit().beep();
92 /**
93 * Copies the selected content into the system clipboard.
95 * @see Toolkit#getSystemClipboard()
96 * @see CutAction
97 * @see PasteAction
99 public static class CopyAction extends TextAction
103 * Create a new <code>CopyAction</code>.
105 public CopyAction()
107 super(copyAction);
111 * Performs the <code>Action</code>.
113 * @param event the action event describing the user action
115 public void actionPerformed(ActionEvent event)
117 getTextComponent(event).copy();
123 * Copies the selected content into the system clipboard and deletes the
124 * selection.
126 * @see Toolkit#getSystemClipboard()
127 * @see CopyAction
128 * @see PasteAction
130 public static class CutAction extends TextAction
134 * Create a new <code>CutAction</code>.
136 public CutAction()
138 super(cutAction);
142 * Performs the <code>Action</code>.
144 * @param event the action event describing the user action
146 public void actionPerformed(ActionEvent event)
148 getTextComponent(event).cut();
153 * Copies content from the system clipboard into the editor.
155 * @see Toolkit#getSystemClipboard()
156 * @see CopyAction
157 * @see CutAction
159 public static class PasteAction extends TextAction
163 * Create a new <code>PasteAction</code>.
165 public PasteAction()
167 super(pasteAction);
171 * Performs the <code>Action</code>.
173 * @param event the action event describing the user action
175 public void actionPerformed(ActionEvent event)
177 getTextComponent(event).paste();
182 * This action is executed as default action when a KEY_TYPED
183 * event is received and no keymap entry exists for that. The purpose
184 * of this action is to filter out a couple of characters. This includes
185 * the control characters and characters with the ALT-modifier.
187 * If an event does not get filtered, it is inserted into the document
188 * of the text component. If there is some text selected in the text
189 * component, this text will be replaced.
191 public static class DefaultKeyTypedAction
192 extends TextAction
196 * Creates a new <code>DefaultKeyTypedAction</code>.
198 public DefaultKeyTypedAction()
200 super(defaultKeyTypedAction);
204 * Performs the <code>Action</code>.
206 * @param event the action event describing the user action
208 public void actionPerformed(ActionEvent event)
210 // first we filter the following events:
211 // - control characters
212 // - key events with the ALT modifier (FIXME: filter that too!)
213 char c = event.getActionCommand().charAt(0);
214 if (Character.isISOControl(c))
215 return;
217 JTextComponent t = getTextComponent(event);
218 if (t != null && t.isEnabled() && t.isEditable())
219 t.replaceSelection(event.getActionCommand());
224 * This action inserts a newline character into the document
225 * of the text component. This is typically triggered by hitting
226 * ENTER on the keyboard.
228 public static class InsertBreakAction extends TextAction
232 * Creates a new <code>InsertBreakAction</code>.
234 public InsertBreakAction()
236 super(insertBreakAction);
240 * Performs the <code>Action</code>.
242 * @param event the action event describing the user action
244 public void actionPerformed(ActionEvent event)
246 JTextComponent t = getTextComponent(event);
247 t.replaceSelection("\n");
252 * Places content into the associated editor. If there currently is a
253 * selection, this selection is replaced.
255 // FIXME: Figure out what this Action is supposed to do. Obviously text
256 // that is entered by the user is inserted through DefaultKeyTypedAction.
257 public static class InsertContentAction extends TextAction
261 * Creates a new <code>InsertContentAction</code>.
263 public InsertContentAction()
265 super(insertContentAction);
269 * Performs the <code>Action</code>.
271 * @param event the action event describing the user action
273 public void actionPerformed(ActionEvent event)
275 // FIXME: Figure out what this Action is supposed to do. Obviously text
276 // that is entered by the user is inserted through DefaultKeyTypedAction.
281 * Inserts a TAB character into the text editor.
283 public static class InsertTabAction extends TextAction
287 * Creates a new <code>TabAction</code>.
289 public InsertTabAction()
291 super(insertTabAction);
295 * Performs the <code>Action</code>.
297 * @param event the action event describing the user action
299 public void actionPerformed(ActionEvent event)
301 JTextComponent t = getTextComponent(event);
302 t.replaceSelection("\t");
307 * The serial version of DefaultEditorKit.
309 private static final long serialVersionUID = 9017245433028523428L;
312 * The name of the <code>Action</code> that moves the caret one character
313 * backwards.
315 * @see #getActions()
317 public static final String backwardAction = "caret-backward";
320 * The name of the <code>Action</code> that creates a beep in the speaker.
322 * @see #getActions()
324 public static final String beepAction = "beep";
327 * The name of the <code>Action</code> that moves the caret to the beginning
328 * of the <code>Document</code>.
330 * @see #getActions()
332 public static final String beginAction = "caret-begin";
335 * The name of the <code>Action</code> that moves the caret to the beginning
336 * of the current line.
338 * @see #getActions()
340 public static final String beginLineAction = "caret-begin-line";
343 * The name of the <code>Action</code> that moves the caret to the beginning
344 * of the current paragraph.
346 * @see #getActions()
348 public static final String beginParagraphAction = "caret-begin-paragraph";
351 * The name of the <code>Action</code> that moves the caret to the beginning
352 * of the current word.
354 * @see #getActions()
356 public static final String beginWordAction = "caret-begin-word";
359 * The name of the <code>Action</code> that copies the selected content
360 * into the system clipboard.
362 * @see #getActions()
364 public static final String copyAction = "copy-to-clipboard";
367 * The name of the <code>Action</code> that copies the selected content
368 * into the system clipboard and removes the selection.
370 * @see #getActions()
372 public static final String cutAction = "cut-to-clipboard";
375 * The name of the <code>Action</code> that is performed by default if
376 * a key is typed and there is no keymap entry.
378 * @see #getActions()
380 public static final String defaultKeyTypedAction = "default-typed";
383 * The name of the <code>Action</code> that deletes the character that
384 * follows the current caret position.
386 * @see #getActions()
388 public static final String deleteNextCharAction = "delete-next";
391 * The name of the <code>Action</code> that deletes the character that
392 * precedes the current caret position.
394 * @see #getActions()
396 public static final String deletePrevCharAction = "delete-previous";
399 * The name of the <code>Action</code> that moves the caret one line down.
401 * @see #getActions()
403 public static final String downAction = "caret-down";
406 * The name of the <code>Action</code> that moves the caret to the end
407 * of the <code>Document</code>.
409 * @see #getActions()
411 public static final String endAction = "caret-end";
414 * The name of the <code>Action</code> that moves the caret to the end
415 * of the current line.
417 * @see #getActions()
419 public static final String endLineAction = "caret-end-line";
422 * When a document is read and an CRLF is encountered, then we add a property
423 * with this name and a value of &quot;\r\n&quot;.
425 public static final String EndOfLineStringProperty = "__EndOfLine__";
428 * The name of the <code>Action</code> that moves the caret to the end
429 * of the current paragraph.
431 * @see #getActions()
433 public static final String endParagraphAction = "caret-end-paragraph";
436 * The name of the <code>Action</code> that moves the caret to the end
437 * of the current word.
439 * @see #getActions()
441 public static final String endWordAction = "caret-end-word";
444 * The name of the <code>Action</code> that moves the caret one character
445 * forward.
447 * @see #getActions()
449 public static final String forwardAction = "caret-forward";
452 * The name of the <code>Action</code> that inserts a line break.
454 * @see #getActions()
456 public static final String insertBreakAction = "insert-break";
459 * The name of the <code>Action</code> that inserts some content.
461 * @see #getActions()
463 public static final String insertContentAction = "insert-content";
466 * The name of the <code>Action</code> that inserts a TAB.
468 * @see #getActions()
470 public static final String insertTabAction = "insert-tab";
473 * The name of the <code>Action</code> that moves the caret to the beginning
474 * of the next word.
476 * @see #getActions()
478 public static final String nextWordAction = "caret-next-word";
481 * The name of the <code>Action</code> that moves the caret one page down.
483 * @see #getActions()
485 public static final String pageDownAction = "page-down";
488 * The name of the <code>Action</code> that moves the caret one page up.
490 * @see #getActions()
492 public static final String pageUpAction = "page-up";
495 * The name of the <code>Action</code> that copies content from the system
496 * clipboard into the document.
498 * @see #getActions()
500 public static final String pasteAction = "paste-from-clipboard";
503 * The name of the <code>Action</code> that moves the caret to the beginning
504 * of the previous word.
506 * @see #getActions()
508 public static final String previousWordAction = "caret-previous-word";
511 * The name of the <code>Action</code> that sets the editor in read only
512 * mode.
514 * @see #getActions()
516 public static final String readOnlyAction = "set-read-only";
519 * The name of the <code>Action</code> that selects the whole document.
521 * @see #getActions()
523 public static final String selectAllAction = "select-all";
526 * The name of the <code>Action</code> that moves the caret one character
527 * backwards, possibly extending the current selection.
529 * @see #getActions()
531 public static final String selectionBackwardAction = "selection-backward";
534 * The name of the <code>Action</code> that moves the caret to the beginning
535 * of the document, possibly extending the current selection.
537 * @see #getActions()
539 public static final String selectionBeginAction = "selection-begin";
542 * The name of the <code>Action</code> that moves the caret to the beginning
543 * of the current line, possibly extending the current selection.
545 * @see #getActions()
547 public static final String selectionBeginLineAction = "selection-begin-line";
550 * The name of the <code>Action</code> that moves the caret to the beginning
551 * of the current paragraph, possibly extending the current selection.
553 * @see #getActions()
555 public static final String selectionBeginParagraphAction =
556 "selection-begin-paragraph";
559 * The name of the <code>Action</code> that moves the caret to the beginning
560 * of the current word, possibly extending the current selection.
562 * @see #getActions()
564 public static final String selectionBeginWordAction = "selection-begin-word";
567 * The name of the <code>Action</code> that moves the caret one line down,
568 * possibly extending the current selection.
570 * @see #getActions()
572 public static final String selectionDownAction = "selection-down";
575 * The name of the <code>Action</code> that moves the caret to the end
576 * of the document, possibly extending the current selection.
578 * @see #getActions()
580 public static final String selectionEndAction = "selection-end";
583 * The name of the <code>Action</code> that moves the caret to the end
584 * of the current line, possibly extending the current selection.
586 * @see #getActions()
588 public static final String selectionEndLineAction = "selection-end-line";
591 * The name of the <code>Action</code> that moves the caret to the end
592 * of the current paragraph, possibly extending the current selection.
594 * @see #getActions()
596 public static final String selectionEndParagraphAction =
597 "selection-end-paragraph";
600 * The name of the <code>Action</code> that moves the caret to the end
601 * of the current word, possibly extending the current selection.
603 * @see #getActions()
605 public static final String selectionEndWordAction = "selection-end-word";
608 * The name of the <code>Action</code> that moves the caret one character
609 * forwards, possibly extending the current selection.
611 * @see #getActions()
613 public static final String selectionForwardAction = "selection-forward";
616 * The name of the <code>Action</code> that moves the caret to the beginning
617 * of the next word, possibly extending the current selection.
619 * @see #getActions()
621 public static final String selectionNextWordAction = "selection-next-word";
624 * The name of the <code>Action</code> that moves the caret to the beginning
625 * of the previous word, possibly extending the current selection.
627 * @see #getActions()
629 public static final String selectionPreviousWordAction =
630 "selection-previous-word";
633 * The name of the <code>Action</code> that moves the caret one line up,
634 * possibly extending the current selection.
636 * @see #getActions()
638 public static final String selectionUpAction = "selection-up";
641 * The name of the <code>Action</code> that selects the line around the
642 * caret.
644 * @see #getActions()
646 public static final String selectLineAction = "select-line";
649 * The name of the <code>Action</code> that selects the paragraph around the
650 * caret.
652 * @see #getActions()
654 public static final String selectParagraphAction = "select-paragraph";
657 * The name of the <code>Action</code> that selects the word around the
658 * caret.
660 * @see #getActions()
662 public static final String selectWordAction = "select-word";
665 * The name of the <code>Action</code> that moves the caret one line up.
667 * @see #getActions()
669 public static final String upAction = "caret-up";
672 * The name of the <code>Action</code> that sets the editor in read-write
673 * mode.
675 * @see #getActions()
677 public static final String writableAction = "set-writable";
680 * Creates a new <code>DefaultEditorKit</code>.
682 public DefaultEditorKit()
684 // Nothing to do here.
688 * The <code>Action</code>s that are supported by the
689 * <code>DefaultEditorKit</code>.
691 // TODO: All these inner classes look ugly. Maybe work out a better way
692 // to handle this.
693 private static Action[] defaultActions =
694 new Action[] {
695 new BeepAction(),
696 new CopyAction(),
697 new CutAction(),
698 new DefaultKeyTypedAction(),
699 new InsertBreakAction(),
700 new InsertContentAction(),
701 new InsertTabAction(),
702 new PasteAction(),
703 new TextAction(beginLineAction)
705 public void actionPerformed(ActionEvent event)
707 JTextComponent t = getTextComponent(event);
710 // TODO: There is a more efficent solution, but
711 // viewToModel doesn't work properly.
712 Point p = t.modelToView(t.getCaret().getDot()).getLocation();
713 int cur = t.getCaretPosition();
714 int y = p.y;
715 while (y == p.y && cur > 0)
716 y = t.modelToView(--cur).getLocation().y;
717 if (cur != 0)
718 cur++;
719 t.setCaretPosition(cur);
721 catch (BadLocationException ble)
723 // Do nothing here.
727 new TextAction(endLineAction)
729 public void actionPerformed(ActionEvent event)
731 JTextComponent t = getTextComponent(event);
734 Point p = t.modelToView(t.getCaret().getDot()).getLocation();
735 int cur = t.getCaretPosition();
736 int y = p.y;
737 int length = t.getDocument().getLength();
738 while (y == p.y && cur < length)
739 y = t.modelToView(++cur).getLocation().y;
740 if (cur != length)
741 cur--;
742 t.setCaretPosition(cur);
744 catch (BadLocationException ble)
746 // Nothing to do here
750 new TextAction(deleteNextCharAction)
752 public void actionPerformed(ActionEvent event)
754 JTextComponent t = getTextComponent(event);
755 if (t != null)
759 int pos = t.getCaret().getDot();
760 if (pos < t.getDocument().getEndPosition().getOffset())
762 t.getDocument().remove(t.getCaret().getDot(), 1);
765 catch (BadLocationException e)
767 // FIXME: we're not authorized to throw this.. swallow it?
772 new TextAction(deletePrevCharAction)
774 public void actionPerformed(ActionEvent event)
776 JTextComponent t = getTextComponent(event);
777 if (t != null)
781 int pos = t.getCaret().getDot();
782 if (pos > t.getDocument().getStartPosition().getOffset())
784 t.getDocument().remove(pos - 1, 1);
785 t.getCaret().setDot(pos - 1);
788 catch (BadLocationException e)
790 // FIXME: we're not authorized to throw this.. swallow it?
795 new TextAction(backwardAction)
797 public void actionPerformed(ActionEvent event)
799 JTextComponent t = getTextComponent(event);
800 if (t != null)
802 t.getCaret().setDot(Math.max(t.getCaret().getDot() - 1,
803 t.getDocument().getStartPosition().getOffset()));
807 new TextAction(forwardAction)
809 public void actionPerformed(ActionEvent event)
811 JTextComponent t = getTextComponent(event);
812 if (t != null)
814 t.getCaret().setDot(Math.min(t.getCaret().getDot() + 1,
815 t.getDocument().getEndPosition().getOffset()));
819 new TextAction(selectionBackwardAction)
821 public void actionPerformed(ActionEvent event)
823 JTextComponent t = getTextComponent(event);
824 if (t != null)
826 t.getCaret().moveDot(Math.max(t.getCaret().getDot() - 1,
827 t.getDocument().getStartPosition().getOffset()));
831 new TextAction(selectionForwardAction)
833 public void actionPerformed(ActionEvent event)
835 JTextComponent t = getTextComponent(event);
836 if (t != null)
838 t.getCaret().moveDot(Math.min(t.getCaret().getDot() + 1,
839 t.getDocument().getEndPosition().getOffset()));
846 * Creates the <code>Caret</code> for this <code>EditorKit</code>. This
847 * returns a {@link DefaultCaret} in this case.
849 * @return the <code>Caret</code> for this <code>EditorKit</code>
851 public Caret createCaret()
853 return new DefaultCaret();
857 * Creates the default {@link Document} that this <code>EditorKit</code>
858 * supports. This is a {@link PlainDocument} in this case.
860 * @return the default {@link Document} that this <code>EditorKit</code>
861 * supports
863 public Document createDefaultDocument()
865 return new PlainDocument();
869 * Returns the <code>Action</code>s supported by this <code>EditorKit</code>.
871 * @return the <code>Action</code>s supported by this <code>EditorKit</code>
873 public Action[] getActions()
875 return defaultActions;
879 * Returns the content type that this <code>EditorKit</code> supports.
880 * The <code>DefaultEditorKit</code> supports the content type
881 * <code>text/plain</code>.
883 * @return the content type that this <code>EditorKit</code> supports
885 public String getContentType()
887 return "text/plain";
891 * Returns a {@link ViewFactory} that is able to create {@link View}s for
892 * the <code>Element</code>s that are used in this <code>EditorKit</code>'s
893 * model. This returns null which lets the UI of the text component supply
894 * <code>View</code>s.
896 * @return a {@link ViewFactory} that is able to create {@link View}s for
897 * the <code>Element</code>s that are used in this
898 * <code>EditorKit</code>'s model
900 public ViewFactory getViewFactory()
902 return null;
906 * Reads a document of the supported content type from an {@link InputStream}
907 * into the actual {@link Document} object.
909 * @param in the stream from which to read the document
910 * @param document the document model into which the content is read
911 * @param offset the offset inside to document where the content is inserted
913 * @throws BadLocationException if <code>offset</code> is an invalid location
914 * inside <code>document</code>
915 * @throws IOException if something goes wrong while reading from
916 * <code>in</code>
918 public void read(InputStream in, Document document, int offset)
919 throws BadLocationException, IOException
921 read(new InputStreamReader(in), document, offset);
925 * Reads a document of the supported content type from a {@link Reader}
926 * into the actual {@link Document} object.
928 * @param in the reader from which to read the document
929 * @param document the document model into which the content is read
930 * @param offset the offset inside to document where the content is inserted
932 * @throws BadLocationException if <code>offset</code> is an invalid location
933 * inside <code>document</code>
934 * @throws IOException if something goes wrong while reading from
935 * <code>in</code>
937 public void read(Reader in, Document document, int offset)
938 throws BadLocationException, IOException
940 BufferedReader reader = new BufferedReader(in);
942 String line;
943 StringBuffer content = new StringBuffer();
945 while ((line = reader.readLine()) != null)
947 content.append(line);
948 content.append("\n");
951 document.insertString(offset, content.substring(0, content.length() - 1),
952 SimpleAttributeSet.EMPTY);
956 * Writes the <code>Document</code> (or a fragment of the
957 * <code>Document</code>) to an {@link OutputStream} in the
958 * supported content type format.
960 * @param out the stream to write to
961 * @param document the document that should be written out
962 * @param offset the beginning offset from where to write
963 * @param len the length of the fragment to write
965 * @throws BadLocationException if <code>offset</code> or
966 * <code>offset + len</code>is an invalid location inside
967 * <code>document</code>
968 * @throws IOException if something goes wrong while writing to
969 * <code>out</code>
971 public void write(OutputStream out, Document document, int offset, int len)
972 throws BadLocationException, IOException
974 write(new OutputStreamWriter(out), document, offset, len);
978 * Writes the <code>Document</code> (or a fragment of the
979 * <code>Document</code>) to a {@link Writer} in the
980 * supported content type format.
982 * @param out the writer to write to
983 * @param document the document that should be written out
984 * @param offset the beginning offset from where to write
985 * @param len the length of the fragment to write
987 * @throws BadLocationException if <code>offset</code> is an
988 * invalid location inside <code>document</code>.
989 * @throws IOException if something goes wrong while writing to
990 * <code>out</code>
992 public void write(Writer out, Document document, int offset, int len)
993 throws BadLocationException, IOException
995 // Throw a BLE if offset is invalid
996 if (offset < 0 || offset > document.getLength())
997 throw new BadLocationException("Tried to write to invalid location",
998 offset);
1000 // If they gave an overly large len, just adjust it
1001 if (offset + len > document.getLength())
1002 len = document.getLength() - offset;
1004 out.write(document.getText(offset, len));