diff -r fd16c54261b3 -r 90ce3da70b43 jdk/src/share/classes/javax/swing/text/DefaultEditorKit.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/javax/swing/text/DefaultEditorKit.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,2306 @@ +/* + * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package javax.swing.text; + +import java.io.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.text.*; +import javax.swing.Action; +import javax.swing.KeyStroke; +import javax.swing.SwingConstants; +import javax.swing.UIManager; + +/** + * This is the set of things needed by a text component + * to be a reasonably functioning editor for some type + * of text document. This implementation provides a default + * implementation which treats text as plain text and + * provides a minimal set of actions for a simple editor. + *

+ *

+ *
Newlines + *
+ * There are two properties which deal with newlines. The + * system property, line.separator, is defined to be + * platform-dependent, either "\n", "\r", or "\r\n". There is also + * a property defined in DefaultEditorKit, called + * EndOfLineStringProperty, + * which is defined automatically when a document is loaded, to be + * the first occurrence of any of the newline characters. + * When a document is loaded, EndOfLineStringProperty + * is set appropriately, and when the document is written back out, the + * EndOfLineStringProperty is used. But while the document + * is in memory, the "\n" character is used to define a + * newline, regardless of how the newline is defined when + * the document is on disk. Therefore, for searching purposes, + * "\n" should always be used. When a new document is created, + * and the EndOfLineStringProperty has not been defined, + * it will use the System property when writing out the + * document. + *

Note that EndOfLineStringProperty is set + * on the Document using the get/putProperty + * methods. Subclasses may override this behavior. + * + *

+ * + * @author Timothy Prinzing + */ +public class DefaultEditorKit extends EditorKit { + + /** + * default constructor for DefaultEditorKit + */ + public DefaultEditorKit() { + } + + /** + * Gets the MIME type of the data that this + * kit represents support for. The default + * is text/plain. + * + * @return the type + */ + public String getContentType() { + return "text/plain"; + } + + /** + * Fetches a factory that is suitable for producing + * views of any models that are produced by this + * kit. The default is to have the UI produce the + * factory, so this method has no implementation. + * + * @return the view factory + */ + public ViewFactory getViewFactory() { + return null; + } + + /** + * Fetches the set of commands that can be used + * on a text component that is using a model and + * view produced by this kit. + * + * @return the command list + */ + public Action[] getActions() { + return defaultActions; + } + + /** + * Fetches a caret that can navigate through views + * produced by the associated ViewFactory. + * + * @return the caret + */ + public Caret createCaret() { + return null; + } + + /** + * Creates an uninitialized text storage model (PlainDocument) + * that is appropriate for this type of editor. + * + * @return the model + */ + public Document createDefaultDocument() { + return new PlainDocument(); + } + + /** + * Inserts content from the given stream which is expected + * to be in a format appropriate for this kind of content + * handler. + * + * @param in The stream to read from + * @param doc The destination for the insertion. + * @param pos The location in the document to place the + * content >= 0. + * @exception IOException on any I/O error + * @exception BadLocationException if pos represents an invalid + * location within the document. + */ + public void read(InputStream in, Document doc, int pos) + throws IOException, BadLocationException { + + read(new InputStreamReader(in), doc, pos); + } + + /** + * Writes content from a document to the given stream + * in a format appropriate for this kind of content handler. + * + * @param out The stream to write to + * @param doc The source for the write. + * @param pos The location in the document to fetch the + * content >= 0. + * @param len The amount to write out >= 0. + * @exception IOException on any I/O error + * @exception BadLocationException if pos represents an invalid + * location within the document. + */ + public void write(OutputStream out, Document doc, int pos, int len) + throws IOException, BadLocationException { + OutputStreamWriter osw = new OutputStreamWriter(out); + + write(osw, doc, pos, len); + osw.flush(); + } + + /** + * Gets the input attributes for the pane. This method exists for + * the benefit of StyledEditorKit so that the read method will + * pick up the correct attributes to apply to inserted text. + * This class's implementation simply returns null. + * + * @return null + */ + MutableAttributeSet getInputAttributes() { + return null; + } + + /** + * Inserts content from the given stream, which will be + * treated as plain text. + * + * @param in The stream to read from + * @param doc The destination for the insertion. + * @param pos The location in the document to place the + * content >= 0. + * @exception IOException on any I/O error + * @exception BadLocationException if pos represents an invalid + * location within the document. + */ + public void read(Reader in, Document doc, int pos) + throws IOException, BadLocationException { + + char[] buff = new char[4096]; + int nch; + boolean lastWasCR = false; + boolean isCRLF = false; + boolean isCR = false; + int last; + boolean wasEmpty = (doc.getLength() == 0); + AttributeSet attr = getInputAttributes(); + + // Read in a block at a time, mapping \r\n to \n, as well as single + // \r's to \n's. If a \r\n is encountered, \r\n will be set as the + // newline string for the document, if \r is encountered it will + // be set as the newline character, otherwise the newline property + // for the document will be removed. + while ((nch = in.read(buff, 0, buff.length)) != -1) { + last = 0; + for(int counter = 0; counter < nch; counter++) { + switch(buff[counter]) { + case '\r': + if (lastWasCR) { + isCR = true; + if (counter == 0) { + doc.insertString(pos, "\n", attr); + pos++; + } + else { + buff[counter - 1] = '\n'; + } + } + else { + lastWasCR = true; + } + break; + case '\n': + if (lastWasCR) { + if (counter > (last + 1)) { + doc.insertString(pos, new String(buff, last, + counter - last - 1), attr); + pos += (counter - last - 1); + } + // else nothing to do, can skip \r, next write will + // write \n + lastWasCR = false; + last = counter; + isCRLF = true; + } + break; + default: + if (lastWasCR) { + isCR = true; + if (counter == 0) { + doc.insertString(pos, "\n", attr); + pos++; + } + else { + buff[counter - 1] = '\n'; + } + lastWasCR = false; + } + break; + } + } + if (last < nch) { + if(lastWasCR) { + if (last < (nch - 1)) { + doc.insertString(pos, new String(buff, last, + nch - last - 1), attr); + pos += (nch - last - 1); + } + } + else { + doc.insertString(pos, new String(buff, last, + nch - last), attr); + pos += (nch - last); + } + } + } + if (lastWasCR) { + doc.insertString(pos, "\n", attr); + isCR = true; + } + if (wasEmpty) { + if (isCRLF) { + doc.putProperty(EndOfLineStringProperty, "\r\n"); + } + else if (isCR) { + doc.putProperty(EndOfLineStringProperty, "\r"); + } + else { + doc.putProperty(EndOfLineStringProperty, "\n"); + } + } + } + + /** + * Writes content from a document to the given stream + * as plain text. + * + * @param out The stream to write to + * @param doc The source for the write. + * @param pos The location in the document to fetch the + * content from >= 0. + * @param len The amount to write out >= 0. + * @exception IOException on any I/O error + * @exception BadLocationException if pos is not within 0 and + * the length of the document. + */ + public void write(Writer out, Document doc, int pos, int len) + throws IOException, BadLocationException { + + if ((pos < 0) || ((pos + len) > doc.getLength())) { + throw new BadLocationException("DefaultEditorKit.write", pos); + } + Segment data = new Segment(); + int nleft = len; + int offs = pos; + Object endOfLineProperty = doc.getProperty(EndOfLineStringProperty); + if (endOfLineProperty == null) { + try { + endOfLineProperty = System.getProperty("line.separator"); + } catch (SecurityException se) { } + } + String endOfLine; + if (endOfLineProperty instanceof String) { + endOfLine = (String)endOfLineProperty; + } + else { + endOfLine = null; + } + if (endOfLineProperty != null && !endOfLine.equals("\n")) { + // There is an end of line string that isn't \n, have to iterate + // through and find all \n's and translate to end of line string. + while (nleft > 0) { + int n = Math.min(nleft, 4096); + doc.getText(offs, n, data); + int last = data.offset; + char[] array = data.array; + int maxCounter = last + data.count; + for (int counter = last; counter < maxCounter; counter++) { + if (array[counter] == '\n') { + if (counter > last) { + out.write(array, last, counter - last); + } + out.write(endOfLine); + last = counter + 1; + } + } + if (maxCounter > last) { + out.write(array, last, maxCounter - last); + } + offs += n; + nleft -= n; + } + } + else { + // Just write out text, will already have \n, no mapping to + // do. + while (nleft > 0) { + int n = Math.min(nleft, 4096); + doc.getText(offs, n, data); + out.write(data.array, data.offset, data.count); + offs += n; + nleft -= n; + } + } + out.flush(); + } + + + /** + * When reading a document if a CRLF is encountered a property + * with this name is added and the value will be "\r\n". + */ + public static final String EndOfLineStringProperty = "__EndOfLine__"; + + // --- names of well-known actions --------------------------- + + /** + * Name of the action to place content into the associated + * document. If there is a selection, it is removed before + * the new content is added. + * @see #getActions + */ + public static final String insertContentAction = "insert-content"; + + /** + * Name of the action to place a line/paragraph break into + * the document. If there is a selection, it is removed before + * the break is added. + * @see #getActions + */ + public static final String insertBreakAction = "insert-break"; + + /** + * Name of the action to place a tab character into + * the document. If there is a selection, it is removed before + * the tab is added. + * @see #getActions + */ + public static final String insertTabAction = "insert-tab"; + + /** + * Name of the action to delete the character of content that + * precedes the current caret position. + * @see #getActions + */ + public static final String deletePrevCharAction = "delete-previous"; + + /** + * Name of the action to delete the character of content that + * follows the current caret position. + * @see #getActions + */ + public static final String deleteNextCharAction = "delete-next"; + + /** + * Name of the action to delete the word that + * follows the beginning of the selection. + * @see #getActions + * @see JTextComponent#getSelectionStart + * @since 1.6 + */ + public static final String deleteNextWordAction = "delete-next-word"; + + /** + * Name of the action to delete the word that + * precedes the beginning of the selection. + * @see #getActions + * @see JTextComponent#getSelectionStart + * @since 1.6 + */ + public static final String deletePrevWordAction = "delete-previous-word"; + + /** + * Name of the action to set the editor into read-only + * mode. + * @see #getActions + */ + public static final String readOnlyAction = "set-read-only"; + + /** + * Name of the action to set the editor into writeable + * mode. + * @see #getActions + */ + public static final String writableAction = "set-writable"; + + /** + * Name of the action to cut the selected region + * and place the contents into the system clipboard. + * @see JTextComponent#cut + * @see #getActions + */ + public static final String cutAction = "cut-to-clipboard"; + + /** + * Name of the action to copy the selected region + * and place the contents into the system clipboard. + * @see JTextComponent#copy + * @see #getActions + */ + public static final String copyAction = "copy-to-clipboard"; + + /** + * Name of the action to paste the contents of the + * system clipboard into the selected region, or before the + * caret if nothing is selected. + * @see JTextComponent#paste + * @see #getActions + */ + public static final String pasteAction = "paste-from-clipboard"; + + /** + * Name of the action to create a beep. + * @see #getActions + */ + public static final String beepAction = "beep"; + + /** + * Name of the action to page up vertically. + * @see #getActions + */ + public static final String pageUpAction = "page-up"; + + /** + * Name of the action to page down vertically. + * @see #getActions + */ + public static final String pageDownAction = "page-down"; + + /** + * Name of the action to page up vertically, and move the + * selection. + * @see #getActions + */ + /*public*/ static final String selectionPageUpAction = "selection-page-up"; + + /** + * Name of the action to page down vertically, and move the + * selection. + * @see #getActions + */ + /*public*/ static final String selectionPageDownAction = "selection-page-down"; + + /** + * Name of the action to page left horizontally, and move the + * selection. + * @see #getActions + */ + /*public*/ static final String selectionPageLeftAction = "selection-page-left"; + + /** + * Name of the action to page right horizontally, and move the + * selection. + * @see #getActions + */ + /*public*/ static final String selectionPageRightAction = "selection-page-right"; + + /** + * Name of the Action for moving the caret + * logically forward one position. + * @see #getActions + */ + public static final String forwardAction = "caret-forward"; + + /** + * Name of the Action for moving the caret + * logically backward one position. + * @see #getActions + */ + public static final String backwardAction = "caret-backward"; + + /** + * Name of the Action for extending the selection + * by moving the caret logically forward one position. + * @see #getActions + */ + public static final String selectionForwardAction = "selection-forward"; + + /** + * Name of the Action for extending the selection + * by moving the caret logically backward one position. + * @see #getActions + */ + public static final String selectionBackwardAction = "selection-backward"; + + /** + * Name of the Action for moving the caret + * logically upward one position. + * @see #getActions + */ + public static final String upAction = "caret-up"; + + /** + * Name of the Action for moving the caret + * logically downward one position. + * @see #getActions + */ + public static final String downAction = "caret-down"; + + /** + * Name of the Action for moving the caret + * logically upward one position, extending the selection. + * @see #getActions + */ + public static final String selectionUpAction = "selection-up"; + + /** + * Name of the Action for moving the caret + * logically downward one position, extending the selection. + * @see #getActions + */ + public static final String selectionDownAction = "selection-down"; + + /** + * Name of the Action for moving the caret + * to the beginning of a word. + * @see #getActions + */ + public static final String beginWordAction = "caret-begin-word"; + + /** + * Name of the Action for moving the caret + * to the end of a word. + * @see #getActions + */ + public static final String endWordAction = "caret-end-word"; + + /** + * Name of the Action for moving the caret + * to the beginning of a word, extending the selection. + * @see #getActions + */ + public static final String selectionBeginWordAction = "selection-begin-word"; + + /** + * Name of the Action for moving the caret + * to the end of a word, extending the selection. + * @see #getActions + */ + public static final String selectionEndWordAction = "selection-end-word"; + + /** + * Name of the Action for moving the caret to the + * beginning of the previous word. + * @see #getActions + */ + public static final String previousWordAction = "caret-previous-word"; + + /** + * Name of the Action for moving the caret to the + * beginning of the next word. + * @see #getActions + */ + public static final String nextWordAction = "caret-next-word"; + + /** + * Name of the Action for moving the selection to the + * beginning of the previous word, extending the selection. + * @see #getActions + */ + public static final String selectionPreviousWordAction = "selection-previous-word"; + + /** + * Name of the Action for moving the selection to the + * beginning of the next word, extending the selection. + * @see #getActions + */ + public static final String selectionNextWordAction = "selection-next-word"; + + /** + * Name of the Action for moving the caret + * to the beginning of a line. + * @see #getActions + */ + public static final String beginLineAction = "caret-begin-line"; + + /** + * Name of the Action for moving the caret + * to the end of a line. + * @see #getActions + */ + public static final String endLineAction = "caret-end-line"; + + /** + * Name of the Action for moving the caret + * to the beginning of a line, extending the selection. + * @see #getActions + */ + public static final String selectionBeginLineAction = "selection-begin-line"; + + /** + * Name of the Action for moving the caret + * to the end of a line, extending the selection. + * @see #getActions + */ + public static final String selectionEndLineAction = "selection-end-line"; + + /** + * Name of the Action for moving the caret + * to the beginning of a paragraph. + * @see #getActions + */ + public static final String beginParagraphAction = "caret-begin-paragraph"; + + /** + * Name of the Action for moving the caret + * to the end of a paragraph. + * @see #getActions + */ + public static final String endParagraphAction = "caret-end-paragraph"; + + /** + * Name of the Action for moving the caret + * to the beginning of a paragraph, extending the selection. + * @see #getActions + */ + public static final String selectionBeginParagraphAction = "selection-begin-paragraph"; + + /** + * Name of the Action for moving the caret + * to the end of a paragraph, extending the selection. + * @see #getActions + */ + public static final String selectionEndParagraphAction = "selection-end-paragraph"; + + /** + * Name of the Action for moving the caret + * to the beginning of the document. + * @see #getActions + */ + public static final String beginAction = "caret-begin"; + + /** + * Name of the Action for moving the caret + * to the end of the document. + * @see #getActions + */ + public static final String endAction = "caret-end"; + + /** + * Name of the Action for moving the caret + * to the beginning of the document. + * @see #getActions + */ + public static final String selectionBeginAction = "selection-begin"; + + /** + * Name of the Action for moving the caret + * to the end of the document. + * @see #getActions + */ + public static final String selectionEndAction = "selection-end"; + + /** + * Name of the Action for selecting a word around the caret. + * @see #getActions + */ + public static final String selectWordAction = "select-word"; + + /** + * Name of the Action for selecting a line around the caret. + * @see #getActions + */ + public static final String selectLineAction = "select-line"; + + /** + * Name of the Action for selecting a paragraph around the caret. + * @see #getActions + */ + public static final String selectParagraphAction = "select-paragraph"; + + /** + * Name of the Action for selecting the entire document + * @see #getActions + */ + public static final String selectAllAction = "select-all"; + + /** + * Name of the Action for removing selection + * @see #getActions + */ + /*public*/ static final String unselectAction = "unselect"; + + /** + * Name of the Action for toggling the component's orientation. + * @see #getActions + */ + /*public*/ static final String toggleComponentOrientationAction + = "toggle-componentOrientation"; + + /** + * Name of the action that is executed by default if + * a key typed event is received and there + * is no keymap entry. + * @see #getActions + */ + public static final String defaultKeyTypedAction = "default-typed"; + + // --- Action implementations --------------------------------- + + private static final Action[] defaultActions = { + new InsertContentAction(), new DeletePrevCharAction(), + new DeleteNextCharAction(), new ReadOnlyAction(), + new DeleteWordAction(deletePrevWordAction), + new DeleteWordAction(deleteNextWordAction), + new WritableAction(), new CutAction(), + new CopyAction(), new PasteAction(), + new VerticalPageAction(pageUpAction, -1, false), + new VerticalPageAction(pageDownAction, 1, false), + new VerticalPageAction(selectionPageUpAction, -1, true), + new VerticalPageAction(selectionPageDownAction, 1, true), + new PageAction(selectionPageLeftAction, true, true), + new PageAction(selectionPageRightAction, false, true), + new InsertBreakAction(), new BeepAction(), + new NextVisualPositionAction(forwardAction, false, + SwingConstants.EAST), + new NextVisualPositionAction(backwardAction, false, + SwingConstants.WEST), + new NextVisualPositionAction(selectionForwardAction, true, + SwingConstants.EAST), + new NextVisualPositionAction(selectionBackwardAction, true, + SwingConstants.WEST), + new NextVisualPositionAction(upAction, false, + SwingConstants.NORTH), + new NextVisualPositionAction(downAction, false, + SwingConstants.SOUTH), + new NextVisualPositionAction(selectionUpAction, true, + SwingConstants.NORTH), + new NextVisualPositionAction(selectionDownAction, true, + SwingConstants.SOUTH), + new BeginWordAction(beginWordAction, false), + new EndWordAction(endWordAction, false), + new BeginWordAction(selectionBeginWordAction, true), + new EndWordAction(selectionEndWordAction, true), + new PreviousWordAction(previousWordAction, false), + new NextWordAction(nextWordAction, false), + new PreviousWordAction(selectionPreviousWordAction, true), + new NextWordAction(selectionNextWordAction, true), + new BeginLineAction(beginLineAction, false), + new EndLineAction(endLineAction, false), + new BeginLineAction(selectionBeginLineAction, true), + new EndLineAction(selectionEndLineAction, true), + new BeginParagraphAction(beginParagraphAction, false), + new EndParagraphAction(endParagraphAction, false), + new BeginParagraphAction(selectionBeginParagraphAction, true), + new EndParagraphAction(selectionEndParagraphAction, true), + new BeginAction(beginAction, false), + new EndAction(endAction, false), + new BeginAction(selectionBeginAction, true), + new EndAction(selectionEndAction, true), + new DefaultKeyTypedAction(), new InsertTabAction(), + new SelectWordAction(), new SelectLineAction(), + new SelectParagraphAction(), new SelectAllAction(), + new UnselectAction(), new ToggleComponentOrientationAction(), + new DumpModelAction() + }; + + /** + * The action that is executed by default if + * a key typed event is received and there + * is no keymap entry. There is a variation across + * different VM's in what gets sent as a key typed + * event, and this action tries to filter out the undesired + * events. This filters the control characters and those + * with the ALT modifier. It allows Control-Alt sequences + * through as these form legitimate unicode characters on + * some PC keyboards. + *

+ * If the event doesn't get filtered, it will try to insert + * content into the text editor. The content is fetched + * from the command string of the ActionEvent. The text + * entry is done through the replaceSelection + * method on the target text component. This is the + * action that will be fired for most text entry tasks. + *

+ * Warning: + * Serialized objects of this class will not be compatible with + * future Swing releases. The current serialization support is + * appropriate for short term storage or RMI between applications running + * the same version of Swing. As of 1.4, support for long term storage + * of all JavaBeansTM + * has been added to the java.beans package. + * Please see {@link java.beans.XMLEncoder}. + * + * @see DefaultEditorKit#defaultKeyTypedAction + * @see DefaultEditorKit#getActions + * @see Keymap#setDefaultAction + * @see Keymap#getDefaultAction + */ + public static class DefaultKeyTypedAction extends TextAction { + + /** + * Creates this object with the appropriate identifier. + */ + public DefaultKeyTypedAction() { + super(defaultKeyTypedAction); + } + + /** + * The operation to perform when this action is triggered. + * + * @param e the action event + */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if ((target != null) && (e != null)) { + if ((! target.isEditable()) || (! target.isEnabled())) { + return; + } + String content = e.getActionCommand(); + int mod = e.getModifiers(); + if ((content != null) && (content.length() > 0) && + ((mod & ActionEvent.ALT_MASK) == (mod & ActionEvent.CTRL_MASK))) { + char c = content.charAt(0); + if ((c >= 0x20) && (c != 0x7F)) { + target.replaceSelection(content); + } + } + } + } + } + + /** + * Places content into the associated document. + * If there is a selection, it is removed before + * the new content is added. + *

+ * Warning: + * Serialized objects of this class will not be compatible with + * future Swing releases. The current serialization support is + * appropriate for short term storage or RMI between applications running + * the same version of Swing. As of 1.4, support for long term storage + * of all JavaBeansTM + * has been added to the java.beans package. + * Please see {@link java.beans.XMLEncoder}. + * + * @see DefaultEditorKit#insertContentAction + * @see DefaultEditorKit#getActions + */ + public static class InsertContentAction extends TextAction { + + /** + * Creates this object with the appropriate identifier. + */ + public InsertContentAction() { + super(insertContentAction); + } + + /** + * The operation to perform when this action is triggered. + * + * @param e the action event + */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if ((target != null) && (e != null)) { + if ((! target.isEditable()) || (! target.isEnabled())) { + UIManager.getLookAndFeel().provideErrorFeedback(target); + return; + } + String content = e.getActionCommand(); + if (content != null) { + target.replaceSelection(content); + } else { + UIManager.getLookAndFeel().provideErrorFeedback(target); + } + } + } + } + + /** + * Places a line/paragraph break into the document. + * If there is a selection, it is removed before + * the break is added. + *

+ * Warning: + * Serialized objects of this class will not be compatible with + * future Swing releases. The current serialization support is + * appropriate for short term storage or RMI between applications running + * the same version of Swing. As of 1.4, support for long term storage + * of all JavaBeansTM + * has been added to the java.beans package. + * Please see {@link java.beans.XMLEncoder}. + * + * @see DefaultEditorKit#insertBreakAction + * @see DefaultEditorKit#getActions + */ + public static class InsertBreakAction extends TextAction { + + /** + * Creates this object with the appropriate identifier. + */ + public InsertBreakAction() { + super(insertBreakAction); + } + + /** + * The operation to perform when this action is triggered. + * + * @param e the action event + */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + if ((! target.isEditable()) || (! target.isEnabled())) { + UIManager.getLookAndFeel().provideErrorFeedback(target); + return; + } + target.replaceSelection("\n"); + } + } + } + + /** + * Places a tab character into the document. If there + * is a selection, it is removed before the tab is added. + *

+ * Warning: + * Serialized objects of this class will not be compatible with + * future Swing releases. The current serialization support is + * appropriate for short term storage or RMI between applications running + * the same version of Swing. As of 1.4, support for long term storage + * of all JavaBeansTM + * has been added to the java.beans package. + * Please see {@link java.beans.XMLEncoder}. + * + * @see DefaultEditorKit#insertTabAction + * @see DefaultEditorKit#getActions + */ + public static class InsertTabAction extends TextAction { + + /** + * Creates this object with the appropriate identifier. + */ + public InsertTabAction() { + super(insertTabAction); + } + + /** + * The operation to perform when this action is triggered. + * + * @param e the action event + */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + if ((! target.isEditable()) || (! target.isEnabled())) { + UIManager.getLookAndFeel().provideErrorFeedback(target); + return; + } + target.replaceSelection("\t"); + } + } + } + + /* + * Deletes the character of content that precedes the + * current caret position. + * @see DefaultEditorKit#deletePrevCharAction + * @see DefaultEditorKit#getActions + */ + static class DeletePrevCharAction extends TextAction { + + /** + * Creates this object with the appropriate identifier. + */ + DeletePrevCharAction() { + super(deletePrevCharAction); + } + + /** + * The operation to perform when this action is triggered. + * + * @param e the action event + */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + boolean beep = true; + if ((target != null) && (target.isEditable())) { + try { + Document doc = target.getDocument(); + Caret caret = target.getCaret(); + int dot = caret.getDot(); + int mark = caret.getMark(); + if (dot != mark) { + doc.remove(Math.min(dot, mark), Math.abs(dot - mark)); + beep = false; + } else if (dot > 0) { + int delChars = 1; + + if (dot > 1) { + String dotChars = doc.getText(dot - 2, 2); + char c0 = dotChars.charAt(0); + char c1 = dotChars.charAt(1); + + if (c0 >= '\uD800' && c0 <= '\uDBFF' && + c1 >= '\uDC00' && c1 <= '\uDFFF') { + delChars = 2; + } + } + + doc.remove(dot - delChars, delChars); + beep = false; + } + } catch (BadLocationException bl) { + } + } + if (beep) { + UIManager.getLookAndFeel().provideErrorFeedback(target); + } + } + } + + /* + * Deletes the character of content that follows the + * current caret position. + * @see DefaultEditorKit#deleteNextCharAction + * @see DefaultEditorKit#getActions + */ + static class DeleteNextCharAction extends TextAction { + + /* Create this object with the appropriate identifier. */ + DeleteNextCharAction() { + super(deleteNextCharAction); + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + boolean beep = true; + if ((target != null) && (target.isEditable())) { + try { + Document doc = target.getDocument(); + Caret caret = target.getCaret(); + int dot = caret.getDot(); + int mark = caret.getMark(); + if (dot != mark) { + doc.remove(Math.min(dot, mark), Math.abs(dot - mark)); + beep = false; + } else if (dot < doc.getLength()) { + int delChars = 1; + + if (dot < doc.getLength() - 1) { + String dotChars = doc.getText(dot, 2); + char c0 = dotChars.charAt(0); + char c1 = dotChars.charAt(1); + + if (c0 >= '\uD800' && c0 <= '\uDBFF' && + c1 >= '\uDC00' && c1 <= '\uDFFF') { + delChars = 2; + } + } + + doc.remove(dot, delChars); + beep = false; + } + } catch (BadLocationException bl) { + } + } + if (beep) { + UIManager.getLookAndFeel().provideErrorFeedback(target); + } + } + } + + + /* + * Deletes the word that precedes/follows the beginning of the selection. + * @see DefaultEditorKit#getActions + */ + static class DeleteWordAction extends TextAction { + DeleteWordAction(String name) { + super(name); + assert (name == deletePrevWordAction) + || (name == deleteNextWordAction); + } + /** + * The operation to perform when this action is triggered. + * + * @param e the action event + */ + public void actionPerformed(ActionEvent e) { + final JTextComponent target = getTextComponent(e); + if ((target != null) && (e != null)) { + if ((! target.isEditable()) || (! target.isEnabled())) { + UIManager.getLookAndFeel().provideErrorFeedback(target); + return; + } + boolean beep = true; + try { + final int start = target.getSelectionStart(); + final Element line = + Utilities.getParagraphElement(target, start); + int end; + if (deleteNextWordAction == getValue(Action.NAME)) { + end = Utilities. + getNextWordInParagraph(target, line, start, false); + if (end == java.text.BreakIterator.DONE) { + //last word in the paragraph + final int endOfLine = line.getEndOffset(); + if (start == endOfLine - 1) { + //for last position remove last \n + end = endOfLine; + } else { + //remove to the end of the paragraph + end = endOfLine - 1; + } + } + } else { + end = Utilities. + getPrevWordInParagraph(target, line, start); + if (end == java.text.BreakIterator.DONE) { + //there is no previous word in the paragraph + final int startOfLine = line.getStartOffset(); + if (start == startOfLine) { + //for first position remove previous \n + end = startOfLine - 1; + } else { + //remove to the start of the paragraph + end = startOfLine; + } + } + } + int offs = Math.min(start, end); + int len = Math.abs(end - start); + if (offs >= 0) { + target.getDocument().remove(offs, len); + beep = false; + } + } catch (BadLocationException ignore) { + } + if (beep) { + UIManager.getLookAndFeel().provideErrorFeedback(target); + } + } + } + } + + + /* + * Sets the editor into read-only mode. + * @see DefaultEditorKit#readOnlyAction + * @see DefaultEditorKit#getActions + */ + static class ReadOnlyAction extends TextAction { + + /* Create this object with the appropriate identifier. */ + ReadOnlyAction() { + super(readOnlyAction); + } + + /** + * The operation to perform when this action is triggered. + * + * @param e the action event + */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + target.setEditable(false); + } + } + } + + /* + * Sets the editor into writeable mode. + * @see DefaultEditorKit#writableAction + * @see DefaultEditorKit#getActions + */ + static class WritableAction extends TextAction { + + /* Create this object with the appropriate identifier. */ + WritableAction() { + super(writableAction); + } + + /** + * The operation to perform when this action is triggered. + * + * @param e the action event + */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + target.setEditable(true); + } + } + } + + /** + * Cuts the selected region and place its contents + * into the system clipboard. + *

+ * Warning: + * Serialized objects of this class will not be compatible with + * future Swing releases. The current serialization support is + * appropriate for short term storage or RMI between applications running + * the same version of Swing. As of 1.4, support for long term storage + * of all JavaBeansTM + * has been added to the java.beans package. + * Please see {@link java.beans.XMLEncoder}. + * + * @see DefaultEditorKit#cutAction + * @see DefaultEditorKit#getActions + */ + public static class CutAction extends TextAction { + + /** Create this object with the appropriate identifier. */ + public CutAction() { + super(cutAction); + } + + /** + * The operation to perform when this action is triggered. + * + * @param e the action event + */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + target.cut(); + } + } + } + + /** + * Copies the selected region and place its contents + * into the system clipboard. + *

+ * Warning: + * Serialized objects of this class will not be compatible with + * future Swing releases. The current serialization support is + * appropriate for short term storage or RMI between applications running + * the same version of Swing. As of 1.4, support for long term storage + * of all JavaBeansTM + * has been added to the java.beans package. + * Please see {@link java.beans.XMLEncoder}. + * + * @see DefaultEditorKit#copyAction + * @see DefaultEditorKit#getActions + */ + public static class CopyAction extends TextAction { + + /** Create this object with the appropriate identifier. */ + public CopyAction() { + super(copyAction); + } + + /** + * The operation to perform when this action is triggered. + * + * @param e the action event + */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + target.copy(); + } + } + } + + /** + * Pastes the contents of the system clipboard into the + * selected region, or before the caret if nothing is + * selected. + *

+ * Warning: + * Serialized objects of this class will not be compatible with + * future Swing releases. The current serialization support is + * appropriate for short term storage or RMI between applications running + * the same version of Swing. As of 1.4, support for long term storage + * of all JavaBeansTM + * has been added to the java.beans package. + * Please see {@link java.beans.XMLEncoder}. + * + * @see DefaultEditorKit#pasteAction + * @see DefaultEditorKit#getActions + */ + public static class PasteAction extends TextAction { + + /** Create this object with the appropriate identifier. */ + public PasteAction() { + super(pasteAction); + } + + /** + * The operation to perform when this action is triggered. + * + * @param e the action event + */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + target.paste(); + } + } + } + + /** + * Creates a beep. + *

+ * Warning: + * Serialized objects of this class will not be compatible with + * future Swing releases. The current serialization support is + * appropriate for short term storage or RMI between applications running + * the same version of Swing. As of 1.4, support for long term storage + * of all JavaBeansTM + * has been added to the java.beans package. + * Please see {@link java.beans.XMLEncoder}. + * + * @see DefaultEditorKit#beepAction + * @see DefaultEditorKit#getActions + */ + public static class BeepAction extends TextAction { + + /** Create this object with the appropriate identifier. */ + public BeepAction() { + super(beepAction); + } + + /** + * The operation to perform when this action is triggered. + * + * @param e the action event + */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + UIManager.getLookAndFeel().provideErrorFeedback(target); + } + } + + /** + * Scrolls up/down vertically. The select version of this action extends + * the selection, instead of simply moving the caret. + * + * @see DefaultEditorKit#pageUpAction + * @see DefaultEditorKit#pageDownAction + * @see DefaultEditorKit#getActions + */ + static class VerticalPageAction extends TextAction { + + /** Create this object with the appropriate identifier. */ + public VerticalPageAction(String nm, int direction, boolean select) { + super(nm); + this.select = select; + this.direction = direction; + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + Rectangle visible = target.getVisibleRect(); + Rectangle newVis = new Rectangle(visible); + int selectedIndex = target.getCaretPosition(); + int scrollAmount = direction * + target.getScrollableBlockIncrement( + visible, SwingConstants.VERTICAL, direction); + int initialY = visible.y; + Caret caret = target.getCaret(); + Point magicPosition = caret.getMagicCaretPosition(); + + if (selectedIndex != -1) { + try { + Rectangle dotBounds = target.modelToView( + selectedIndex); + int x = (magicPosition != null) ? magicPosition.x : + dotBounds.x; + int h = dotBounds.height; + if (h > 0) { + // We want to scroll by a multiple of caret height, + // rounding towards lower integer + scrollAmount = scrollAmount / h * h; + } + newVis.y = constrainY(target, + initialY + scrollAmount, visible.height); + + int newIndex; + + if (visible.contains(dotBounds.x, dotBounds.y)) { + // Dot is currently visible, base the new + // location off the old, or + newIndex = target.viewToModel( + new Point(x, constrainY(target, + dotBounds.y + scrollAmount, 0))); + } + else { + // Dot isn't visible, choose the top or the bottom + // for the new location. + if (direction == -1) { + newIndex = target.viewToModel(new Point( + x, newVis.y)); + } + else { + newIndex = target.viewToModel(new Point( + x, newVis.y + visible.height)); + } + } + newIndex = constrainOffset(target, newIndex); + if (newIndex != selectedIndex) { + // Make sure the new visible location contains + // the location of dot, otherwise Caret will + // cause an additional scroll. + adjustScrollIfNecessary(target, newVis, initialY, + newIndex); + if (select) { + target.moveCaretPosition(newIndex); + } + else { + target.setCaretPosition(newIndex); + } + } + } catch (BadLocationException ble) { } + } else { + newVis.y = constrainY(target, + initialY + scrollAmount, visible.height); + } + if (magicPosition != null) { + caret.setMagicCaretPosition(magicPosition); + } + target.scrollRectToVisible(newVis); + } + } + + /** + * Makes sure y is a valid location in + * target. + */ + private int constrainY(JTextComponent target, int y, int vis) { + if (y < 0) { + y = 0; + } + else if (y + vis > target.getHeight()) { + y = Math.max(0, target.getHeight() - vis); + } + return y; + } + + /** + * Ensures that offset is a valid offset into the + * model for text. + */ + private int constrainOffset(JTextComponent text, int offset) { + Document doc = text.getDocument(); + + if ((offset != 0) && (offset > doc.getLength())) { + offset = doc.getLength(); + } + if (offset < 0) { + offset = 0; + } + return offset; + } + + /** + * Adjusts the rectangle that indicates the location to scroll to + * after selecting index. + */ + private void adjustScrollIfNecessary(JTextComponent text, + Rectangle visible, int initialY, + int index) { + try { + Rectangle dotBounds = text.modelToView(index); + + if (dotBounds.y < visible.y || + (dotBounds.y > (visible.y + visible.height)) || + (dotBounds.y + dotBounds.height) > + (visible.y + visible.height)) { + int y; + + if (dotBounds.y < visible.y) { + y = dotBounds.y; + } + else { + y = dotBounds.y + dotBounds.height - visible.height; + } + if ((direction == -1 && y < initialY) || + (direction == 1 && y > initialY)) { + // Only adjust if won't cause scrolling upward. + visible.y = y; + } + } + } catch (BadLocationException ble) {} + } + + /** + * Adjusts the Rectangle to contain the bounds of the character at + * index in response to a page up. + */ + private boolean select; + + /** + * Direction to scroll, 1 is down, -1 is up. + */ + private int direction; + } + + + /** + * Pages one view to the left or right. + */ + static class PageAction extends TextAction { + + /** Create this object with the appropriate identifier. */ + public PageAction(String nm, boolean left, boolean select) { + super(nm); + this.select = select; + this.left = left; + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + int selectedIndex; + Rectangle visible = new Rectangle(); + target.computeVisibleRect(visible); + if (left) { + visible.x = Math.max(0, visible.x - visible.width); + } + else { + visible.x += visible.width; + } + + selectedIndex = target.getCaretPosition(); + if(selectedIndex != -1) { + if (left) { + selectedIndex = target.viewToModel + (new Point(visible.x, visible.y)); + } + else { + selectedIndex = target.viewToModel + (new Point(visible.x + visible.width - 1, + visible.y + visible.height - 1)); + } + Document doc = target.getDocument(); + if ((selectedIndex != 0) && + (selectedIndex > (doc.getLength()-1))) { + selectedIndex = doc.getLength()-1; + } + else if(selectedIndex < 0) { + selectedIndex = 0; + } + if (select) + target.moveCaretPosition(selectedIndex); + else + target.setCaretPosition(selectedIndex); + } + } + } + + private boolean select; + private boolean left; + } + + static class DumpModelAction extends TextAction { + + DumpModelAction() { + super("dump-model"); + } + + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + Document d = target.getDocument(); + if (d instanceof AbstractDocument) { + ((AbstractDocument) d).dump(System.err); + } + } + } + } + + /* + * Action to move the selection by way of the + * getNextVisualPositionFrom method. Constructor indicates direction + * to use. + */ + static class NextVisualPositionAction extends TextAction { + + /** + * Create this action with the appropriate identifier. + * @param nm the name of the action, Action.NAME. + * @param select whether to extend the selection when + * changing the caret position. + */ + NextVisualPositionAction(String nm, boolean select, int direction) { + super(nm); + this.select = select; + this.direction = direction; + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + Caret caret = target.getCaret(); + DefaultCaret bidiCaret = (caret instanceof DefaultCaret) ? + (DefaultCaret)caret : null; + int dot = caret.getDot(); + Position.Bias[] bias = new Position.Bias[1]; + Point magicPosition = caret.getMagicCaretPosition(); + + try { + if(magicPosition == null && + (direction == SwingConstants.NORTH || + direction == SwingConstants.SOUTH)) { + Rectangle r = (bidiCaret != null) ? + target.getUI().modelToView(target, dot, + bidiCaret.getDotBias()) : + target.modelToView(dot); + magicPosition = new Point(r.x, r.y); + } + + NavigationFilter filter = target.getNavigationFilter(); + + if (filter != null) { + dot = filter.getNextVisualPositionFrom + (target, dot, (bidiCaret != null) ? + bidiCaret.getDotBias() : + Position.Bias.Forward, direction, bias); + } + else { + dot = target.getUI().getNextVisualPositionFrom + (target, dot, (bidiCaret != null) ? + bidiCaret.getDotBias() : + Position.Bias.Forward, direction, bias); + } + if(bias[0] == null) { + bias[0] = Position.Bias.Forward; + } + if(bidiCaret != null) { + if (select) { + bidiCaret.moveDot(dot, bias[0]); + } else { + bidiCaret.setDot(dot, bias[0]); + } + } + else { + if (select) { + caret.moveDot(dot); + } else { + caret.setDot(dot); + } + } + if(magicPosition != null && + (direction == SwingConstants.NORTH || + direction == SwingConstants.SOUTH)) { + target.getCaret().setMagicCaretPosition(magicPosition); + } + } catch (BadLocationException ex) { + } + } + } + + private boolean select; + private int direction; + } + + /* + * Position the caret to the beginning of the word. + * @see DefaultEditorKit#beginWordAction + * @see DefaultEditorKit#selectBeginWordAction + * @see DefaultEditorKit#getActions + */ + static class BeginWordAction extends TextAction { + + /** + * Create this action with the appropriate identifier. + * @param nm the name of the action, Action.NAME. + * @param select whether to extend the selection when + * changing the caret position. + */ + BeginWordAction(String nm, boolean select) { + super(nm); + this.select = select; + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + try { + int offs = target.getCaretPosition(); + int begOffs = Utilities.getWordStart(target, offs); + if (select) { + target.moveCaretPosition(begOffs); + } else { + target.setCaretPosition(begOffs); + } + } catch (BadLocationException bl) { + UIManager.getLookAndFeel().provideErrorFeedback(target); + } + } + } + + private boolean select; + } + + /* + * Position the caret to the end of the word. + * @see DefaultEditorKit#endWordAction + * @see DefaultEditorKit#selectEndWordAction + * @see DefaultEditorKit#getActions + */ + static class EndWordAction extends TextAction { + + /** + * Create this action with the appropriate identifier. + * @param nm the name of the action, Action.NAME. + * @param select whether to extend the selection when + * changing the caret position. + */ + EndWordAction(String nm, boolean select) { + super(nm); + this.select = select; + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + try { + int offs = target.getCaretPosition(); + int endOffs = Utilities.getWordEnd(target, offs); + if (select) { + target.moveCaretPosition(endOffs); + } else { + target.setCaretPosition(endOffs); + } + } catch (BadLocationException bl) { + UIManager.getLookAndFeel().provideErrorFeedback(target); + } + } + } + + private boolean select; + } + + /* + * Position the caret to the beginning of the previous word. + * @see DefaultEditorKit#previousWordAction + * @see DefaultEditorKit#selectPreviousWordAction + * @see DefaultEditorKit#getActions + */ + static class PreviousWordAction extends TextAction { + + /** + * Create this action with the appropriate identifier. + * @param nm the name of the action, Action.NAME. + * @param select whether to extend the selection when + * changing the caret position. + */ + PreviousWordAction(String nm, boolean select) { + super(nm); + this.select = select; + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + int offs = target.getCaretPosition(); + boolean failed = false; + try { + Element curPara = + Utilities.getParagraphElement(target, offs); + offs = Utilities.getPreviousWord(target, offs); + if(offs < curPara.getStartOffset()) { + // we should first move to the end of the + // previous paragraph (bug #4278839) + offs = Utilities.getParagraphElement(target, offs). + getEndOffset() - 1; + } + } catch (BadLocationException bl) { + if (offs != 0) { + offs = 0; + } + else { + failed = true; + } + } + if (!failed) { + if (select) { + target.moveCaretPosition(offs); + } else { + target.setCaretPosition(offs); + } + } + else { + UIManager.getLookAndFeel().provideErrorFeedback(target); + } + } + } + + private boolean select; + } + + /* + * Position the caret to the next of the word. + * @see DefaultEditorKit#nextWordAction + * @see DefaultEditorKit#selectNextWordAction + * @see DefaultEditorKit#getActions + */ + static class NextWordAction extends TextAction { + + /** + * Create this action with the appropriate identifier. + * @param nm the name of the action, Action.NAME. + * @param select whether to extend the selection when + * changing the caret position. + */ + NextWordAction(String nm, boolean select) { + super(nm); + this.select = select; + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + int offs = target.getCaretPosition(); + boolean failed = false; + int oldOffs = offs; + Element curPara = + Utilities.getParagraphElement(target, offs); + try { + offs = Utilities.getNextWord(target, offs); + if(offs >= curPara.getEndOffset() && + oldOffs != curPara.getEndOffset() - 1) { + // we should first move to the end of current + // paragraph (bug #4278839) + offs = curPara.getEndOffset() - 1; + } + } catch (BadLocationException bl) { + int end = target.getDocument().getLength(); + if (offs != end) { + if(oldOffs != curPara.getEndOffset() - 1) { + offs = curPara.getEndOffset() - 1; + } else { + offs = end; + } + } + else { + failed = true; + } + } + if (!failed) { + if (select) { + target.moveCaretPosition(offs); + } else { + target.setCaretPosition(offs); + } + } + else { + UIManager.getLookAndFeel().provideErrorFeedback(target); + } + } + } + + private boolean select; + } + + /* + * Position the caret to the beginning of the line. + * @see DefaultEditorKit#beginLineAction + * @see DefaultEditorKit#selectBeginLineAction + * @see DefaultEditorKit#getActions + */ + static class BeginLineAction extends TextAction { + + /** + * Create this action with the appropriate identifier. + * @param nm the name of the action, Action.NAME. + * @param select whether to extend the selection when + * changing the caret position. + */ + BeginLineAction(String nm, boolean select) { + super(nm); + this.select = select; + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + try { + int offs = target.getCaretPosition(); + int begOffs = Utilities.getRowStart(target, offs); + if (select) { + target.moveCaretPosition(begOffs); + } else { + target.setCaretPosition(begOffs); + } + } catch (BadLocationException bl) { + UIManager.getLookAndFeel().provideErrorFeedback(target); + } + } + } + + private boolean select; + } + + /* + * Position the caret to the end of the line. + * @see DefaultEditorKit#endLineAction + * @see DefaultEditorKit#selectEndLineAction + * @see DefaultEditorKit#getActions + */ + static class EndLineAction extends TextAction { + + /** + * Create this action with the appropriate identifier. + * @param nm the name of the action, Action.NAME. + * @param select whether to extend the selection when + * changing the caret position. + */ + EndLineAction(String nm, boolean select) { + super(nm); + this.select = select; + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + try { + int offs = target.getCaretPosition(); + int endOffs = Utilities.getRowEnd(target, offs); + if (select) { + target.moveCaretPosition(endOffs); + } else { + target.setCaretPosition(endOffs); + } + } catch (BadLocationException bl) { + UIManager.getLookAndFeel().provideErrorFeedback(target); + } + } + } + + private boolean select; + } + + /* + * Position the caret to the beginning of the paragraph. + * @see DefaultEditorKit#beginParagraphAction + * @see DefaultEditorKit#selectBeginParagraphAction + * @see DefaultEditorKit#getActions + */ + static class BeginParagraphAction extends TextAction { + + /** + * Create this action with the appropriate identifier. + * @param nm the name of the action, Action.NAME. + * @param select whether to extend the selection when + * changing the caret position. + */ + BeginParagraphAction(String nm, boolean select) { + super(nm); + this.select = select; + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + int offs = target.getCaretPosition(); + Element elem = Utilities.getParagraphElement(target, offs); + offs = elem.getStartOffset(); + if (select) { + target.moveCaretPosition(offs); + } else { + target.setCaretPosition(offs); + } + } + } + + private boolean select; + } + + /* + * Position the caret to the end of the paragraph. + * @see DefaultEditorKit#endParagraphAction + * @see DefaultEditorKit#selectEndParagraphAction + * @see DefaultEditorKit#getActions + */ + static class EndParagraphAction extends TextAction { + + /** + * Create this action with the appropriate identifier. + * @param nm the name of the action, Action.NAME. + * @param select whether to extend the selection when + * changing the caret position. + */ + EndParagraphAction(String nm, boolean select) { + super(nm); + this.select = select; + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + int offs = target.getCaretPosition(); + Element elem = Utilities.getParagraphElement(target, offs); + offs = Math.min(target.getDocument().getLength(), + elem.getEndOffset()); + if (select) { + target.moveCaretPosition(offs); + } else { + target.setCaretPosition(offs); + } + } + } + + private boolean select; + } + + /* + * Move the caret to the beginning of the document. + * @see DefaultEditorKit#beginAction + * @see DefaultEditorKit#getActions + */ + static class BeginAction extends TextAction { + + /* Create this object with the appropriate identifier. */ + BeginAction(String nm, boolean select) { + super(nm); + this.select = select; + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + if (select) { + target.moveCaretPosition(0); + } else { + target.setCaretPosition(0); + } + } + } + + private boolean select; + } + + /* + * Move the caret to the end of the document. + * @see DefaultEditorKit#endAction + * @see DefaultEditorKit#getActions + */ + static class EndAction extends TextAction { + + /* Create this object with the appropriate identifier. */ + EndAction(String nm, boolean select) { + super(nm); + this.select = select; + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + Document doc = target.getDocument(); + int dot = doc.getLength(); + if (select) { + target.moveCaretPosition(dot); + } else { + target.setCaretPosition(dot); + } + } + } + + private boolean select; + } + + /* + * Select the word around the caret + * @see DefaultEditorKit#endAction + * @see DefaultEditorKit#getActions + */ + static class SelectWordAction extends TextAction { + + /** + * Create this action with the appropriate identifier. + * @param nm the name of the action, Action.NAME. + * @param select whether to extend the selection when + * changing the caret position. + */ + SelectWordAction() { + super(selectWordAction); + start = new BeginWordAction("pigdog", false); + end = new EndWordAction("pigdog", true); + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + start.actionPerformed(e); + end.actionPerformed(e); + } + + private Action start; + private Action end; + } + + /* + * Select the line around the caret + * @see DefaultEditorKit#endAction + * @see DefaultEditorKit#getActions + */ + static class SelectLineAction extends TextAction { + + /** + * Create this action with the appropriate identifier. + * @param nm the name of the action, Action.NAME. + * @param select whether to extend the selection when + * changing the caret position. + */ + SelectLineAction() { + super(selectLineAction); + start = new BeginLineAction("pigdog", false); + end = new EndLineAction("pigdog", true); + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + start.actionPerformed(e); + end.actionPerformed(e); + } + + private Action start; + private Action end; + } + + /* + * Select the paragraph around the caret + * @see DefaultEditorKit#endAction + * @see DefaultEditorKit#getActions + */ + static class SelectParagraphAction extends TextAction { + + /** + * Create this action with the appropriate identifier. + * @param nm the name of the action, Action.NAME. + * @param select whether to extend the selection when + * changing the caret position. + */ + SelectParagraphAction() { + super(selectParagraphAction); + start = new BeginParagraphAction("pigdog", false); + end = new EndParagraphAction("pigdog", true); + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + start.actionPerformed(e); + end.actionPerformed(e); + } + + private Action start; + private Action end; + } + + /* + * Select the entire document + * @see DefaultEditorKit#endAction + * @see DefaultEditorKit#getActions + */ + static class SelectAllAction extends TextAction { + + /** + * Create this action with the appropriate identifier. + * @param nm the name of the action, Action.NAME. + * @param select whether to extend the selection when + * changing the caret position. + */ + SelectAllAction() { + super(selectAllAction); + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + Document doc = target.getDocument(); + target.setCaretPosition(0); + target.moveCaretPosition(doc.getLength()); + } + } + + } + + /* + * Remove the selection, if any. + * @see DefaultEditorKit#unselectAction + * @see DefaultEditorKit#getActions + */ + static class UnselectAction extends TextAction { + + /** + * Create this action with the appropriate identifier. + */ + UnselectAction() { + super(unselectAction); + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + target.setCaretPosition(target.getCaretPosition()); + } + } + + } + + /* + * Toggles the ComponentOrientation of the text component. + * @see DefaultEditorKit#toggleComponentOrientationAction + * @see DefaultEditorKit#getActions + */ + static class ToggleComponentOrientationAction extends TextAction { + + /** + * Create this action with the appropriate identifier. + */ + ToggleComponentOrientationAction() { + super(toggleComponentOrientationAction); + } + + /** The operation to perform when this action is triggered. */ + public void actionPerformed(ActionEvent e) { + JTextComponent target = getTextComponent(e); + if (target != null) { + ComponentOrientation last = target.getComponentOrientation(); + ComponentOrientation next; + if( last == ComponentOrientation.RIGHT_TO_LEFT ) + next = ComponentOrientation.LEFT_TO_RIGHT; + else + next = ComponentOrientation.RIGHT_TO_LEFT; + target.setComponentOrientation(next); + target.repaint(); + } + } + } + +}