Save This Page
Home » openjdk-7 » javax » swing » text » [javadoc | source]
    1   /*
    2    * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   package javax.swing.text;
   26   
   27   import java.lang.reflect.Method;
   28   
   29   import java.security.AccessController;
   30   import java.security.PrivilegedAction;
   31   
   32   import java.beans.Transient;
   33   import java.util.Collections;
   34   import java.util.HashMap;
   35   import java.util.Hashtable;
   36   import java.util.Enumeration;
   37   import java.util.Vector;
   38   import java.util.Iterator;
   39   import java.util.Map;
   40   import java.util.Map.Entry;
   41   import java.util.Set;
   42   
   43   import java.util.concurrent;
   44   
   45   import java.io;
   46   
   47   import java.awt;
   48   import java.awt.event;
   49   import java.awt.print;
   50   import java.awt.datatransfer;
   51   import java.awt.im.InputContext;
   52   import java.awt.im.InputMethodRequests;
   53   import java.awt.font.TextHitInfo;
   54   import java.awt.font.TextAttribute;
   55   
   56   import java.awt.print.Printable;
   57   import java.awt.print.PrinterException;
   58   
   59   import javax.print.PrintService;
   60   import javax.print.attribute.PrintRequestAttributeSet;
   61   
   62   import java.text;
   63   import java.text.AttributedCharacterIterator.Attribute;
   64   
   65   import javax.swing;
   66   import javax.swing.event;
   67   import javax.swing.plaf;
   68   
   69   import javax.accessibility;
   70   
   71   import javax.print.attribute;
   72   
   73   import sun.awt.AppContext;
   74   
   75   
   76   import sun.swing.PrintingStatus;
   77   import sun.swing.SwingUtilities2;
   78   import sun.swing.text.TextComponentPrintable;
   79   
   80   /**
   81    * <code>JTextComponent</code> is the base class for swing text
   82    * components.  It tries to be compatible with the
   83    * <code>java.awt.TextComponent</code> class
   84    * where it can reasonably do so.  Also provided are other services
   85    * for additional flexibility (beyond the pluggable UI and bean
   86    * support).
   87    * You can find information on how to use the functionality
   88    * this class provides in
   89    * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/generaltext.html">General Rules for Using Text Components</a>,
   90    * a section in <em>The Java Tutorial.</em>
   91    *
   92    * <p>
   93    * <dl>
   94    * <dt><b><font size=+1>Caret Changes</font></b>
   95    * <dd>
   96    * The caret is a pluggable object in swing text components.
   97    * Notification of changes to the caret position and the selection
   98    * are sent to implementations of the <code>CaretListener</code>
   99    * interface that have been registered with the text component.
  100    * The UI will install a default caret unless a customized caret
  101    * has been set. <br>
  102    * By default the caret tracks all the document changes
  103    * performed on the Event Dispatching Thread and updates it's position
  104    * accordingly if an insertion occurs before or at the caret position
  105    * or a removal occurs before the caret position. <code>DefaultCaret</code>
  106    * tries to make itself visible which may lead to scrolling
  107    * of a text component within <code>JScrollPane</code>. The default caret
  108    * behavior can be changed by the {@link DefaultCaret#setUpdatePolicy} method.
  109    * <br>
  110    * <b>Note</b>: Non-editable text components also have a caret though
  111    * it may not be painted.
  112    *
  113    * <p>
  114    * <dt><b><font size=+1>Commands</font></b>
  115    * <dd>
  116    * Text components provide a number of commands that can be used
  117    * to manipulate the component.  This is essentially the way that
  118    * the component expresses its capabilities.  These are expressed
  119    * in terms of the swing <code>Action</code> interface,
  120    * using the <code>TextAction</code> implementation.
  121    * The set of commands supported by the text component can be
  122    * found with the {@link #getActions} method.  These actions
  123    * can be bound to key events, fired from buttons, etc.
  124    *
  125    * <p>
  126    * <dt><b><font size=+1>Text Input</font></b>
  127    * <dd>
  128    * The text components support flexible and internationalized text input, using
  129    * keymaps and the input method framework, while maintaining compatibility with
  130    * the AWT listener model.
  131    * <p>
  132    * A {@link javax.swing.text.Keymap} lets an application bind key
  133    * strokes to actions.
  134    * In order to allow keymaps to be shared across multiple text components, they
  135    * can use actions that extend <code>TextAction</code>.
  136    * <code>TextAction</code> can determine which <code>JTextComponent</code>
  137    * most recently has or had focus and therefore is the subject of
  138    * the action (In the case that the <code>ActionEvent</code>
  139    * sent to the action doesn't contain the target text component as its source).
  140    * <p>
  141    * The <a href="../../../../technotes/guides/imf/spec.html">input method framework</a>
  142    * lets text components interact with input methods, separate software
  143    * components that preprocess events to let users enter thousands of
  144    * different characters using keyboards with far fewer keys.
  145    * <code>JTextComponent</code> is an <em>active client</em> of
  146    * the framework, so it implements the preferred user interface for interacting
  147    * with input methods. As a consequence, some key events do not reach the text
  148    * component because they are handled by an input method, and some text input
  149    * reaches the text component as committed text within an {@link
  150    * java.awt.event.InputMethodEvent} instead of as a key event.
  151    * The complete text input is the combination of the characters in
  152    * <code>keyTyped</code> key events and committed text in input method events.
  153    * <p>
  154    * The AWT listener model lets applications attach event listeners to
  155    * components in order to bind events to actions. Swing encourages the
  156    * use of keymaps instead of listeners, but maintains compatibility
  157    * with listeners by giving the listeners a chance to steal an event
  158    * by consuming it.
  159    * <p>
  160    * Keyboard event and input method events are handled in the following stages,
  161    * with each stage capable of consuming the event:
  162    *
  163    * <table border=1 summary="Stages of keyboard and input method event handling">
  164    * <tr>
  165    * <th id="stage"><p align="left">Stage</p></th>
  166    * <th id="ke"><p align="left">KeyEvent</p></th>
  167    * <th id="ime"><p align="left">InputMethodEvent</p></th></tr>
  168    * <tr><td headers="stage">1.   </td>
  169    *     <td headers="ke">input methods </td>
  170    *     <td headers="ime">(generated here)</td></tr>
  171    * <tr><td headers="stage">2.   </td>
  172    *     <td headers="ke">focus manager </td>
  173    *     <td headers="ime"></td>
  174    * </tr>
  175    * <tr>
  176    *     <td headers="stage">3.   </td>
  177    *     <td headers="ke">registered key listeners</td>
  178    *     <td headers="ime">registered input method listeners</tr>
  179    * <tr>
  180    *     <td headers="stage">4.   </td>
  181    *     <td headers="ke"></td>
  182    *     <td headers="ime">input method handling in JTextComponent</tr>
  183    * <tr>
  184    *     <td headers="stage">5.   </td><td headers="ke ime" colspan=2>keymap handling using the current keymap</td></tr>
  185    * <tr><td headers="stage">6.   </td><td headers="ke">keyboard handling in JComponent (e.g. accelerators, component navigation, etc.)</td>
  186    *     <td headers="ime"></td></tr>
  187    * </table>
  188    *
  189    * <p>
  190    * To maintain compatibility with applications that listen to key
  191    * events but are not aware of input method events, the input
  192    * method handling in stage 4 provides a compatibility mode for
  193    * components that do not process input method events. For these
  194    * components, the committed text is converted to keyTyped key events
  195    * and processed in the key event pipeline starting at stage 3
  196    * instead of in the input method event pipeline.
  197    * <p>
  198    * By default the component will create a keymap (named <b>DEFAULT_KEYMAP</b>)
  199    * that is shared by all JTextComponent instances as the default keymap.
  200    * Typically a look-and-feel implementation will install a different keymap
  201    * that resolves to the default keymap for those bindings not found in the
  202    * different keymap. The minimal bindings include:
  203    * <ul>
  204    * <li>inserting content into the editor for the
  205    *  printable keys.
  206    * <li>removing content with the backspace and del
  207    *  keys.
  208    * <li>caret movement forward and backward
  209    * </ul>
  210    *
  211    * <p>
  212    * <dt><b><font size=+1>Model/View Split</font></b>
  213    * <dd>
  214    * The text components have a model-view split.  A text component pulls
  215    * together the objects used to represent the model, view, and controller.
  216    * The text document model may be shared by other views which act as observers
  217    * of the model (e.g. a document may be shared by multiple components).
  218    *
  219    * <p align=center><img src="doc-files/editor.gif" alt="Diagram showing interaction between Controller, Document, events, and ViewFactory"
  220    *                  HEIGHT=358 WIDTH=587></p>
  221    *
  222    * <p>
  223    * The model is defined by the {@link Document} interface.
  224    * This is intended to provide a flexible text storage mechanism
  225    * that tracks change during edits and can be extended to more sophisticated
  226    * models.  The model interfaces are meant to capture the capabilities of
  227    * expression given by SGML, a system used to express a wide variety of
  228    * content.
  229    * Each modification to the document causes notification of the
  230    * details of the change to be sent to all observers in the form of a
  231    * {@link DocumentEvent} which allows the views to stay up to date with the model.
  232    * This event is sent to observers that have implemented the
  233    * {@link DocumentListener}
  234    * interface and registered interest with the model being observed.
  235    *
  236    * <p>
  237    * <dt><b><font size=+1>Location Information</font></b>
  238    * <dd>
  239    * The capability of determining the location of text in
  240    * the view is provided.  There are two methods, {@link #modelToView}
  241    * and {@link #viewToModel} for determining this information.
  242    *
  243    * <p>
  244    * <dt><b><font size=+1>Undo/Redo support</font></b>
  245    * <dd>
  246    * Support for an edit history mechanism is provided to allow
  247    * undo/redo operations.  The text component does not itself
  248    * provide the history buffer by default, but does provide
  249    * the <code>UndoableEdit</code> records that can be used in conjunction
  250    * with a history buffer to provide the undo/redo support.
  251    * The support is provided by the Document model, which allows
  252    * one to attach UndoableEditListener implementations.
  253    *
  254    * <p>
  255    * <dt><b><font size=+1>Thread Safety</font></b>
  256    * <dd>
  257    * The swing text components provide some support of thread
  258    * safe operations.  Because of the high level of configurability
  259    * of the text components, it is possible to circumvent the
  260    * protection provided.  The protection primarily comes from
  261    * the model, so the documentation of <code>AbstractDocument</code>
  262    * describes the assumptions of the protection provided.
  263    * The methods that are safe to call asynchronously are marked
  264    * with comments.
  265    *
  266    * <p>
  267    * <dt><b><font size=+1>Newlines</font></b>
  268    * <dd>
  269    * For a discussion on how newlines are handled, see
  270    * <a href="DefaultEditorKit.html">DefaultEditorKit</a>.
  271    *
  272    * <p>
  273    * <dt><b><font size=+1>Printing support</font></b>
  274    * <dd>
  275    * Several {@link #print print} methods are provided for basic
  276    * document printing.  If more advanced printing is needed, use the
  277    * {@link #getPrintable} method.
  278    * </dl>
  279    *
  280    * <p>
  281    * <strong>Warning:</strong>
  282    * Serialized objects of this class will not be compatible with
  283    * future Swing releases. The current serialization support is
  284    * appropriate for short term storage or RMI between applications running
  285    * the same version of Swing.  As of 1.4, support for long term storage
  286    * of all JavaBeans<sup><font size="-2">TM</font></sup>
  287    * has been added to the <code>java.beans</code> package.
  288    * Please see {@link java.beans.XMLEncoder}.
  289    *
  290    * @beaninfo
  291    *     attribute: isContainer false
  292    *
  293    * @author  Timothy Prinzing
  294    * @author Igor Kushnirskiy (printing support)
  295    * @see Document
  296    * @see DocumentEvent
  297    * @see DocumentListener
  298    * @see Caret
  299    * @see CaretEvent
  300    * @see CaretListener
  301    * @see TextUI
  302    * @see View
  303    * @see ViewFactory
  304    */
  305   public abstract class JTextComponent extends JComponent implements Scrollable, Accessible
  306   {
  307       /**
  308        * Creates a new <code>JTextComponent</code>.
  309        * Listeners for caret events are established, and the pluggable
  310        * UI installed.  The component is marked as editable.  No layout manager
  311        * is used, because layout is managed by the view subsystem of text.
  312        * The document model is set to <code>null</code>.
  313        */
  314       public JTextComponent() {
  315           super();
  316           // enable InputMethodEvent for on-the-spot pre-editing
  317           enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.INPUT_METHOD_EVENT_MASK);
  318           caretEvent = new MutableCaretEvent(this);
  319           addMouseListener(caretEvent);
  320           addFocusListener(caretEvent);
  321           setEditable(true);
  322           setDragEnabled(false);
  323           setLayout(null); // layout is managed by View hierarchy
  324           updateUI();
  325       }
  326   
  327       /**
  328        * Fetches the user-interface factory for this text-oriented editor.
  329        *
  330        * @return the factory
  331        */
  332       public TextUI getUI() { return (TextUI)ui; }
  333   
  334       /**
  335        * Sets the user-interface factory for this text-oriented editor.
  336        *
  337        * @param ui the factory
  338        */
  339       public void setUI(TextUI ui) {
  340           super.setUI(ui);
  341       }
  342   
  343       /**
  344        * Reloads the pluggable UI.  The key used to fetch the
  345        * new interface is <code>getUIClassID()</code>.  The type of
  346        * the UI is <code>TextUI</code>.  <code>invalidate</code>
  347        * is called after setting the UI.
  348        */
  349       public void updateUI() {
  350           setUI((TextUI)UIManager.getUI(this));
  351           invalidate();
  352       }
  353   
  354       /**
  355        * Adds a caret listener for notification of any changes
  356        * to the caret.
  357        *
  358        * @param listener the listener to be added
  359        * @see javax.swing.event.CaretEvent
  360        */
  361       public void addCaretListener(CaretListener listener) {
  362           listenerList.add(CaretListener.class, listener);
  363       }
  364   
  365       /**
  366        * Removes a caret listener.
  367        *
  368        * @param listener the listener to be removed
  369        * @see javax.swing.event.CaretEvent
  370        */
  371       public void removeCaretListener(CaretListener listener) {
  372           listenerList.remove(CaretListener.class, listener);
  373       }
  374   
  375       /**
  376        * Returns an array of all the caret listeners
  377        * registered on this text component.
  378        *
  379        * @return all of this component's <code>CaretListener</code>s
  380        *         or an empty
  381        *         array if no caret listeners are currently registered
  382        *
  383        * @see #addCaretListener
  384        * @see #removeCaretListener
  385        *
  386        * @since 1.4
  387        */
  388       public CaretListener[] getCaretListeners() {
  389           return (CaretListener[])listenerList.getListeners(CaretListener.class);
  390       }
  391   
  392       /**
  393        * Notifies all listeners that have registered interest for
  394        * notification on this event type.  The event instance
  395        * is lazily created using the parameters passed into
  396        * the fire method.  The listener list is processed in a
  397        * last-to-first manner.
  398        *
  399        * @param e the event
  400        * @see EventListenerList
  401        */
  402       protected void fireCaretUpdate(CaretEvent e) {
  403           // Guaranteed to return a non-null array
  404           Object[] listeners = listenerList.getListenerList();
  405           // Process the listeners last to first, notifying
  406           // those that are interested in this event
  407           for (int i = listeners.length-2; i>=0; i-=2) {
  408               if (listeners[i]==CaretListener.class) {
  409                   ((CaretListener)listeners[i+1]).caretUpdate(e);
  410               }
  411           }
  412       }
  413   
  414       /**
  415        * Associates the editor with a text document.
  416        * The currently registered factory is used to build a view for
  417        * the document, which gets displayed by the editor after revalidation.
  418        * A PropertyChange event ("document") is propagated to each listener.
  419        *
  420        * @param doc  the document to display/edit
  421        * @see #getDocument
  422        * @beaninfo
  423        *  description: the text document model
  424        *        bound: true
  425        *       expert: true
  426        */
  427       public void setDocument(Document doc) {
  428           Document old = model;
  429   
  430           /*
  431            * aquire a read lock on the old model to prevent notification of
  432            * mutations while we disconnecting the old model.
  433            */
  434           try {
  435               if (old instanceof AbstractDocument) {
  436                   ((AbstractDocument)old).readLock();
  437               }
  438               if (accessibleContext != null) {
  439                   model.removeDocumentListener(
  440                       ((AccessibleJTextComponent)accessibleContext));
  441               }
  442               if (inputMethodRequestsHandler != null) {
  443                   model.removeDocumentListener((DocumentListener)inputMethodRequestsHandler);
  444               }
  445               model = doc;
  446   
  447               // Set the document's run direction property to match the
  448               // component's ComponentOrientation property.
  449               Boolean runDir = getComponentOrientation().isLeftToRight()
  450                                ? TextAttribute.RUN_DIRECTION_LTR
  451                                : TextAttribute.RUN_DIRECTION_RTL;
  452               if (runDir != doc.getProperty(TextAttribute.RUN_DIRECTION)) {
  453                   doc.putProperty(TextAttribute.RUN_DIRECTION, runDir );
  454               }
  455               firePropertyChange("document", old, doc);
  456           } finally {
  457               if (old instanceof AbstractDocument) {
  458                   ((AbstractDocument)old).readUnlock();
  459               }
  460           }
  461   
  462           revalidate();
  463           repaint();
  464           if (accessibleContext != null) {
  465               model.addDocumentListener(
  466                   ((AccessibleJTextComponent)accessibleContext));
  467           }
  468           if (inputMethodRequestsHandler != null) {
  469               model.addDocumentListener((DocumentListener)inputMethodRequestsHandler);
  470           }
  471       }
  472   
  473       /**
  474        * Fetches the model associated with the editor.  This is
  475        * primarily for the UI to get at the minimal amount of
  476        * state required to be a text editor.  Subclasses will
  477        * return the actual type of the model which will typically
  478        * be something that extends Document.
  479        *
  480        * @return the model
  481        */
  482       public Document getDocument() {
  483           return model;
  484       }
  485   
  486       // Override of Component.setComponentOrientation
  487       public void setComponentOrientation( ComponentOrientation o ) {
  488           // Set the document's run direction property to match the
  489           // ComponentOrientation property.
  490           Document doc = getDocument();
  491           if( doc !=  null ) {
  492               Boolean runDir = o.isLeftToRight()
  493                                ? TextAttribute.RUN_DIRECTION_LTR
  494                                : TextAttribute.RUN_DIRECTION_RTL;
  495               doc.putProperty( TextAttribute.RUN_DIRECTION, runDir );
  496           }
  497           super.setComponentOrientation( o );
  498       }
  499   
  500       /**
  501        * Fetches the command list for the editor.  This is
  502        * the list of commands supported by the plugged-in UI
  503        * augmented by the collection of commands that the
  504        * editor itself supports.  These are useful for binding
  505        * to events, such as in a keymap.
  506        *
  507        * @return the command list
  508        */
  509       public Action[] getActions() {
  510           return getUI().getEditorKit(this).getActions();
  511       }
  512   
  513       /**
  514        * Sets margin space between the text component's border
  515        * and its text.  The text component's default <code>Border</code>
  516        * object will use this value to create the proper margin.
  517        * However, if a non-default border is set on the text component,
  518        * it is that <code>Border</code> object's responsibility to create the
  519        * appropriate margin space (else this property will effectively
  520        * be ignored).  This causes a redraw of the component.
  521        * A PropertyChange event ("margin") is sent to all listeners.
  522        *
  523        * @param m the space between the border and the text
  524        * @beaninfo
  525        *  description: desired space between the border and text area
  526        *        bound: true
  527        */
  528       public void setMargin(Insets m) {
  529           Insets old = margin;
  530           margin = m;
  531           firePropertyChange("margin", old, m);
  532           invalidate();
  533       }
  534   
  535       /**
  536        * Returns the margin between the text component's border and
  537        * its text.
  538        *
  539        * @return the margin
  540        */
  541       public Insets getMargin() {
  542           return margin;
  543       }
  544   
  545       /**
  546        * Sets the <code>NavigationFilter</code>. <code>NavigationFilter</code>
  547        * is used by <code>DefaultCaret</code> and the default cursor movement
  548        * actions as a way to restrict the cursor movement.
  549        *
  550        * @since 1.4
  551        */
  552       public void setNavigationFilter(NavigationFilter filter) {
  553           navigationFilter = filter;
  554       }
  555   
  556       /**
  557        * Returns the <code>NavigationFilter</code>. <code>NavigationFilter</code>
  558        * is used by <code>DefaultCaret</code> and the default cursor movement
  559        * actions as a way to restrict the cursor movement. A null return value
  560        * implies the cursor movement and selection should not be restricted.
  561        *
  562        * @since 1.4
  563        * @return the NavigationFilter
  564        */
  565       public NavigationFilter getNavigationFilter() {
  566           return navigationFilter;
  567       }
  568   
  569       /**
  570        * Fetches the caret that allows text-oriented navigation over
  571        * the view.
  572        *
  573        * @return the caret
  574        */
  575       @Transient
  576       public Caret getCaret() {
  577           return caret;
  578       }
  579   
  580       /**
  581        * Sets the caret to be used.  By default this will be set
  582        * by the UI that gets installed.  This can be changed to
  583        * a custom caret if desired.  Setting the caret results in a
  584        * PropertyChange event ("caret") being fired.
  585        *
  586        * @param c the caret
  587        * @see #getCaret
  588        * @beaninfo
  589        *  description: the caret used to select/navigate
  590        *        bound: true
  591        *       expert: true
  592        */
  593       public void setCaret(Caret c) {
  594           if (caret != null) {
  595               caret.removeChangeListener(caretEvent);
  596               caret.deinstall(this);
  597           }
  598           Caret old = caret;
  599           caret = c;
  600           if (caret != null) {
  601               caret.install(this);
  602               caret.addChangeListener(caretEvent);
  603           }
  604           firePropertyChange("caret", old, caret);
  605       }
  606   
  607       /**
  608        * Fetches the object responsible for making highlights.
  609        *
  610        * @return the highlighter
  611        */
  612       public Highlighter getHighlighter() {
  613           return highlighter;
  614       }
  615   
  616       /**
  617        * Sets the highlighter to be used.  By default this will be set
  618        * by the UI that gets installed.  This can be changed to
  619        * a custom highlighter if desired.  The highlighter can be set to
  620        * <code>null</code> to disable it.
  621        * A PropertyChange event ("highlighter") is fired
  622        * when a new highlighter is installed.
  623        *
  624        * @param h the highlighter
  625        * @see #getHighlighter
  626        * @beaninfo
  627        *  description: object responsible for background highlights
  628        *        bound: true
  629        *       expert: true
  630        */
  631       public void setHighlighter(Highlighter h) {
  632           if (highlighter != null) {
  633               highlighter.deinstall(this);
  634           }
  635           Highlighter old = highlighter;
  636           highlighter = h;
  637           if (highlighter != null) {
  638               highlighter.install(this);
  639           }
  640           firePropertyChange("highlighter", old, h);
  641       }
  642   
  643       /**
  644        * Sets the keymap to use for binding events to
  645        * actions.  Setting to <code>null</code> effectively disables
  646        * keyboard input.
  647        * A PropertyChange event ("keymap") is fired when a new keymap
  648        * is installed.
  649        *
  650        * @param map the keymap
  651        * @see #getKeymap
  652        * @beaninfo
  653        *  description: set of key event to action bindings to use
  654        *        bound: true
  655        */
  656       public void setKeymap(Keymap map) {
  657           Keymap old = keymap;
  658           keymap = map;
  659           firePropertyChange("keymap", old, keymap);
  660           updateInputMap(old, map);
  661       }
  662   
  663       /**
  664        * Turns on or off automatic drag handling. In order to enable automatic
  665        * drag handling, this property should be set to {@code true}, and the
  666        * component's {@code TransferHandler} needs to be {@code non-null}.
  667        * The default value of the {@code dragEnabled} property is {@code false}.
  668        * <p>
  669        * The job of honoring this property, and recognizing a user drag gesture,
  670        * lies with the look and feel implementation, and in particular, the component's
  671        * {@code TextUI}. When automatic drag handling is enabled, most look and
  672        * feels (including those that subclass {@code BasicLookAndFeel}) begin a
  673        * drag and drop operation whenever the user presses the mouse button over
  674        * a selection and then moves the mouse a few pixels. Setting this property to
  675        * {@code true} can therefore have a subtle effect on how selections behave.
  676        * <p>
  677        * If a look and feel is used that ignores this property, you can still
  678        * begin a drag and drop operation by calling {@code exportAsDrag} on the
  679        * component's {@code TransferHandler}.
  680        *
  681        * @param b whether or not to enable automatic drag handling
  682        * @exception HeadlessException if
  683        *            <code>b</code> is <code>true</code> and
  684        *            <code>GraphicsEnvironment.isHeadless()</code>
  685        *            returns <code>true</code>
  686        * @see java.awt.GraphicsEnvironment#isHeadless
  687        * @see #getDragEnabled
  688        * @see #setTransferHandler
  689        * @see TransferHandler
  690        * @since 1.4
  691        *
  692        * @beaninfo
  693        *  description: determines whether automatic drag handling is enabled
  694        *        bound: false
  695        */
  696       public void setDragEnabled(boolean b) {
  697           if (b && GraphicsEnvironment.isHeadless()) {
  698               throw new HeadlessException();
  699           }
  700           dragEnabled = b;
  701       }
  702   
  703       /**
  704        * Returns whether or not automatic drag handling is enabled.
  705        *
  706        * @return the value of the {@code dragEnabled} property
  707        * @see #setDragEnabled
  708        * @since 1.4
  709        */
  710       public boolean getDragEnabled() {
  711           return dragEnabled;
  712       }
  713   
  714       /**
  715        * Sets the drop mode for this component. For backward compatibility,
  716        * the default for this property is <code>DropMode.USE_SELECTION</code>.
  717        * Usage of <code>DropMode.INSERT</code> is recommended, however,
  718        * for an improved user experience. It offers similar behavior of dropping
  719        * between text locations, but does so without affecting the actual text
  720        * selection and caret location.
  721        * <p>
  722        * <code>JTextComponents</code> support the following drop modes:
  723        * <ul>
  724        *    <li><code>DropMode.USE_SELECTION</code></li>
  725        *    <li><code>DropMode.INSERT</code></li>
  726        * </ul>
  727        * <p>
  728        * The drop mode is only meaningful if this component has a
  729        * <code>TransferHandler</code> that accepts drops.
  730        *
  731        * @param dropMode the drop mode to use
  732        * @throws IllegalArgumentException if the drop mode is unsupported
  733        *         or <code>null</code>
  734        * @see #getDropMode
  735        * @see #getDropLocation
  736        * @see #setTransferHandler
  737        * @see javax.swing.TransferHandler
  738        * @since 1.6
  739        */
  740       public final void setDropMode(DropMode dropMode) {
  741           if (dropMode != null) {
  742               switch (dropMode) {
  743                   case USE_SELECTION:
  744                   case INSERT:
  745                       this.dropMode = dropMode;
  746                       return;
  747               }
  748           }
  749   
  750           throw new IllegalArgumentException(dropMode + ": Unsupported drop mode for text");
  751       }
  752   
  753       /**
  754        * Returns the drop mode for this component.
  755        *
  756        * @return the drop mode for this component
  757        * @see #setDropMode
  758        * @since 1.6
  759        */
  760       public final DropMode getDropMode() {
  761           return dropMode;
  762       }
  763   
  764   
  765       /**
  766        * Calculates a drop location in this component, representing where a
  767        * drop at the given point should insert data.
  768        * <p>
  769        * Note: This method is meant to override
  770        * <code>JComponent.dropLocationForPoint()</code>, which is package-private
  771        * in javax.swing. <code>TransferHandler</code> will detect text components
  772        * and call this method instead via reflection. It's name should therefore
  773        * not be changed.
  774        *
  775        * @param p the point to calculate a drop location for
  776        * @return the drop location, or <code>null</code>
  777        */
  778       DropLocation dropLocationForPoint(Point p) {
  779           Position.Bias[] bias = new Position.Bias[1];
  780           int index = getUI().viewToModel(this, p, bias);
  781   
  782           // viewToModel currently returns null for some HTML content
  783           // when the point is within the component's top inset
  784           if (bias[0] == null) {
  785               bias[0] = Position.Bias.Forward;
  786           }
  787   
  788           return new DropLocation(p, index, bias[0]);
  789       }
  790   
  791       /**
  792        * Called to set or clear the drop location during a DnD operation.
  793        * In some cases, the component may need to use it's internal selection
  794        * temporarily to indicate the drop location. To help facilitate this,
  795        * this method returns and accepts as a parameter a state object.
  796        * This state object can be used to store, and later restore, the selection
  797        * state. Whatever this method returns will be passed back to it in
  798        * future calls, as the state parameter. If it wants the DnD system to
  799        * continue storing the same state, it must pass it back every time.
  800        * Here's how this is used:
  801        * <p>
  802        * Let's say that on the first call to this method the component decides
  803        * to save some state (because it is about to use the selection to show
  804        * a drop index). It can return a state object to the caller encapsulating
  805        * any saved selection state. On a second call, let's say the drop location
  806        * is being changed to something else. The component doesn't need to
  807        * restore anything yet, so it simply passes back the same state object
  808        * to have the DnD system continue storing it. Finally, let's say this
  809        * method is messaged with <code>null</code>. This means DnD
  810        * is finished with this component for now, meaning it should restore
  811        * state. At this point, it can use the state parameter to restore
  812        * said state, and of course return <code>null</code> since there's
  813        * no longer anything to store.
  814        * <p>
  815        * Note: This method is meant to override
  816        * <code>JComponent.setDropLocation()</code>, which is package-private
  817        * in javax.swing. <code>TransferHandler</code> will detect text components
  818        * and call this method instead via reflection. It's name should therefore
  819        * not be changed.
  820        *
  821        * @param location the drop location (as calculated by
  822        *        <code>dropLocationForPoint</code>) or <code>null</code>
  823        *        if there's no longer a valid drop location
  824        * @param state the state object saved earlier for this component,
  825        *        or <code>null</code>
  826        * @param forDrop whether or not the method is being called because an
  827        *        actual drop occurred
  828        * @return any saved state for this component, or <code>null</code> if none
  829        */
  830       Object setDropLocation(TransferHandler.DropLocation location,
  831                              Object state,
  832                              boolean forDrop) {
  833   
  834           Object retVal = null;
  835           DropLocation textLocation = (DropLocation)location;
  836   
  837           if (dropMode == DropMode.USE_SELECTION) {
  838               if (textLocation == null) {
  839                   if (state != null) {
  840                       /*
  841                        * This object represents the state saved earlier.
  842                        *     If the caret is a DefaultCaret it will be
  843                        *     an Object array containing, in order:
  844                        *         - the saved caret mark (Integer)
  845                        *         - the saved caret dot (Integer)
  846                        *         - the saved caret visibility (Boolean)
  847                        *         - the saved mark bias (Position.Bias)
  848                        *         - the saved dot bias (Position.Bias)
  849                        *     If the caret is not a DefaultCaret it will
  850                        *     be similar, but will not contain the dot
  851                        *     or mark bias.
  852                        */
  853                       Object[] vals = (Object[])state;
  854   
  855                       if (!forDrop) {
  856                           if (caret instanceof DefaultCaret) {
  857                               ((DefaultCaret)caret).setDot(((Integer)vals[0]).intValue(),
  858                                                            (Position.Bias)vals[3]);
  859                               ((DefaultCaret)caret).moveDot(((Integer)vals[1]).intValue(),
  860                                                            (Position.Bias)vals[4]);
  861                           } else {
  862                               caret.setDot(((Integer)vals[0]).intValue());
  863                               caret.moveDot(((Integer)vals[1]).intValue());
  864                           }
  865                       }
  866   
  867                       caret.setVisible(((Boolean)vals[2]).booleanValue());
  868                   }
  869               } else {
  870                   if (dropLocation == null) {
  871                       boolean visible;
  872   
  873                       if (caret instanceof DefaultCaret) {
  874                           DefaultCaret dc = (DefaultCaret)caret;
  875                           visible = dc.isActive();
  876                           retVal = new Object[] {Integer.valueOf(dc.getMark()),
  877                                                  Integer.valueOf(dc.getDot()),
  878                                                  Boolean.valueOf(visible),
  879                                                  dc.getMarkBias(),
  880                                                  dc.getDotBias()};
  881                       } else {
  882                           visible = caret.isVisible();
  883                           retVal = new Object[] {Integer.valueOf(caret.getMark()),
  884                                                  Integer.valueOf(caret.getDot()),
  885                                                  Boolean.valueOf(visible)};
  886                       }
  887   
  888                       caret.setVisible(true);
  889                   } else {
  890                       retVal = state;
  891                   }
  892   
  893                   if (caret instanceof DefaultCaret) {
  894                       ((DefaultCaret)caret).setDot(textLocation.getIndex(), textLocation.getBias());
  895                   } else {
  896                       caret.setDot(textLocation.getIndex());
  897                   }
  898               }
  899           } else {
  900               if (textLocation == null) {
  901                   if (state != null) {
  902                       caret.setVisible(((Boolean)state).booleanValue());
  903                   }
  904               } else {
  905                   if (dropLocation == null) {
  906                       boolean visible = caret instanceof DefaultCaret
  907                                         ? ((DefaultCaret)caret).isActive()
  908                                         : caret.isVisible();
  909                       retVal = Boolean.valueOf(visible);
  910                       caret.setVisible(false);
  911                   } else {
  912                       retVal = state;
  913                   }
  914               }
  915           }
  916   
  917           DropLocation old = dropLocation;
  918           dropLocation = textLocation;
  919           firePropertyChange("dropLocation", old, dropLocation);
  920   
  921           return retVal;
  922       }
  923   
  924       /**
  925        * Returns the location that this component should visually indicate
  926        * as the drop location during a DnD operation over the component,
  927        * or {@code null} if no location is to currently be shown.
  928        * <p>
  929        * This method is not meant for querying the drop location
  930        * from a {@code TransferHandler}, as the drop location is only
  931        * set after the {@code TransferHandler}'s <code>canImport</code>
  932        * has returned and has allowed for the location to be shown.
  933        * <p>
  934        * When this property changes, a property change event with
  935        * name "dropLocation" is fired by the component.
  936        *
  937        * @return the drop location
  938        * @see #setDropMode
  939        * @see TransferHandler#canImport(TransferHandler.TransferSupport)
  940        * @since 1.6
  941        */
  942       public final DropLocation getDropLocation() {
  943           return dropLocation;
  944       }
  945   
  946   
  947       /**
  948        * Updates the <code>InputMap</code>s in response to a
  949        * <code>Keymap</code> change.
  950        * @param oldKm  the old <code>Keymap</code>
  951        * @param newKm  the new <code>Keymap</code>
  952        */
  953       void updateInputMap(Keymap oldKm, Keymap newKm) {
  954           // Locate the current KeymapWrapper.
  955           InputMap km = getInputMap(JComponent.WHEN_FOCUSED);
  956           InputMap last = km;
  957           while (km != null && !(km instanceof KeymapWrapper)) {
  958               last = km;
  959               km = km.getParent();
  960           }
  961           if (km != null) {
  962               // Found it, tweak the InputMap that points to it, as well
  963               // as anything it points to.
  964               if (newKm == null) {
  965                   if (last != km) {
  966                       last.setParent(km.getParent());
  967                   }
  968                   else {
  969                       last.setParent(null);
  970                   }
  971               }
  972               else {
  973                   InputMap newKM = new KeymapWrapper(newKm);
  974                   last.setParent(newKM);
  975                   if (last != km) {
  976                       newKM.setParent(km.getParent());
  977                   }
  978               }
  979           }
  980           else if (newKm != null) {
  981               km = getInputMap(JComponent.WHEN_FOCUSED);
  982               if (km != null) {
  983                   // Couldn't find it.
  984                   // Set the parent of WHEN_FOCUSED InputMap to be the new one.
  985                   InputMap newKM = new KeymapWrapper(newKm);
  986                   newKM.setParent(km.getParent());
  987                   km.setParent(newKM);
  988               }
  989           }
  990   
  991           // Do the same thing with the ActionMap
  992           ActionMap am = getActionMap();
  993           ActionMap lastAM = am;
  994           while (am != null && !(am instanceof KeymapActionMap)) {
  995               lastAM = am;
  996               am = am.getParent();
  997           }
  998           if (am != null) {
  999               // Found it, tweak the Actionap that points to it, as well
 1000               // as anything it points to.
 1001               if (newKm == null) {
 1002                   if (lastAM != am) {
 1003                       lastAM.setParent(am.getParent());
 1004                   }
 1005                   else {
 1006                       lastAM.setParent(null);
 1007                   }
 1008               }
 1009               else {
 1010                   ActionMap newAM = new KeymapActionMap(newKm);
 1011                   lastAM.setParent(newAM);
 1012                   if (lastAM != am) {
 1013                       newAM.setParent(am.getParent());
 1014                   }
 1015               }
 1016           }
 1017           else if (newKm != null) {
 1018               am = getActionMap();
 1019               if (am != null) {
 1020                   // Couldn't find it.
 1021                   // Set the parent of ActionMap to be the new one.
 1022                   ActionMap newAM = new KeymapActionMap(newKm);
 1023                   newAM.setParent(am.getParent());
 1024                   am.setParent(newAM);
 1025               }
 1026           }
 1027       }
 1028   
 1029       /**
 1030        * Fetches the keymap currently active in this text
 1031        * component.
 1032        *
 1033        * @return the keymap
 1034        */
 1035       public Keymap getKeymap() {
 1036           return keymap;
 1037       }
 1038   
 1039       /**
 1040        * Adds a new keymap into the keymap hierarchy.  Keymap bindings
 1041        * resolve from bottom up so an attribute specified in a child
 1042        * will override an attribute specified in the parent.
 1043        *
 1044        * @param nm   the name of the keymap (must be unique within the
 1045        *   collection of named keymaps in the document); the name may
 1046        *   be <code>null</code> if the keymap is unnamed,
 1047        *   but the caller is responsible for managing the reference
 1048        *   returned as an unnamed keymap can't
 1049        *   be fetched by name
 1050        * @param parent the parent keymap; this may be <code>null</code> if
 1051        *   unspecified bindings need not be resolved in some other keymap
 1052        * @return the keymap
 1053        */
 1054       public static Keymap addKeymap(String nm, Keymap parent) {
 1055           Keymap map = new DefaultKeymap(nm, parent);
 1056           if (nm != null) {
 1057               // add a named keymap, a class of bindings
 1058               getKeymapTable().put(nm, map);
 1059           }
 1060           return map;
 1061       }
 1062   
 1063       /**
 1064        * Removes a named keymap previously added to the document.  Keymaps
 1065        * with <code>null</code> names may not be removed in this way.
 1066        *
 1067        * @param nm  the name of the keymap to remove
 1068        * @return the keymap that was removed
 1069        */
 1070       public static Keymap removeKeymap(String nm) {
 1071           return getKeymapTable().remove(nm);
 1072       }
 1073   
 1074       /**
 1075        * Fetches a named keymap previously added to the document.
 1076        * This does not work with <code>null</code>-named keymaps.
 1077        *
 1078        * @param nm  the name of the keymap
 1079        * @return the keymap
 1080        */
 1081       public static Keymap getKeymap(String nm) {
 1082           return getKeymapTable().get(nm);
 1083       }
 1084   
 1085       private static HashMap<String,Keymap> getKeymapTable() {
 1086           synchronized (KEYMAP_TABLE) {
 1087               AppContext appContext = AppContext.getAppContext();
 1088               HashMap<String,Keymap> keymapTable =
 1089                   (HashMap<String,Keymap>)appContext.get(KEYMAP_TABLE);
 1090               if (keymapTable == null) {
 1091                   keymapTable = new HashMap<String,Keymap>(17);
 1092                   appContext.put(KEYMAP_TABLE, keymapTable);
 1093                   //initialize default keymap
 1094                   Keymap binding = addKeymap(DEFAULT_KEYMAP, null);
 1095                   binding.setDefaultAction(new
 1096                                            DefaultEditorKit.DefaultKeyTypedAction());
 1097               }
 1098               return keymapTable;
 1099           }
 1100       }
 1101   
 1102       /**
 1103        * Binding record for creating key bindings.
 1104        * <p>
 1105        * <strong>Warning:</strong>
 1106        * Serialized objects of this class will not be compatible with
 1107        * future Swing releases. The current serialization support is
 1108        * appropriate for short term storage or RMI between applications running
 1109        * the same version of Swing.  As of 1.4, support for long term storage
 1110        * of all JavaBeans<sup><font size="-2">TM</font></sup>
 1111        * has been added to the <code>java.beans</code> package.
 1112        * Please see {@link java.beans.XMLEncoder}.
 1113        */
 1114       public static class KeyBinding {
 1115   
 1116           /**
 1117            * The key.
 1118            */
 1119           public KeyStroke key;
 1120   
 1121           /**
 1122            * The name of the action for the key.
 1123            */
 1124           public String actionName;
 1125   
 1126           /**
 1127            * Creates a new key binding.
 1128            *
 1129            * @param key the key
 1130            * @param actionName the name of the action for the key
 1131            */
 1132           public KeyBinding(KeyStroke key, String actionName) {
 1133               this.key = key;
 1134               this.actionName = actionName;
 1135           }
 1136       }
 1137   
 1138       /**
 1139        * <p>
 1140        * Loads a keymap with a bunch of
 1141        * bindings.  This can be used to take a static table of
 1142        * definitions and load them into some keymap.  The following
 1143        * example illustrates an example of binding some keys to
 1144        * the cut, copy, and paste actions associated with a
 1145        * JTextComponent.  A code fragment to accomplish
 1146        * this might look as follows:
 1147        * <pre><code>
 1148        *
 1149        *   static final JTextComponent.KeyBinding[] defaultBindings = {
 1150        *     new JTextComponent.KeyBinding(
 1151        *       KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK),
 1152        *       DefaultEditorKit.copyAction),
 1153        *     new JTextComponent.KeyBinding(
 1154        *       KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK),
 1155        *       DefaultEditorKit.pasteAction),
 1156        *     new JTextComponent.KeyBinding(
 1157        *       KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK),
 1158        *       DefaultEditorKit.cutAction),
 1159        *   };
 1160        *
 1161        *   JTextComponent c = new JTextPane();
 1162        *   Keymap k = c.getKeymap();
 1163        *   JTextComponent.loadKeymap(k, defaultBindings, c.getActions());
 1164        *
 1165        * </code></pre>
 1166        * The sets of bindings and actions may be empty but must be
 1167        * non-<code>null</code>.
 1168        *
 1169        * @param map the keymap
 1170        * @param bindings the bindings
 1171        * @param actions the set of actions
 1172        */
 1173       public static void loadKeymap(Keymap map, KeyBinding[] bindings, Action[] actions) {
 1174           Hashtable h = new Hashtable();
 1175           for (int i = 0; i < actions.length; i++) {
 1176               Action a = actions[i];
 1177               String value = (String)a.getValue(Action.NAME);
 1178               h.put((value!=null ? value:""), a);
 1179           }
 1180           for (int i = 0; i < bindings.length; i++) {
 1181               Action a = (Action) h.get(bindings[i].actionName);
 1182               if (a != null) {
 1183                   map.addActionForKeyStroke(bindings[i].key, a);
 1184               }
 1185           }
 1186       }
 1187   
 1188       /**
 1189        * Returns true if <code>klass</code> is NOT a JTextComponent and it or
 1190        * one of its superclasses (stoping at JTextComponent) overrides
 1191        * <code>processInputMethodEvent</code>. It is assumed this will be
 1192        * invoked from within a <code>doPrivileged</code>, and it is also
 1193        * assumed <code>klass</code> extends <code>JTextComponent</code>.
 1194        */
 1195       private static Boolean isProcessInputMethodEventOverridden(Class klass) {
 1196           if (klass == JTextComponent.class) {
 1197               return Boolean.FALSE;
 1198           }
 1199           Boolean retValue = (Boolean)overrideMap.get(klass.getName());
 1200   
 1201           if (retValue != null) {
 1202               return retValue;
 1203           }
 1204           Boolean sOverriden = isProcessInputMethodEventOverridden(
 1205                                          klass.getSuperclass());
 1206   
 1207           if (sOverriden.booleanValue()) {
 1208               // If our superclass has overriden it, then by definition klass
 1209               // overrides it.
 1210               overrideMap.put(klass.getName(), sOverriden);
 1211               return sOverriden;
 1212           }
 1213           // klass's superclass didn't override it, check for an override in
 1214           // klass.
 1215           try {
 1216               Class[] classes = new Class[1];
 1217               classes[0] = InputMethodEvent.class;
 1218   
 1219               Method m = klass.getDeclaredMethod("processInputMethodEvent",
 1220                                                  classes);
 1221               retValue = Boolean.TRUE;
 1222           } catch (NoSuchMethodException nsme) {
 1223               retValue = Boolean.FALSE;
 1224           }
 1225           overrideMap.put(klass.getName(), retValue);
 1226           return retValue;
 1227       }
 1228   
 1229       /**
 1230        * Fetches the current color used to render the
 1231        * caret.
 1232        *
 1233        * @return the color
 1234        */
 1235       public Color getCaretColor() {
 1236           return caretColor;
 1237       }
 1238   
 1239       /**
 1240        * Sets the current color used to render the caret.
 1241        * Setting to <code>null</code> effectively restores the default color.
 1242        * Setting the color results in a PropertyChange event ("caretColor")
 1243        * being fired.
 1244        *
 1245        * @param c the color
 1246        * @see #getCaretColor
 1247        * @beaninfo
 1248        *  description: the color used to render the caret
 1249        *        bound: true
 1250        *    preferred: true
 1251        */
 1252       public void setCaretColor(Color c) {
 1253           Color old = caretColor;
 1254           caretColor = c;
 1255           firePropertyChange("caretColor", old, caretColor);
 1256       }
 1257   
 1258       /**
 1259        * Fetches the current color used to render the
 1260        * selection.
 1261        *
 1262        * @return the color
 1263        */
 1264       public Color getSelectionColor() {
 1265           return selectionColor;
 1266       }
 1267   
 1268       /**
 1269        * Sets the current color used to render the selection.
 1270        * Setting the color to <code>null</code> is the same as setting
 1271        * <code>Color.white</code>.  Setting the color results in a
 1272        * PropertyChange event ("selectionColor").
 1273        *
 1274        * @param c the color
 1275        * @see #getSelectionColor
 1276        * @beaninfo
 1277        *  description: color used to render selection background
 1278        *        bound: true
 1279        *    preferred: true
 1280        */
 1281       public void setSelectionColor(Color c) {
 1282           Color old = selectionColor;
 1283           selectionColor = c;
 1284           firePropertyChange("selectionColor", old, selectionColor);
 1285       }
 1286   
 1287       /**
 1288        * Fetches the current color used to render the
 1289        * selected text.
 1290        *
 1291        * @return the color
 1292        */
 1293       public Color getSelectedTextColor() {
 1294           return selectedTextColor;
 1295       }
 1296   
 1297       /**
 1298        * Sets the current color used to render the selected text.
 1299        * Setting the color to <code>null</code> is the same as
 1300        * <code>Color.black</code>. Setting the color results in a
 1301        * PropertyChange event ("selectedTextColor") being fired.
 1302        *
 1303        * @param c the color
 1304        * @see #getSelectedTextColor
 1305        * @beaninfo
 1306        *  description: color used to render selected text
 1307        *        bound: true
 1308        *    preferred: true
 1309        */
 1310       public void setSelectedTextColor(Color c) {
 1311           Color old = selectedTextColor;
 1312           selectedTextColor = c;
 1313           firePropertyChange("selectedTextColor", old, selectedTextColor);
 1314       }
 1315   
 1316       /**
 1317        * Fetches the current color used to render the
 1318        * disabled text.
 1319        *
 1320        * @return the color
 1321        */
 1322       public Color getDisabledTextColor() {
 1323           return disabledTextColor;
 1324       }
 1325   
 1326       /**
 1327        * Sets the current color used to render the
 1328        * disabled text.  Setting the color fires off a
 1329        * PropertyChange event ("disabledTextColor").
 1330        *
 1331        * @param c the color
 1332        * @see #getDisabledTextColor
 1333        * @beaninfo
 1334        *  description: color used to render disabled text
 1335        *        bound: true
 1336        *    preferred: true
 1337        */
 1338       public void setDisabledTextColor(Color c) {
 1339           Color old = disabledTextColor;
 1340           disabledTextColor = c;
 1341           firePropertyChange("disabledTextColor", old, disabledTextColor);
 1342       }
 1343   
 1344       /**
 1345        * Replaces the currently selected content with new content
 1346        * represented by the given string.  If there is no selection
 1347        * this amounts to an insert of the given text.  If there
 1348        * is no replacement text this amounts to a removal of the
 1349        * current selection.
 1350        * <p>
 1351        * This is the method that is used by the default implementation
 1352        * of the action for inserting content that gets bound to the
 1353        * keymap actions.
 1354        *
 1355        * @param content  the content to replace the selection with
 1356        */
 1357       public void replaceSelection(String content) {
 1358           Document doc = getDocument();
 1359           if (doc != null) {
 1360               try {
 1361                   boolean composedTextSaved = saveComposedText(caret.getDot());
 1362                   int p0 = Math.min(caret.getDot(), caret.getMark());
 1363                   int p1 = Math.max(caret.getDot(), caret.getMark());
 1364                   if (doc instanceof AbstractDocument) {
 1365                       ((AbstractDocument)doc).replace(p0, p1 - p0, content,null);
 1366                   }
 1367                   else {
 1368                       if (p0 != p1) {
 1369                           doc.remove(p0, p1 - p0);
 1370                       }
 1371                       if (content != null && content.length() > 0) {
 1372                           doc.insertString(p0, content, null);
 1373                       }
 1374                   }
 1375                   if (composedTextSaved) {
 1376                       restoreComposedText();
 1377                   }
 1378               } catch (BadLocationException e) {
 1379                   UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this);
 1380               }
 1381           }
 1382       }
 1383   
 1384       /**
 1385        * Fetches a portion of the text represented by the
 1386        * component.  Returns an empty string if length is 0.
 1387        *
 1388        * @param offs the offset >= 0
 1389        * @param len the length >= 0
 1390        * @return the text
 1391        * @exception BadLocationException if the offset or length are invalid
 1392        */
 1393       public String getText(int offs, int len) throws BadLocationException {
 1394           return getDocument().getText(offs, len);
 1395       }
 1396   
 1397       /**
 1398        * Converts the given location in the model to a place in
 1399        * the view coordinate system.
 1400        * The component must have a positive size for
 1401        * this translation to be computed (i.e. layout cannot
 1402        * be computed until the component has been sized).  The
 1403        * component does not have to be visible or painted.
 1404        *
 1405        * @param pos the position >= 0
 1406        * @return the coordinates as a rectangle, with (r.x, r.y) as the location
 1407        *   in the coordinate system, or null if the component does
 1408        *   not yet have a positive size.
 1409        * @exception BadLocationException if the given position does not
 1410        *   represent a valid location in the associated document
 1411        * @see TextUI#modelToView
 1412        */
 1413       public Rectangle modelToView(int pos) throws BadLocationException {
 1414           return getUI().modelToView(this, pos);
 1415       }
 1416   
 1417       /**
 1418        * Converts the given place in the view coordinate system
 1419        * to the nearest representative location in the model.
 1420        * The component must have a positive size for
 1421        * this translation to be computed (i.e. layout cannot
 1422        * be computed until the component has been sized).  The
 1423        * component does not have to be visible or painted.
 1424        *
 1425        * @param pt the location in the view to translate
 1426        * @return the offset >= 0 from the start of the document,
 1427        *   or -1 if the component does not yet have a positive
 1428        *   size.
 1429        * @see TextUI#viewToModel
 1430        */
 1431       public int viewToModel(Point pt) {
 1432           return getUI().viewToModel(this, pt);
 1433       }
 1434   
 1435       /**
 1436        * Transfers the currently selected range in the associated
 1437        * text model to the system clipboard, removing the contents
 1438        * from the model.  The current selection is reset.  Does nothing
 1439        * for <code>null</code> selections.
 1440        *
 1441        * @see java.awt.Toolkit#getSystemClipboard
 1442        * @see java.awt.datatransfer.Clipboard
 1443        */
 1444       public void cut() {
 1445           if (isEditable() && isEnabled()) {
 1446               invokeAction("cut", TransferHandler.getCutAction());
 1447           }
 1448       }
 1449   
 1450       /**
 1451        * Transfers the currently selected range in the associated
 1452        * text model to the system clipboard, leaving the contents
 1453        * in the text model.  The current selection remains intact.
 1454        * Does nothing for <code>null</code> selections.
 1455        *
 1456        * @see java.awt.Toolkit#getSystemClipboard
 1457        * @see java.awt.datatransfer.Clipboard
 1458        */
 1459       public void copy() {
 1460           invokeAction("copy", TransferHandler.getCopyAction());
 1461       }
 1462   
 1463       /**
 1464        * Transfers the contents of the system clipboard into the
 1465        * associated text model.  If there is a selection in the
 1466        * associated view, it is replaced with the contents of the
 1467        * clipboard.  If there is no selection, the clipboard contents
 1468        * are inserted in front of the current insert position in
 1469        * the associated view.  If the clipboard is empty, does nothing.
 1470        *
 1471        * @see #replaceSelection
 1472        * @see java.awt.Toolkit#getSystemClipboard
 1473        * @see java.awt.datatransfer.Clipboard
 1474        */
 1475       public void paste() {
 1476           if (isEditable() && isEnabled()) {
 1477               invokeAction("paste", TransferHandler.getPasteAction());
 1478           }
 1479       }
 1480   
 1481       /**
 1482        * This is a conveniance method that is only useful for
 1483        * <code>cut</code>, <code>copy</code> and <code>paste</code>.  If
 1484        * an <code>Action</code> with the name <code>name</code> does not
 1485        * exist in the <code>ActionMap</code>, this will attemp to install a
 1486        * <code>TransferHandler</code> and then use <code>altAction</code>.
 1487        */
 1488       private void invokeAction(String name, Action altAction) {
 1489           ActionMap map = getActionMap();
 1490           Action action = null;
 1491   
 1492           if (map != null) {
 1493               action = map.get(name);
 1494           }
 1495           if (action == null) {
 1496               installDefaultTransferHandlerIfNecessary();
 1497               action = altAction;
 1498           }
 1499           action.actionPerformed(new ActionEvent(this,
 1500                                  ActionEvent.ACTION_PERFORMED, (String)action.
 1501                                  getValue(Action.NAME),
 1502                                  EventQueue.getMostRecentEventTime(),
 1503                                  getCurrentEventModifiers()));
 1504       }
 1505   
 1506       /**
 1507        * If the current <code>TransferHandler</code> is null, this will
 1508        * install a new one.
 1509        */
 1510       private void installDefaultTransferHandlerIfNecessary() {
 1511           if (getTransferHandler() == null) {
 1512               if (defaultTransferHandler == null) {
 1513                   defaultTransferHandler = new DefaultTransferHandler();
 1514               }
 1515               setTransferHandler(defaultTransferHandler);
 1516           }
 1517       }
 1518   
 1519       /**
 1520        * Moves the caret to a new position, leaving behind a mark
 1521        * defined by the last time <code>setCaretPosition</code> was
 1522        * called.  This forms a selection.
 1523        * If the document is <code>null</code>, does nothing. The position
 1524        * must be between 0 and the length of the component's text or else
 1525        * an exception is thrown.
 1526        *
 1527        * @param pos the position
 1528        * @exception    IllegalArgumentException if the value supplied
 1529        *               for <code>position</code> is less than zero or greater
 1530        *               than the component's text length
 1531        * @see #setCaretPosition
 1532        */
 1533       public void moveCaretPosition(int pos) {
 1534           Document doc = getDocument();
 1535           if (doc != null) {
 1536               if (pos > doc.getLength() || pos < 0) {
 1537                   throw new IllegalArgumentException("bad position: " + pos);
 1538               }
 1539               caret.moveDot(pos);
 1540           }
 1541       }
 1542   
 1543       /**
 1544        * The bound property name for the focus accelerator.
 1545        */
 1546       public static final String FOCUS_ACCELERATOR_KEY = "focusAcceleratorKey";
 1547   
 1548       /**
 1549        * Sets the key accelerator that will cause the receiving text
 1550        * component to get the focus.  The accelerator will be the
 1551        * key combination of the <em>alt</em> key and the character
 1552        * given (converted to upper case).  By default, there is no focus
 1553        * accelerator key.  Any previous key accelerator setting will be
 1554        * superseded.  A '\0' key setting will be registered, and has the
 1555        * effect of turning off the focus accelerator.  When the new key
 1556        * is set, a PropertyChange event (FOCUS_ACCELERATOR_KEY) will be fired.
 1557        *
 1558        * @param aKey the key
 1559        * @see #getFocusAccelerator
 1560        * @beaninfo
 1561        *  description: accelerator character used to grab focus
 1562        *        bound: true
 1563        */
 1564       public void setFocusAccelerator(char aKey) {
 1565           aKey = Character.toUpperCase(aKey);
 1566           char old = focusAccelerator;
 1567           focusAccelerator = aKey;
 1568           // Fix for 4341002: value of FOCUS_ACCELERATOR_KEY is wrong.
 1569           // So we fire both FOCUS_ACCELERATOR_KEY, for compatibility,
 1570           // and the correct event here.
 1571           firePropertyChange(FOCUS_ACCELERATOR_KEY, old, focusAccelerator);
 1572           firePropertyChange("focusAccelerator", old, focusAccelerator);
 1573       }
 1574   
 1575       /**
 1576        * Returns the key accelerator that will cause the receiving
 1577        * text component to get the focus.  Return '\0' if no focus
 1578        * accelerator has been set.
 1579        *
 1580        * @return the key
 1581        */
 1582       public char getFocusAccelerator() {
 1583           return focusAccelerator;
 1584       }
 1585   
 1586       /**
 1587        * Initializes from a stream.  This creates a
 1588        * model of the type appropriate for the component
 1589        * and initializes the model from the stream.
 1590        * By default this will load the model as plain
 1591        * text.  Previous contents of the model are discarded.
 1592        *
 1593        * @param in the stream to read from
 1594        * @param desc an object describing the stream; this
 1595        *   might be a string, a File, a URL, etc.  Some kinds
 1596        *   of documents (such as html for example) might be
 1597        *   able to make use of this information; if non-<code>null</code>,
 1598        *   it is added as a property of the document
 1599        * @exception IOException as thrown by the stream being
 1600        *  used to initialize
 1601        * @see EditorKit#createDefaultDocument
 1602        * @see #setDocument
 1603        * @see PlainDocument
 1604        */
 1605       public void read(Reader in, Object desc) throws IOException {
 1606           EditorKit kit = getUI().getEditorKit(this);
 1607           Document doc = kit.createDefaultDocument();
 1608           if (desc != null) {
 1609               doc.putProperty(Document.StreamDescriptionProperty, desc);
 1610           }
 1611           try {
 1612               kit.read(in, doc, 0);
 1613               setDocument(doc);
 1614           } catch (BadLocationException e) {
 1615               throw new IOException(e.getMessage());
 1616           }
 1617       }
 1618   
 1619       /**
 1620        * Stores the contents of the model into the given
 1621        * stream.  By default this will store the model as plain
 1622        * text.
 1623        *
 1624        * @param out the output stream
 1625        * @exception IOException on any I/O error
 1626        */
 1627       public void write(Writer out) throws IOException {
 1628           Document doc = getDocument();
 1629           try {
 1630               getUI().getEditorKit(this).write(out, doc, 0, doc.getLength());
 1631           } catch (BadLocationException e) {
 1632               throw new IOException(e.getMessage());
 1633           }
 1634       }
 1635   
 1636       public void removeNotify() {
 1637           super.removeNotify();
 1638           if (getFocusedComponent() == this) {
 1639               AppContext.getAppContext().remove(FOCUSED_COMPONENT);
 1640           }
 1641       }
 1642   
 1643       // --- java.awt.TextComponent methods ------------------------
 1644   
 1645       /**
 1646        * Sets the position of the text insertion caret for the
 1647        * <code>TextComponent</code>.  Note that the caret tracks change,
 1648        * so this may move if the underlying text of the component is changed.
 1649        * If the document is <code>null</code>, does nothing. The position
 1650        * must be between 0 and the length of the component's text or else
 1651        * an exception is thrown.
 1652        *
 1653        * @param position the position
 1654        * @exception    IllegalArgumentException if the value supplied
 1655        *               for <code>position</code> is less than zero or greater
 1656        *               than the component's text length
 1657        * @beaninfo
 1658        * description: the caret position
 1659        */
 1660       public void setCaretPosition(int position) {
 1661           Document doc = getDocument();
 1662           if (doc != null) {
 1663               if (position > doc.getLength() || position < 0) {
 1664                   throw new IllegalArgumentException("bad position: " + position);
 1665               }
 1666               caret.setDot(position);
 1667           }
 1668       }
 1669   
 1670       /**
 1671        * Returns the position of the text insertion caret for the
 1672        * text component.
 1673        *
 1674        * @return the position of the text insertion caret for the
 1675        *  text component >= 0
 1676        */
 1677       @Transient
 1678       public int getCaretPosition() {
 1679           return caret.getDot();
 1680       }
 1681   
 1682       /**
 1683        * Sets the text of this <code>TextComponent</code>
 1684        * to the specified text.  If the text is <code>null</code>
 1685        * or empty, has the effect of simply deleting the old text.
 1686        * When text has been inserted, the resulting caret location
 1687        * is determined by the implementation of the caret class.
 1688        *
 1689        * <p>
 1690        * Note that text is not a bound property, so no <code>PropertyChangeEvent
 1691        * </code> is fired when it changes. To listen for changes to the text,
 1692        * use <code>DocumentListener</code>.
 1693        *
 1694        * @param t the new text to be set
 1695        * @see #getText
 1696        * @see DefaultCaret
 1697        * @beaninfo
 1698        * description: the text of this component
 1699        */
 1700       public void setText(String t) {
 1701           try {
 1702               Document doc = getDocument();
 1703               if (doc instanceof AbstractDocument) {
 1704                   ((AbstractDocument)doc).replace(0, doc.getLength(), t,null);
 1705               }
 1706               else {
 1707                   doc.remove(0, doc.getLength());
 1708                   doc.insertString(0, t, null);
 1709               }
 1710           } catch (BadLocationException e) {
 1711               UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this);
 1712           }
 1713       }
 1714   
 1715       /**
 1716        * Returns the text contained in this <code>TextComponent</code>.
 1717        * If the underlying document is <code>null</code>,
 1718        * will give a <code>NullPointerException</code>.
 1719        *
 1720        * Note that text is not a bound property, so no <code>PropertyChangeEvent
 1721        * </code> is fired when it changes. To listen for changes to the text,
 1722        * use <code>DocumentListener</code>.
 1723        *
 1724        * @return the text
 1725        * @exception NullPointerException if the document is <code>null</code>
 1726        * @see #setText
 1727        */
 1728       public String getText() {
 1729           Document doc = getDocument();
 1730           String txt;
 1731           try {
 1732               txt = doc.getText(0, doc.getLength());
 1733           } catch (BadLocationException e) {
 1734               txt = null;
 1735           }
 1736           return txt;
 1737       }
 1738   
 1739       /**
 1740        * Returns the selected text contained in this
 1741        * <code>TextComponent</code>.  If the selection is
 1742        * <code>null</code> or the document empty, returns <code>null</code>.
 1743        *
 1744        * @return the text
 1745        * @exception IllegalArgumentException if the selection doesn't
 1746        *  have a valid mapping into the document for some reason
 1747        * @see #setText
 1748        */
 1749       public String getSelectedText() {
 1750           String txt = null;
 1751           int p0 = Math.min(caret.getDot(), caret.getMark());
 1752           int p1 = Math.max(caret.getDot(), caret.getMark());
 1753           if (p0 != p1) {
 1754               try {
 1755                   Document doc = getDocument();
 1756                   txt = doc.getText(p0, p1 - p0);
 1757               } catch (BadLocationException e) {
 1758                   throw new IllegalArgumentException(e.getMessage());
 1759               }
 1760           }
 1761           return txt;
 1762       }
 1763   
 1764       /**
 1765        * Returns the boolean indicating whether this
 1766        * <code>TextComponent</code> is editable or not.
 1767        *
 1768        * @return the boolean value
 1769        * @see #setEditable
 1770        */
 1771       public boolean isEditable() {
 1772           return editable;
 1773       }
 1774   
 1775       /**
 1776        * Sets the specified boolean to indicate whether or not this
 1777        * <code>TextComponent</code> should be editable.
 1778        * A PropertyChange event ("editable") is fired when the
 1779        * state is changed.
 1780        *
 1781        * @param b the boolean to be set
 1782        * @see #isEditable
 1783        * @beaninfo
 1784        * description: specifies if the text can be edited
 1785        *       bound: true
 1786        */
 1787       public void setEditable(boolean b) {
 1788           if (b != editable) {
 1789               boolean oldVal = editable;
 1790               editable = b;
 1791               enableInputMethods(editable);
 1792               firePropertyChange("editable", Boolean.valueOf(oldVal), Boolean.valueOf(editable));
 1793               repaint();
 1794           }
 1795       }
 1796   
 1797       /**
 1798        * Returns the selected text's start position.  Return 0 for an
 1799        * empty document, or the value of dot if no selection.
 1800        *
 1801        * @return the start position >= 0
 1802        */
 1803       @Transient
 1804       public int getSelectionStart() {
 1805           int start = Math.min(caret.getDot(), caret.getMark());
 1806           return start;
 1807       }
 1808   
 1809       /**
 1810        * Sets the selection start to the specified position.  The new
 1811        * starting point is constrained to be before or at the current
 1812        * selection end.
 1813        * <p>
 1814        * This is available for backward compatibility to code
 1815        * that called this method on <code>java.awt.TextComponent</code>.
 1816        * This is implemented to forward to the <code>Caret</code>
 1817        * implementation which is where the actual selection is maintained.
 1818        *
 1819        * @param selectionStart the start position of the text >= 0
 1820        * @beaninfo
 1821        * description: starting location of the selection.
 1822        */
 1823       public void setSelectionStart(int selectionStart) {
 1824           /* Route through select method to enforce consistent policy
 1825            * between selectionStart and selectionEnd.
 1826            */
 1827           select(selectionStart, getSelectionEnd());
 1828       }
 1829   
 1830       /**
 1831        * Returns the selected text's end position.  Return 0 if the document
 1832        * is empty, or the value of dot if there is no selection.
 1833        *
 1834        * @return the end position >= 0
 1835        */
 1836       @Transient
 1837       public int getSelectionEnd() {
 1838           int end = Math.max(caret.getDot(), caret.getMark());
 1839           return end;
 1840       }
 1841   
 1842       /**
 1843        * Sets the selection end to the specified position.  The new
 1844        * end point is constrained to be at or after the current
 1845        * selection start.
 1846        * <p>
 1847        * This is available for backward compatibility to code
 1848        * that called this method on <code>java.awt.TextComponent</code>.
 1849        * This is implemented to forward to the <code>Caret</code>
 1850        * implementation which is where the actual selection is maintained.
 1851        *
 1852        * @param selectionEnd the end position of the text >= 0
 1853        * @beaninfo
 1854        * description: ending location of the selection.
 1855        */
 1856       public void setSelectionEnd(int selectionEnd) {
 1857           /* Route through select method to enforce consistent policy
 1858            * between selectionStart and selectionEnd.
 1859            */
 1860           select(getSelectionStart(), selectionEnd);
 1861       }
 1862   
 1863       /**
 1864        * Selects the text between the specified start and end positions.
 1865        * <p>
 1866        * This method sets the start and end positions of the
 1867        * selected text, enforcing the restriction that the start position
 1868        * must be greater than or equal to zero.  The end position must be
 1869        * greater than or equal to the start position, and less than or
 1870        * equal to the length of the text component's text.
 1871        * <p>
 1872        * If the caller supplies values that are inconsistent or out of
 1873        * bounds, the method enforces these constraints silently, and
 1874        * without failure. Specifically, if the start position or end
 1875        * position is greater than the length of the text, it is reset to
 1876        * equal the text length. If the start position is less than zero,
 1877        * it is reset to zero, and if the end position is less than the
 1878        * start position, it is reset to the start position.
 1879        * <p>
 1880        * This call is provided for backward compatibility.
 1881        * It is routed to a call to <code>setCaretPosition</code>
 1882        * followed by a call to <code>moveCaretPosition</code>.
 1883        * The preferred way to manage selection is by calling
 1884        * those methods directly.
 1885        *
 1886        * @param selectionStart the start position of the text
 1887        * @param selectionEnd the end position of the text
 1888        * @see #setCaretPosition
 1889        * @see #moveCaretPosition
 1890        */
 1891       public void select(int selectionStart, int selectionEnd) {
 1892           // argument adjustment done by java.awt.TextComponent
 1893           int docLength = getDocument().getLength();
 1894   
 1895           if (selectionStart < 0) {
 1896               selectionStart = 0;
 1897           }
 1898           if (selectionStart > docLength) {
 1899               selectionStart = docLength;
 1900           }
 1901           if (selectionEnd > docLength) {
 1902               selectionEnd = docLength;
 1903           }
 1904           if (selectionEnd < selectionStart) {
 1905               selectionEnd = selectionStart;
 1906           }
 1907   
 1908           setCaretPosition(selectionStart);
 1909           moveCaretPosition(selectionEnd);
 1910       }
 1911   
 1912       /**
 1913        * Selects all the text in the <code>TextComponent</code>.
 1914        * Does nothing on a <code>null</code> or empty document.
 1915        */
 1916       public void selectAll() {
 1917           Document doc = getDocument();
 1918           if (doc != null) {
 1919               setCaretPosition(0);
 1920               moveCaretPosition(doc.getLength());
 1921           }
 1922       }
 1923   
 1924       // --- Tooltip Methods ---------------------------------------------
 1925   
 1926       /**
 1927        * Returns the string to be used as the tooltip for <code>event</code>.
 1928        * This will return one of:
 1929        * <ol>
 1930        *  <li>If <code>setToolTipText</code> has been invoked with a
 1931        *      non-<code>null</code>
 1932        *      value, it will be returned, otherwise
 1933        *  <li>The value from invoking <code>getToolTipText</code> on
 1934        *      the UI will be returned.
 1935        * </ol>
 1936        * By default <code>JTextComponent</code> does not register
 1937        * itself with the <code>ToolTipManager</code>.
 1938        * This means that tooltips will NOT be shown from the
 1939        * <code>TextUI</code> unless <code>registerComponent</code> has
 1940        * been invoked on the <code>ToolTipManager</code>.
 1941        *
 1942        * @param event the event in question
 1943        * @return the string to be used as the tooltip for <code>event</code>
 1944        * @see javax.swing.JComponent#setToolTipText
 1945        * @see javax.swing.plaf.TextUI#getToolTipText
 1946        * @see javax.swing.ToolTipManager#registerComponent
 1947        */
 1948       public String getToolTipText(MouseEvent event) {
 1949           String retValue = super.getToolTipText(event);
 1950   
 1951           if (retValue == null) {
 1952               TextUI ui = getUI();
 1953               if (ui != null) {
 1954                   retValue = ui.getToolTipText(this, new Point(event.getX(),
 1955                                                                event.getY()));
 1956               }
 1957           }
 1958           return retValue;
 1959       }
 1960   
 1961       // --- Scrollable methods ---------------------------------------------
 1962   
 1963       /**
 1964        * Returns the preferred size of the viewport for a view component.
 1965        * This is implemented to do the default behavior of returning
 1966        * the preferred size of the component.
 1967        *
 1968        * @return the <code>preferredSize</code> of a <code>JViewport</code>
 1969        * whose view is this <code>Scrollable</code>
 1970        */
 1971       public Dimension getPreferredScrollableViewportSize() {
 1972           return getPreferredSize();
 1973       }
 1974   
 1975   
 1976       /**
 1977        * Components that display logical rows or columns should compute
 1978        * the scroll increment that will completely expose one new row
 1979        * or column, depending on the value of orientation.  Ideally,
 1980        * components should handle a partially exposed row or column by
 1981        * returning the distance required to completely expose the item.
 1982        * <p>
 1983        * The default implementation of this is to simply return 10% of
 1984        * the visible area.  Subclasses are likely to be able to provide
 1985        * a much more reasonable value.
 1986        *
 1987        * @param visibleRect the view area visible within the viewport
 1988        * @param orientation either <code>SwingConstants.VERTICAL</code> or
 1989        *   <code>SwingConstants.HORIZONTAL</code>
 1990        * @param direction less than zero to scroll up/left, greater than
 1991        *   zero for down/right
 1992        * @return the "unit" increment for scrolling in the specified direction
 1993        * @exception IllegalArgumentException for an invalid orientation
 1994        * @see JScrollBar#setUnitIncrement
 1995        */
 1996       public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
 1997           switch(orientation) {
 1998           case SwingConstants.VERTICAL:
 1999               return visibleRect.height / 10;
 2000           case SwingConstants.HORIZONTAL:
 2001               return visibleRect.width / 10;
 2002           default:
 2003               throw new IllegalArgumentException("Invalid orientation: " + orientation);
 2004           }
 2005       }
 2006   
 2007   
 2008       /**
 2009        * Components that display logical rows or columns should compute
 2010        * the scroll increment that will completely expose one block
 2011        * of rows or columns, depending on the value of orientation.
 2012        * <p>
 2013        * The default implementation of this is to simply return the visible
 2014        * area.  Subclasses will likely be able to provide a much more
 2015        * reasonable value.
 2016        *
 2017        * @param visibleRect the view area visible within the viewport
 2018        * @param orientation either <code>SwingConstants.VERTICAL</code> or
 2019        *   <code>SwingConstants.HORIZONTAL</code>
 2020        * @param direction less than zero to scroll up/left, greater than zero
 2021        *  for down/right
 2022        * @return the "block" increment for scrolling in the specified direction
 2023        * @exception IllegalArgumentException for an invalid orientation
 2024        * @see JScrollBar#setBlockIncrement
 2025        */
 2026       public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
 2027           switch(orientation) {
 2028           case SwingConstants.VERTICAL:
 2029               return visibleRect.height;
 2030           case SwingConstants.HORIZONTAL:
 2031               return visibleRect.width;
 2032           default:
 2033               throw new IllegalArgumentException("Invalid orientation: " + orientation);
 2034           }
 2035       }
 2036   
 2037   
 2038       /**
 2039        * Returns true if a viewport should always force the width of this
 2040        * <code>Scrollable</code> to match the width of the viewport.
 2041        * For example a normal text view that supported line wrapping
 2042        * would return true here, since it would be undesirable for
 2043        * wrapped lines to disappear beyond the right
 2044        * edge of the viewport.  Note that returning true for a
 2045        * <code>Scrollable</code> whose ancestor is a <code>JScrollPane</code>
 2046        * effectively disables horizontal scrolling.
 2047        * <p>
 2048        * Scrolling containers, like <code>JViewport</code>,
 2049        * will use this method each time they are validated.
 2050        *
 2051        * @return true if a viewport should force the <code>Scrollable</code>s
 2052        *   width to match its own
 2053        */
 2054       public boolean getScrollableTracksViewportWidth() {
 2055           if (getParent() instanceof JViewport) {
 2056               return (((JViewport)getParent()).getWidth() > getPreferredSize().width);
 2057           }
 2058           return false;
 2059       }
 2060   
 2061       /**
 2062        * Returns true if a viewport should always force the height of this
 2063        * <code>Scrollable</code> to match the height of the viewport.
 2064        * For example a columnar text view that flowed text in left to
 2065        * right columns could effectively disable vertical scrolling by
 2066        * returning true here.
 2067        * <p>
 2068        * Scrolling containers, like <code>JViewport</code>,
 2069        * will use this method each time they are validated.
 2070        *
 2071        * @return true if a viewport should force the Scrollables height
 2072        *   to match its own
 2073        */
 2074       public boolean getScrollableTracksViewportHeight() {
 2075           if (getParent() instanceof JViewport) {
 2076               return (((JViewport)getParent()).getHeight() > getPreferredSize().height);
 2077           }
 2078           return false;
 2079       }
 2080   
 2081   
 2082   //////////////////
 2083   // Printing Support
 2084   //////////////////
 2085   
 2086       /**
 2087        * A convenience print method that displays a print dialog, and then
 2088        * prints this {@code JTextComponent} in <i>interactive</i> mode with no
 2089        * header or footer text. Note: this method
 2090        * blocks until printing is done.
 2091        * <p>
 2092        * Note: In <i>headless</i> mode, no dialogs will be shown.
 2093        *
 2094        * <p> This method calls the full featured
 2095        * {@link #print(MessageFormat, MessageFormat, boolean, PrintService, PrintRequestAttributeSet, boolean)
 2096        * print} method to perform printing.
 2097        * @return {@code true}, unless printing is canceled by the user
 2098        * @throws PrinterException if an error in the print system causes the job
 2099        *         to be aborted
 2100        * @throws SecurityException if this thread is not allowed to
 2101        *                           initiate a print job request
 2102        *
 2103        * @see #print(MessageFormat, MessageFormat, boolean, PrintService, PrintRequestAttributeSet, boolean)
 2104        *
 2105        * @since 1.6
 2106        */
 2107   
 2108       public boolean print() throws PrinterException {
 2109           return print(null, null, true, null, null, true);
 2110       }
 2111   
 2112       /**
 2113        * A convenience print method that displays a print dialog, and then
 2114        * prints this {@code JTextComponent} in <i>interactive</i> mode with
 2115        * the specified header and footer text. Note: this method
 2116        * blocks until printing is done.
 2117        * <p>
 2118        * Note: In <i>headless</i> mode, no dialogs will be shown.
 2119        *
 2120        * <p> This method calls the full featured
 2121        * {@link #print(MessageFormat, MessageFormat, boolean, PrintService, PrintRequestAttributeSet, boolean)
 2122        * print} method to perform printing.
 2123        * @param headerFormat the text, in {@code MessageFormat}, to be
 2124        *        used as the header, or {@code null} for no header
 2125        * @param footerFormat the text, in {@code MessageFormat}, to be
 2126        *        used as the footer, or {@code null} for no footer
 2127        * @return {@code true}, unless printing is canceled by the user
 2128        * @throws PrinterException if an error in the print system causes the job
 2129        *         to be aborted
 2130        * @throws SecurityException if this thread is not allowed to
 2131        *                           initiate a print job request
 2132        *
 2133        * @see #print(MessageFormat, MessageFormat, boolean, PrintService, PrintRequestAttributeSet, boolean)
 2134        * @see java.text.MessageFormat
 2135        * @since 1.6
 2136        */
 2137       public boolean print(final MessageFormat headerFormat,
 2138               final MessageFormat footerFormat) throws PrinterException {
 2139           return print(headerFormat, footerFormat, true, null, null, true);
 2140       }
 2141   
 2142       /**
 2143        * Prints the content of this {@code JTextComponent}. Note: this method
 2144        * blocks until printing is done.
 2145        *
 2146        * <p>
 2147        * Page header and footer text can be added to the output by providing
 2148        * {@code MessageFormat} arguments. The printing code requests
 2149        * {@code Strings} from the formats, providing a single item which may be
 2150        * included in the formatted string: an {@code Integer} representing the
 2151        * current page number.
 2152        *
 2153        * <p>
 2154        * {@code showPrintDialog boolean} parameter allows you to specify whether
 2155        * a print dialog is displayed to the user. When it is, the user
 2156        * may use the dialog to change printing attributes or even cancel the
 2157        * print.
 2158        *
 2159        * <p>
 2160        * {@code service} allows you to provide the initial
 2161        * {@code PrintService} for the print dialog, or to specify
 2162        * {@code PrintService} to print to when the dialog is not shown.
 2163        *
 2164        * <p>
 2165        * {@code attributes} can be used to provide the
 2166        * initial values for the print dialog, or to supply any needed
 2167        * attributes when the dialog is not shown. {@code attributes} can
 2168        * be used to control how the job will print, for example
 2169        * <i>duplex</i> or <i>single-sided</i>.
 2170        *
 2171        * <p>
 2172        * {@code interactive boolean} parameter allows you to specify
 2173        * whether to perform printing in <i>interactive</i>
 2174        * mode. If {@code true}, a progress dialog, with an abort option,
 2175        * is displayed for the duration of printing.  This dialog is
 2176        * <i>modal</i> when {@code print} is invoked on the <i>Event Dispatch
 2177        * Thread</i> and <i>non-modal</i> otherwise. <b>Warning</b>:
 2178        * calling this method on the <i>Event Dispatch Thread</i> with {@code
 2179        * interactive false} blocks <i>all</i> events, including repaints, from
 2180        * being processed until printing is complete. It is only
 2181        * recommended when printing from an application with no
 2182        * visible GUI.
 2183        *
 2184        * <p>
 2185        * Note: In <i>headless</i> mode, {@code showPrintDialog} and
 2186        * {@code interactive} parameters are ignored and no dialogs are
 2187        * shown.
 2188        *
 2189        * <p>
 2190        * This method ensures the {@code document} is not mutated during printing.
 2191        * To indicate it visually, {@code setEnabled(false)} is set for the
 2192        * duration of printing.
 2193        *
 2194        * <p>
 2195        * This method uses {@link #getPrintable} to render document content.
 2196        *
 2197        * <p>
 2198        * This method is thread-safe, although most Swing methods are not. Please
 2199        * see <A
 2200        * HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">
 2201        * How to Use Threads</A> for more information.
 2202        *
 2203        * <p>
 2204        * <b>Sample Usage</b>. This code snippet shows a cross-platform print
 2205        * dialog and then prints the {@code JTextComponent} in <i>interactive</i> mode
 2206        * unless the user cancels the dialog:
 2207        *
 2208        * <pre>
 2209        * textComponent.print(new MessageFormat(&quot;My text component header&quot;),
 2210        *     new MessageFormat(&quot;Footer. Page - {0}&quot;), true, null, null, true);
 2211        * </pre>
 2212        * <p>
 2213        * Executing this code off the <i>Event Dispatch Thread</i>
 2214        * performs printing on the <i>background</i>.
 2215        * The following pattern might be used for <i>background</i>
 2216        * printing:
 2217        * <pre>
 2218        *     FutureTask&lt;Boolean&gt; future =
 2219        *         new FutureTask&lt;Boolean&gt;(
 2220        *             new Callable&lt;Boolean&gt;() {
 2221        *                 public Boolean call() {
 2222        *                     return textComponent.print(.....);
 2223        *                 }
 2224        *             });
 2225        *     executor.execute(future);
 2226        * </pre>
 2227        *
 2228        * @param headerFormat the text, in {@code MessageFormat}, to be
 2229        *        used as the header, or {@code null} for no header
 2230        * @param footerFormat the text, in {@code MessageFormat}, to be
 2231        *        used as the footer, or {@code null} for no footer
 2232        * @param showPrintDialog {@code true} to display a print dialog,
 2233        *        {@code false} otherwise
 2234        * @param service initial {@code PrintService}, or {@code null} for the
 2235        *        default
 2236        * @param attributes the job attributes to be applied to the print job, or
 2237        *        {@code null} for none
 2238        * @param interactive whether to print in an interactive mode
 2239        * @return {@code true}, unless printing is canceled by the user
 2240        * @throws PrinterException if an error in the print system causes the job
 2241        *         to be aborted
 2242        * @throws SecurityException if this thread is not allowed to
 2243        *                           initiate a print job request
 2244        *
 2245        * @see #getPrintable
 2246        * @see java.text.MessageFormat
 2247        * @see java.awt.GraphicsEnvironment#isHeadless
 2248        * @see java.util.concurrent.FutureTask
 2249        *
 2250        * @since 1.6
 2251        */
 2252       public boolean print(final MessageFormat headerFormat,
 2253               final MessageFormat footerFormat,
 2254               final boolean showPrintDialog,
 2255               final PrintService service,
 2256               final PrintRequestAttributeSet attributes,
 2257               final boolean interactive)
 2258               throws PrinterException {
 2259   
 2260           final PrinterJob job = PrinterJob.getPrinterJob();
 2261           final Printable printable;
 2262           final PrintingStatus printingStatus;
 2263           final boolean isHeadless = GraphicsEnvironment.isHeadless();
 2264           final boolean isEventDispatchThread =
 2265               SwingUtilities.isEventDispatchThread();
 2266           final Printable textPrintable = getPrintable(headerFormat, footerFormat);
 2267           if (interactive && ! isHeadless) {
 2268               printingStatus =
 2269                   PrintingStatus.createPrintingStatus(this, job);
 2270               printable =
 2271                   printingStatus.createNotificationPrintable(textPrintable);
 2272           } else {
 2273               printingStatus = null;
 2274               printable = textPrintable;
 2275           }
 2276   
 2277           if (service != null) {
 2278               job.setPrintService(service);
 2279           }
 2280   
 2281           job.setPrintable(printable);
 2282   
 2283           final PrintRequestAttributeSet attr = (attributes == null)
 2284               ? new HashPrintRequestAttributeSet()
 2285               : attributes;
 2286   
 2287           if (showPrintDialog && ! isHeadless && ! job.printDialog(attr)) {
 2288               return false;
 2289           }
 2290   
 2291           /*
 2292            * there are three cases for printing:
 2293            * 1. print non interactively (! interactive || isHeadless)
 2294            * 2. print interactively off EDT
 2295            * 3. print interactively on EDT
 2296            *
 2297            * 1 and 2 prints on the current thread (3 prints on another thread)
 2298            * 2 and 3 deal with PrintingStatusDialog
 2299            */
 2300           final Callable<Object> doPrint =
 2301               new Callable<Object>() {
 2302                   public Object call() throws Exception {
 2303                       try {
 2304                           job.print(attr);
 2305                       } finally {
 2306                           if (printingStatus != null) {
 2307                               printingStatus.dispose();
 2308                           }
 2309                       }
 2310                       return null;
 2311                   }
 2312               };
 2313   
 2314           final FutureTask<Object> futurePrinting =
 2315               new FutureTask<Object>(doPrint);
 2316   
 2317 &nb