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