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