home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / jfc.bin / JTextComponent.java < prev    next >
Text File  |  1998-02-26  |  67KB  |  2,100 lines

  1. /*
  2.  * @(#)JTextComponent.java    1.92 98/02/06
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package com.sun.java.swing.text;
  21.  
  22. import java.util.Hashtable;
  23. import java.util.Enumeration;
  24. import java.io.*;
  25. import java.awt.*;
  26. import java.awt.event.*;
  27. import java.awt.datatransfer.*;
  28. import java.text.*;
  29. import com.sun.java.swing.*;
  30. import com.sun.java.swing.event.*;
  31. import com.sun.java.swing.plaf.*;
  32. import com.sun.java.accessibility.*;
  33.  
  34. /**
  35.  * <p>
  36.  * JTextComponent is the base class for swing text components.  It
  37.  * tries to be compatible with the java.awt.TextComponent class
  38.  * where it can reasonably do so.  Also provided are other services
  39.  * for additional flexibility (beyond the pluggable UI and bean
  40.  * support).
  41.  * <dl>
  42.  * <dt><b><font size=+1>Caret Changes</font></b>
  43.  * <dd>
  44.  * The caret is a pluggable object in swing text components.
  45.  * Notification of changes to the caret position and the selection
  46.  * are sent to implementations of the CaretListener interface that
  47.  * have been registered with the text component.  The UI will
  48.  * install a default caret unless a customized caret has been 
  49.  * set.
  50.  * <dt><b><font size=+1>Commands</font></b>
  51.  * <dd>
  52.  * <p>
  53.  * Text components provide a number of commands that can be used
  54.  * to manipulate the component.  This is essentially the way that
  55.  * the component expresses it's capabilities.  These are expressed
  56.  * in terms of the swing Action interface, using the TextAction
  57.  * implementation.  The set of commands supported by the text
  58.  * component can be found with the 
  59.  * <a href="#getActions">getActions</a> method.  These actions
  60.  * can be bound to key events, fired from buttons, etc.
  61.  *
  62.  * <dt><b><font size=+1>Keymaps</font></b>
  63.  * <dd>
  64.  * <p>
  65.  * To facilitate flexible use of the keyboard, support for
  66.  * creating keymaps and binding various keystrokes to some kind of 
  67.  * action is provided.  In order to allow keymaps to be shared across 
  68.  * multiple text components, they can use actions that extend TextAction.  
  69.  * TextAction can determine which JTextComponent most recently has or had
  70.  * focus and therefore is the subject of the action (In the case that the 
  71.  * ActionEvent sent to the action doesn't contain the target text component 
  72.  * as it's source).
  73.  * <p>
  74.  * The use of the keymap is encouraged, but backward compatibilty
  75.  * with the awt mechanism is provided by giving the 
  76.  * listeners a chance to steal the event by consuming it.
  77.  * Keyboard event distribution is handled the following order, with
  78.  * each distribution capable of consuming the event.
  79.  * <ol>
  80.  * <li>focus manager
  81.  * <li>registered KeyListener's
  82.  * <li>keymap handling using the current keymap
  83.  * <li>keyboard handling in JComponent (eg accelerators,
  84.  * component navigation, etc).
  85.  * </ol>
  86.  * <p>
  87.  * By default the component will create a keymap (named <b>DEFAULT_KEYMAP</b>) 
  88.  * that is shared by all JTextComponent instances as the default keymap.  
  89.  * Typically a look-and-feel implementation will install a different keymap
  90.  * that resolves to the default keymap for those bindings not found in the 
  91.  * different keymap. The minimal bindings include:
  92.  * <ul>
  93.  * <li>inserting content into the editor for the
  94.  *  printable keys.
  95.  * <li>removing content with the backspace and del
  96.  *  keys.
  97.  * <li>caret movement forward and backward
  98.  * </ul>
  99.  *
  100.  * <dt><b><font size=+1>Model/View Split</font></b>
  101.  * <dd>
  102.  * <p>
  103.  * The text components have a model-view split.  A text component pulls 
  104.  * together the objects used to represent the model, view, and controller. 
  105.  * The text document model may be shared by other views which act as observers 
  106.  * of the model (eg. a document may be shared by multiple components).
  107.  *
  108.  * <p align=center><img src="images/editor.gif" HEIGHT=358 WIDTH=587></p>
  109.  *
  110.  * <p>
  111.  * The model is defined by the
  112.  * <a href="com.sun.java.swing.text.Document.html">Document</a>
  113.  * interface.  This is intended to provide a flexible text storage mechanism
  114.  * that tracks change during edits and can be extended to more sophisticated
  115.  * models.  The model interfaces are meant to capture the capabilities of
  116.  * expression given by SGML, a system used to express a wide variety of
  117.  * content.  Changes to the model are sent in the form of a
  118.  * Each modification to the document causes notification of the
  119.  * details of the change to be sent to all observers in the form of a 
  120.  * <a href="com.sun.java.swing.event.DocumentEvent.html">DocumentEvent</a>
  121.  * which allows the views to stay up to date with the model.
  122.  * This event is sent to observers that have implemented the 
  123.  * <a href="com.sun.java.swing.event.DocumentListener.html">DocumentListener</a>
  124.  * interface and registered interest with the model being observed.
  125.  *
  126.  * <dt><b><font size=+1>Location Information</font></b>
  127.  * <dd>
  128.  * The capability of determining the location of text in
  129.  * the view is provided.  There are two methods, 
  130.  * <a href="#modelToView">modelToView</a> and
  131.  * <a href="#viewToModel">viewToModel</a> for determining
  132.  * this information.
  133.  * <dt><b><font size=+1>Undo/Redo support</font></b>
  134.  * <dd>
  135.  * Support of an edit history mechanism is provided to allow
  136.  * undo/redo operations.  The text component does not itself
  137.  * provide the history buffer by default, but does provide
  138.  * the UndoableEdit records that can be used in conjunction
  139.  * with a history buffer to provide the undo/redo support.
  140.  * The support is provided by the Document model, which allows
  141.  * one to attach UndoableEditListener implementations.
  142.  *
  143.  * <dt><b><font size=+1>Thread Safety</font></b>
  144.  * <dd>
  145.  * The swing text components provide some support of thread
  146.  * safe operations.  Because of the high level of configurability
  147.  * of the text components, it is possible to circumvent the
  148.  * protection provided.  The protection primarily comes from
  149.  * the model, so the documentation of AbstractDocument
  150.  * describes the assumptions of the protection provided.
  151.  * The methods that are safe to call asynchronously are marked
  152.  * with comments.
  153.  * </dl>
  154.  *
  155.  * <p>
  156.  * Warning: serialized objects of this class will not be compatible with
  157.  * future swing releases.  The current serialization support is appropriate
  158.  * for short term storage or RMI between Swing1.0 applications.  It will
  159.  * not be possible to load serialized Swing1.0 objects with future releases
  160.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  161.  * baseline for the serialized form of Swing objects.
  162.  *
  163.  * @beaninfo
  164.  *     attribute: isContainer false
  165.  * 
  166.  * @author  Timothy Prinzing
  167.  * @version 1.92 02/06/98
  168.  * @see Document
  169.  * @see DocumentEvent
  170.  * @see DocumentListener
  171.  * @see Caret
  172.  * @see CaretEvent
  173.  * @see CaretListener
  174.  * @see TextUI
  175.  * @see View
  176.  * @see ViewFactory
  177.  */
  178. public abstract class JTextComponent extends JComponent implements Scrollable,
  179. Accessible
  180. {
  181.  
  182.     /**
  183.      * Creates a new JTextComponent.
  184.      */
  185.     public JTextComponent() {
  186.         super();
  187.     enableEvents(AWTEvent.KEY_EVENT_MASK);
  188.         caretEvent = new MutableCaretEvent(this);
  189.         addMouseListener(caretEvent);
  190.     addFocusListener(caretEvent);
  191.         setEditable(true);
  192.         setLayout(null); // layout is managed by View hierarchy
  193.         updateUI();
  194.     }
  195.  
  196.     /**
  197.      * Fetches the user-interface factory for this text-oriented editor.
  198.      *
  199.      * @return the factory
  200.      */
  201.     public TextUI getUI() { return (TextUI)ui; }
  202.  
  203.     /**
  204.      * Sets the user-interface factory for this text-oriented editor
  205.      *
  206.      * @param ui the factory
  207.      */
  208.     public void setUI(TextUI ui) {
  209.         super.setUI(ui);
  210.     }
  211.  
  212.     /**
  213.      * Reloads the pluggable UI.  The key used to fetch the
  214.      * new interface is <b>getUIClassID()</b>.  The type of
  215.      * the UI is <b>TextUI</b>.
  216.      */
  217.     public void updateUI() {
  218.         setUI((TextUI)UIManager.getUI(this));
  219.         invalidate();
  220.     }
  221.  
  222.  
  223.     /**
  224.      * Returns true if this component is completely opaque.  
  225.      * 
  226.      * @return true if this component is completely opaque.
  227.      */
  228.     public boolean isOpaque() {
  229.         return opaque;
  230.     }
  231.  
  232.     /**
  233.      * Sets whether or not the UI should render a background.
  234.      *
  235.      * @param o true if should render a background
  236.      */
  237.     public void setOpaque(boolean o) {
  238.         opaque = o;
  239.     }
  240.  
  241.     /**
  242.      * Adds a caret listener for notification of any changes
  243.      * to the caret.
  244.      *
  245.      * @param listener the listener
  246.      * @see com.sun.java.swing.event.CaretEvent
  247.      */
  248.     public void addCaretListener(CaretListener listener) {
  249.         listenerList.add(CaretListener.class, listener);
  250.     }
  251.  
  252.     /**
  253.      * Removes a caret listener.
  254.      *
  255.      * @param listener the listener
  256.      * @see com.sun.java.swing.event.CaretEvent
  257.      */
  258.     public void removeCaretListener(CaretListener listener) {
  259.         listenerList.remove(CaretListener.class, listener);
  260.     }
  261.  
  262.     /**
  263.      * Notifies all listeners that have registered interest for
  264.      * notification on this event type.  The event instance 
  265.      * is lazily created using the parameters passed into 
  266.      * the fire method.
  267.      *
  268.      * @param e the event
  269.      * @see EventListenerList
  270.      */
  271.     protected void fireCaretUpdate(CaretEvent e) {
  272.         // Guaranteed to return a non-null array
  273.         Object[] listeners = listenerList.getListenerList();
  274.         // Process the listeners last to first, notifying
  275.         // those that are interested in this event
  276.         for (int i = listeners.length-2; i>=0; i-=2) {
  277.             if (listeners[i]==CaretListener.class) {
  278.                 ((CaretListener)listeners[i+1]).caretUpdate(e);
  279.             }
  280.         }
  281.     }
  282.  
  283.     /**
  284.      * Associates the editor with a text document.
  285.      * The currently registered factory is used to build a view for
  286.      * the document, which gets displayed by the editor.
  287.      *
  288.      * @param doc  the document to display/edit
  289.      * @see #getDocument
  290.      * @beaninfo
  291.      *  description: the text document model
  292.      *        bound: true
  293.      *       expert: true
  294.      */
  295.     public void setDocument(Document doc) {
  296.         if (accessibleContext != null) {
  297.             model.removeDocumentListener(
  298.                 ((AccessibleJTextComponent)accessibleContext));
  299.         }
  300.         Document old = model;
  301.         model = doc;
  302.         firePropertyChange("document", old, doc);
  303.     revalidate();
  304.         repaint();
  305.         if (accessibleContext != null) {
  306.             model.addDocumentListener(
  307.                 ((AccessibleJTextComponent)accessibleContext));
  308.         }
  309.     }
  310.  
  311.     /**
  312.      * Fetches the model associated with the editor.  This is
  313.      * primarily for the UI to get at the minimal amount of
  314.      * state required to be a text editor.  Subclasses will
  315.      * return the actual type of the model which will typically
  316.      * be something that extends Document.
  317.      *
  318.      * @return the model
  319.      */
  320.     public Document getDocument() {
  321.         return model;
  322.     }
  323.  
  324.     /**
  325.      * Fetches the command list for the editor.  This is
  326.      * the list of commands supported by the plugged-in UI
  327.      * augmented by the collection of commands that the
  328.      * editor itself supports.  These are useful for binding
  329.      * to events, such as in a keymap.
  330.      *
  331.      * @return the command list
  332.      */
  333.     public Action[] getActions() {      
  334.         return getUI().getEditorKit().getActions(); 
  335.     }
  336.  
  337.     /**
  338.      * Sets margin space between the text component's border
  339.      * and its text. Setting it to null will cause the text component
  340.      * to use a default margin.  The text component's default Border
  341.      * object will use this value to create the proper margin.
  342.      * However, if a non-default border is set on the text component, 
  343.      * it is that Border object's responsibility to create the
  344.      * appropriate margin space (else this property will effectively 
  345.      * be ignored).
  346.      *
  347.      * @param m the space between the border and the text
  348.      * @beaninfo
  349.      *  description: desired space between the border and text area
  350.      *        bound: true
  351.      */
  352.     public void setMargin(Insets m) {
  353.         Insets old = margin;
  354.         margin = m;
  355.         firePropertyChange("margin", old, m);
  356.         invalidate();
  357.     }
  358.  
  359.     /**
  360.      * Returns the margin between the text component's border and
  361.      * its text.
  362.      *
  363.      * @return the margin
  364.      */
  365.     public Insets getMargin() {
  366.         if(margin == null) {
  367.             return ((TextUI)ui).getDefaultMargin();
  368.         } else {
  369.             return margin;
  370.         }
  371.     }
  372.  
  373.     /**
  374.      * Fetches the cursor that allows text-oriented navigation over
  375.      * the view.  
  376.      *
  377.      * @return the cursor
  378.      */
  379.     public Caret getCaret() {
  380.         return caret;
  381.     }
  382.  
  383.     /**
  384.      * Sets the caret to be used.  By default this will be set
  385.      * by the UI that gets installed.  This can be changed to
  386.      * a custom caret if desired.
  387.      *
  388.      * @param c the caret
  389.      * @see #getCaret
  390.      * @beaninfo
  391.      *  description: the caret used to select/navigate
  392.      *        bound: true
  393.      *       expert: true
  394.      */
  395.     public void setCaret(Caret c) {
  396.         if (caret != null) {
  397.             caret.removeChangeListener(caretEvent);
  398.             caret.deinstall(this);
  399.         }
  400.         Caret old = caret;
  401.         caret = c;
  402.         if (caret != null) {
  403.             caret.install(this);
  404.             caret.addChangeListener(caretEvent);
  405.         }
  406.         firePropertyChange("caret", old, caret);
  407.     }
  408.  
  409.     /**
  410.      * Fetches the object responsible for making highlights.
  411.      *
  412.      * @return the highlighter
  413.      */
  414.     public Highlighter getHighlighter() {
  415.         return highlighter;
  416.     }
  417.  
  418.     /**
  419.      * Sets the highlighter to be used.  By default this will be set
  420.      * by the UI that gets installed.  This can be changed to
  421.      * a custom highlighter if desired.
  422.      *
  423.      * @param h the highlighter
  424.      * @see #getHighlighter
  425.      * @beaninfo
  426.      *  description: object responsible for background highlights
  427.      *        bound: true
  428.      *       expert: true
  429.      */
  430.     public void setHighlighter(Highlighter h) {
  431.         if (highlighter != null) {
  432.             highlighter.deinstall(this);
  433.         }
  434.         Highlighter old = highlighter;
  435.         highlighter = h;
  436.         if (highlighter != null) {
  437.             highlighter.install(this);
  438.         }
  439.         firePropertyChange("highlighter", old, h);
  440.     }
  441.  
  442.     /**
  443.      * Sets the keymap to use for binding events to
  444.      * actions.
  445.      *
  446.      * @param map the keymap
  447.      * @see #getKeymap
  448.      * @beaninfo
  449.      *  description: set of key event to action bindings to use
  450.      *        bound: true
  451.      */
  452.     public void setKeymap(Keymap map) {
  453.         Keymap old = keymap;
  454.         keymap = map;
  455.         firePropertyChange("keymap", old, keymap);
  456.     }
  457.  
  458.     /**
  459.      * Fetches the keymap being used by the controller
  460.      *
  461.      * @return the keymap
  462.      */
  463.     public Keymap getKeymap() {
  464.         return keymap;
  465.     }
  466.  
  467.     /**
  468.      * Adds a new keymap into the keymap hierarchy.  Keymap bindings
  469.      * resolve from bottom up so an attribute specified in a child
  470.      * will override an attribute specified in the parent.
  471.      *
  472.      * @param nm   the name of the keymap (must be unique within the
  473.      *   collection of named keymaps in the document).  The name may 
  474.      *   be null if the keymap is unnamed, but the caller is responsible
  475.      *   for managing the reference returned as an unnamed keymap can't
  476.      *   be fetched by name.  
  477.      * @param parent the parent keymap.  This may be null if unspecified
  478.      *   bindings need not be resolved in some other keymap.
  479.      * @return the keymap
  480.      */
  481.     public static Keymap addKeymap(String nm, Keymap parent) {
  482.     Keymap map = new DefaultKeymap(nm, parent); 
  483.     if (nm != null) {
  484.         // add a named keymap, a class of bindings
  485.         keymapTable.put(nm, map);
  486.     }
  487.     return map;
  488.     }
  489.  
  490.     /**
  491.      * Removes a named keymap previously added to the document.  
  492.      *
  493.      * @param nm  the name of the keymap to remove
  494.      * @return the keymap
  495.      */
  496.     public static Keymap removeKeymap(String nm) {
  497.     return (Keymap) keymapTable.remove(nm);
  498.     }
  499.  
  500.     /**
  501.      * Fetches a named keymap previously added to the document.
  502.      *
  503.      * @param nm  the name of the keymap
  504.      * @return the keymap
  505.      */
  506.     public static Keymap getKeymap(String nm) {
  507.     return (Keymap) keymapTable.get(nm);
  508.     }
  509.  
  510.     /**
  511.      * Binding record for creating key bindings
  512.      * <p>
  513.      * Warning: serialized objects of this class will not be compatible with
  514.      * future swing releases.  The current serialization support is appropriate
  515.      * for short term storage or RMI between Swing1.0 applications.  It will
  516.      * not be possible to load serialized Swing1.0 objects with future releases
  517.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  518.      * baseline for the serialized form of Swing objects.
  519.      */
  520.     public static class KeyBinding {
  521.     
  522.         /**
  523.          * The key.
  524.          */
  525.     public KeyStroke key;
  526.  
  527.         /**
  528.          * The name of the action for the key.
  529.          */
  530.     public String actionName;
  531.  
  532.         /**
  533.          * Creates a new key binding.
  534.          *
  535.          * @param key the key
  536.          * @param actionName the name of the action for the key
  537.          */
  538.         public KeyBinding(KeyStroke key, String actionName) {
  539.         this.key = key;
  540.         this.actionName = actionName;
  541.     }
  542.     }
  543.  
  544.     /**
  545.      * <p>
  546.      * Loads a keymap with a bunch of 
  547.      * bindings.  This can be used to take a static table of
  548.      * definitions and load them into some keymap.  The following
  549.      * example illustrates an example of binding some keys to
  550.      * the cut, copy, and paste actions associated with a 
  551.      * JTextComponent.  It also binds tab to insert the tab
  552.      * into the text component.  A code fragment to accomplish
  553.      * this might look as follows:
  554.      * <pre>
  555.      *    JTextComponent c = new JTextPane();
  556.      *    Keymap k = c.getKeymap();
  557.      *    JTextComponent.loadKeymap(k, c.getActions(), defaultBindings);
  558.      *  
  559.      *    static final JTextComponent.KeyBinding[] defaultBindings = {
  560.      *      new JTextComponent.KeyBinding(
  561.      *        KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK),
  562.      *        JTextComponent.copyAction),
  563.      *      new JTextComponent.KeyBinding(
  564.      *        KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK),
  565.      *        JTextComponent.pasteAction),
  566.      *      new JTextComponent.KeyBinding(
  567.      *        KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK),
  568.      *        JTextComponent.cutAction),
  569.      *      new JTextComponent.KeyBinding(
  570.      *        KeyStroke.getKeyStroke('\t'),
  571.      *        JTextComponent.insertContentAction)
  572.      *    };
  573.      * </pre>
  574.      *
  575.      * @param map the keymap
  576.      * @param bindings the bindings
  577.      * @param actions the set of actions
  578.      */
  579.     public static void loadKeymap(Keymap map, KeyBinding[] bindings, Action[] actions) {
  580.     Hashtable h = new Hashtable();
  581.     for (int i = 0; i < actions.length; i++) {
  582.         Action a = actions[i];
  583.         String value = (String)a.getValue(Action.NAME);
  584.         h.put((value!=null ? value:""), a);
  585.     }
  586.     for (int i = 0; i < bindings.length; i++) {
  587.         Action a = (Action) h.get(bindings[i].actionName);
  588.         if (a != null) {
  589.         map.addActionForKeyStroke(bindings[i].key, a);
  590.         }
  591.     }
  592.     }
  593.  
  594.     /**
  595.      * Maps an event to an action if one is defined in the 
  596.      * installed keymap, and perform the action.  If the action is 
  597.      * performed, the event is consumed.
  598.      * @returns true if an action was performed, false otherwise.
  599.      */
  600.     private final boolean mapEventToAction(KeyEvent e) {
  601.     Keymap binding = getKeymap();
  602.     if (binding != null) {
  603.         KeyStroke k = KeyStroke.getKeyStrokeForEvent(e);
  604.         Action a = binding.getAction(k);
  605.         if (a != null) {
  606.         String command = null;
  607.         if (e.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
  608.             command = String.valueOf(e.getKeyChar());
  609.         }
  610.         ActionEvent ae =  new ActionEvent(this, 
  611.                           ActionEvent.ACTION_PERFORMED, 
  612.                           command, e.getModifiers());
  613.         a.actionPerformed(ae);
  614.         e.consume();
  615.         return true;
  616.         }
  617.     }
  618.     return false;
  619.     }
  620.  
  621.     /**
  622.      * Fetches the current color used to render the 
  623.      * caret.
  624.      *
  625.      * @return the color
  626.      */
  627.     public Color getCaretColor() {
  628.         return caretColor;
  629.     }
  630.  
  631.     /**
  632.      * Sets the current color used to render the
  633.      * caret.
  634.      *
  635.      * @param c the color
  636.      * @see #getCaretColor
  637.      * @beaninfo
  638.      *  description: the color used to render the caret
  639.      *        bound: true
  640.      *    preferred: true
  641.      */
  642.     public void setCaretColor(Color c) {
  643.         Color old = caretColor;
  644.         caretColor = c;
  645.         firePropertyChange("caretColor", old, caretColor);
  646.     }
  647.  
  648.     /**
  649.      * Fetches the current color used to render the 
  650.      * selection.
  651.      *
  652.      * @return the color
  653.      */
  654.     public Color getSelectionColor() {
  655.         return selectionColor;
  656.     }
  657.  
  658.     /**
  659.      * Sets the current color used to render the
  660.      * selection.
  661.      *
  662.      * @param c the color
  663.      * @see #getSelectionColor
  664.      * @beaninfo
  665.      *  description: color used to render selection background
  666.      *        bound: true
  667.      *    preferred: true
  668.      */
  669.     public void setSelectionColor(Color c) {
  670.         Color old = selectionColor;
  671.         selectionColor = c;
  672.         firePropertyChange("selectionColor", old, selectionColor);
  673.     }
  674.  
  675.     /**
  676.      * Fetches the current color used to render the 
  677.      * selected text.
  678.      *
  679.      * @return the color
  680.      */
  681.     public Color getSelectedTextColor() {
  682.         return selectedTextColor;
  683.     }
  684.  
  685.     /**
  686.      * Sets the current color used to render the
  687.      * selected text.
  688.      *
  689.      * @param c the color
  690.      * @see #getSelectedTextColor
  691.      * @beaninfo
  692.      *  description: color used to render selected text
  693.      *        bound: true
  694.      *    preferred: true
  695.      */
  696.     public void setSelectedTextColor(Color c) {
  697.         Color old = selectedTextColor;
  698.         selectedTextColor = c;
  699.         firePropertyChange("selectedTextColor", old, selectedTextColor);
  700.     }
  701.  
  702.     /**
  703.      * Fetches the current color used to render the 
  704.      * selected text.
  705.      *
  706.      * @return the color
  707.      */
  708.     public Color getDisabledTextColor() {
  709.         return disabledTextColor;
  710.     }
  711.  
  712.     /**
  713.      * Sets the current color used to render the
  714.      * disabled text.
  715.      *
  716.      * @param c the color
  717.      * @see #getDisabledTextColor
  718.      * @beaninfo
  719.      *  description: color used to render disabled text
  720.      *        bound: true
  721.      *    preferred: true
  722.      */
  723.     public void setDisabledTextColor(Color c) {
  724.         Color old = disabledTextColor;
  725.         disabledTextColor = c;
  726.         firePropertyChange("disabledTextColor", old, disabledTextColor);
  727.     }
  728.  
  729.     /**
  730.      * Replaces the currently selected content with new content
  731.      * represented by the given string.  If there is no selection
  732.      * this amounts to an insert of the given text.  If there
  733.      * is no replacement text this amounts to a removal of the
  734.      * current selection.  
  735.      * <p>
  736.      * This is the method that is used by the default implementation
  737.      * of the action for inserting content that gets bound to the
  738.      * keymap actions.
  739.      * <p>
  740.      * This method is thread safe, although most Swing methods
  741.      * are not. Please see 
  742.      * <A HREF="http://java.sun.com/products/jfc/swingdoc/threads.html">Threads
  743.      * and Swing</A> for more information.     
  744.      *
  745.      * @param content  the content to replace the selection with
  746.      */
  747.     public void replaceSelection(String content) {
  748.         if (! isEditable()) {
  749.             getToolkit().beep();
  750.             return;
  751.         }
  752.         Document doc = getDocument();
  753.         if (doc != null) {
  754.             try {
  755.                 int p0 = Math.min(caret.getDot(), caret.getMark());
  756.                 int p1 = Math.max(caret.getDot(), caret.getMark());
  757.                 if (p0 != p1) {
  758.                     doc.remove(p0, p1 - p0);
  759.                 }
  760.                 if (content != null && content.length() > 0) {
  761.                     doc.insertString(p0, content, null);
  762.                 }
  763.             } catch (BadLocationException e) {
  764.                 getToolkit().beep();
  765.             }
  766.         }
  767.     }
  768.  
  769.     /**
  770.      * Fetches a portion of the text represented by the
  771.      * component.
  772.      *
  773.      * @param offs the offset
  774.      * @param len the length
  775.      * @return the text
  776.      * @exception BadLocationException of the offset or length are invalid
  777.      */
  778.     public String getText(int offs, int len) throws BadLocationException {
  779.         return getDocument().getText(offs, len);
  780.     }
  781.  
  782.     /**
  783.      * Converts the given location in the model to a place in
  784.      * the view coordinate system.
  785.      *
  786.      * @param pos the position
  787.      * @return the coordinates as a rectangle
  788.      * @exception BadLocationException  if the given position does not represent a
  789.      *   valid location in the associated document
  790.      * @see TextUI#modelToView
  791.      */
  792.     public Rectangle modelToView(int pos) throws BadLocationException {
  793.         return getUI().modelToView(pos);
  794.     }
  795.  
  796.     /**
  797.      * Converts the given place in the view coordinate system
  798.      * to the nearest representative location in the model.
  799.      *
  800.      * @param pt the location in the view to translate
  801.      * @return the offset from the start of the document
  802.      * @see TextUI#viewToModel
  803.      */
  804.     public int viewToModel(Point pt) {
  805.         return getUI().viewToModel(pt);
  806.     }
  807.  
  808.     /**
  809.      * Transfers the currently selected range in the associated
  810.      * text model to the system clipboard, removing the contents
  811.      * from the model.  The current selection is reset.
  812.      */
  813.     public void cut() {
  814.         try {
  815.             Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
  816.             int p0 = Math.min(caret.getDot(), caret.getMark());
  817.             int p1 = Math.max(caret.getDot(), caret.getMark());
  818.             if (p0 != p1) {
  819.                 Document doc = getDocument();
  820.                 String srcData = doc.getText(p0, p1 - p0);
  821.                 StringSelection contents = new StringSelection(srcData);
  822.                 clipboard.setContents(contents, defaultClipboardOwner);
  823.                 doc.remove(p0, p1 - p0);
  824.             }
  825.         } catch (BadLocationException e) {
  826.         }
  827.     }
  828.  
  829.     /**
  830.      * Transfers the currently selected range in the associated
  831.      * text model to the system clipboard, leaving the contents
  832.      * in the text model.  The current selection is remains intact.
  833.      */
  834.     public void copy() {
  835.         try {
  836.             Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
  837.             int p0 = Math.min(caret.getDot(), caret.getMark());
  838.             int p1 = Math.max(caret.getDot(), caret.getMark());
  839.             if (p0 != p1) {
  840.                 Document doc = getDocument();
  841.                 String srcData = doc.getText(p0, p1 - p0);
  842.                 StringSelection contents = new StringSelection(srcData);
  843.                 clipboard.setContents(contents, defaultClipboardOwner);
  844.             }
  845.         } catch (BadLocationException e) {
  846.         }
  847.     }
  848.     
  849.     /**
  850.      * Transfers the contents of the system clipboard into the
  851.      * associated text model.  If there is a selection in the
  852.      * associated view, it is replaced with the contents of the
  853.      * clipboard.  If there is no selection, the clipboard contents
  854.      * are inserted in front of the current insert position in 
  855.      * the associated view.
  856.      * @see #replaceSelection
  857.      */ 
  858.     public void paste() {
  859.         Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
  860.         Transferable content = clipboard.getContents(this);
  861.         if (content != null) {
  862.             try {
  863.                 String dstData = (String)(content.getTransferData(DataFlavor.stringFlavor));
  864.                 replaceSelection(dstData);
  865.             } catch (Exception e) {
  866.                 System.err.println("Couldn't get clipboard contents in format: "+
  867.                                    DataFlavor.stringFlavor.getHumanPresentableName());         
  868.             }
  869.         }
  870.     }
  871.  
  872.     /**
  873.      * Moves the caret to a new position, leaving behind a
  874.      * mark defined by the last time setCaretPosition was
  875.      * called.  This forms a selection.
  876.      *
  877.      * @param pos the position
  878.      * @see #setCaretPosition
  879.      */
  880.     public void moveCaretPosition(int pos) {
  881.         caret.moveDot(pos);
  882.     }
  883.  
  884.     /**
  885.      * The bound property name for the focus accelerator.
  886.      */ 
  887.     public static final String FOCUS_ACCELERATOR_KEY = "focusAcceleratorKey";
  888.  
  889.     /**
  890.      * Sets the key accelerator that will cause the receiving text
  891.      * component to get the focus.  The accelerator will be the 
  892.      * key combination of the <em>alt</em> key and the character
  893.      * given.  By default, there is no focus accelerator key.
  894.      *
  895.      * @param aKey the key
  896.      * @see getFocusAccelerator
  897.      * @beaninfo
  898.      *  description: accelerator character used to grab focus
  899.      *        bound: true
  900.      */
  901.     public void setFocusAccelerator(char aKey) {
  902.     aKey = Character.toUpperCase(aKey);
  903.     KeyStroke[] keyStrokes = getRegisteredKeyStrokes();
  904.     int i,c;
  905.     for(i=0,c=keyStrokes.length;i<c;i++) {
  906.         if(getActionForKeyStroke(keyStrokes[i]) == focusAction) {
  907.         if(keyStrokes[i].getKeyChar() == aKey)
  908.             return;
  909.         else
  910.             unregisterKeyboardAction(keyStrokes[i]);
  911.         break;
  912.         }
  913.     }
  914.     if(aKey != '\0') {
  915.         registerKeyboardAction(focusAction,KeyStroke.getKeyStroke(aKey,ActionEvent.ALT_MASK),
  916.                    JComponent.WHEN_IN_FOCUSED_WINDOW);
  917.     }
  918.         char old = focusAccelerator;
  919.         focusAccelerator = aKey;
  920.         firePropertyChange(FOCUS_ACCELERATOR_KEY, old, focusAccelerator);
  921.     }
  922.  
  923.     /**
  924.      * Returns the key accelerator that will cause the receiving
  925.      * text component to get the focus.  Return '\0' if no focus
  926.      * accelerator has been set.
  927.      *
  928.      * @return the key
  929.      */
  930.     public char getFocusAccelerator() {
  931.         return focusAccelerator;
  932.     }
  933.  
  934.     /**
  935.      * Initialize from a stream.  This creates a
  936.      * model of the type appropriate for the component
  937.      * and initializes the model from the stream.
  938.      * By default this will load the model as plain
  939.      * text.
  940.      *
  941.      * @param in The stream to read from
  942.      * @param desc An object describing the stream.  This
  943.      *   might be a string, a File, a URL, etc.  Some kinds
  944.      *   of documents (such as html for example) might be
  945.      *   able to make use of this information.
  946.      * @exception IOException as thrown by the stream being
  947.      *  used to initialize.
  948.      * @see EditorKit#createDefaultDocument
  949.      * @see #setDocument
  950.      * @see PlainDocument
  951.      */
  952.     public void read(Reader in, Object desc) throws IOException {
  953.         EditorKit kit = getUI().getEditorKit();
  954.         Document doc = kit.createDefaultDocument();
  955.         if (desc != null) {
  956.             doc.putProperty(Document.StreamDescriptionProperty, desc);
  957.         }
  958.         try {
  959.             kit.read(in, doc, 0);
  960.             setDocument(doc);
  961.         } catch (BadLocationException e) {
  962.             throw new IOException(e.getMessage());
  963.         }
  964.     }
  965.  
  966.     /**
  967.      * Stores the contents of the model into the given
  968.      * stream.  By default this will store the model as plain
  969.      * text.
  970.      *
  971.      * @param out the output stream
  972.      * @exception IOException on any I/O error
  973.      */
  974.     public void write(Writer out) throws IOException {
  975.         Document doc = getDocument();
  976.         try {
  977.             getUI().getEditorKit().write(out, doc, 0, doc.getLength());
  978.         } catch (BadLocationException e) {
  979.             throw new IOException(e.getMessage());
  980.         }
  981.     }
  982.  
  983.     // --- java.awt.Component methods ----------------------------
  984.  
  985.     /**
  986.      * Returns true if the focus can be traversed.
  987.      *
  988.      * @return true if the focus is traversable
  989.      */
  990.     public boolean isFocusTraversable() {
  991.         return isEnabled();
  992.     }
  993.  
  994.     /**
  995.      * Process any key events that the component itself 
  996.      * recognizes.  This will be called after the focus
  997.      * manager and any interested listeners have been
  998.      * given a chance to steal away the event.  This 
  999.      * method will only be called is the event has not
  1000.      * yet been consumed.  This method is called prior
  1001.      * to the keyboard UI logic.
  1002.      * <p>
  1003.      * This is implemented to do nothing.  Subclasses would
  1004.      * normally override this method if they process some
  1005.      * key events themselves.  If the event is processed,
  1006.      * it should be consumed.
  1007.      *
  1008.      * @param e the event
  1009.      */
  1010.     protected void processComponentKeyEvent(KeyEvent e) {
  1011.     int id = e.getID();
  1012.     switch(id) {
  1013.     case KeyEvent.KEY_TYPED:
  1014.         if (mapEventToAction(e) == false) {
  1015.         // default behavior is to input translated
  1016.         // characters as content if the character
  1017.         // hasn't been mapped in the keymap.
  1018.         Keymap binding = getKeymap();
  1019.             if (binding != null) {
  1020.             Action a = binding.getDefaultAction();
  1021.             if (a != null) {
  1022.                 ActionEvent ae = new ActionEvent(this, 
  1023.                                  ActionEvent.ACTION_PERFORMED, 
  1024.                                  String.valueOf(e.getKeyChar()),
  1025.                                  e.getModifiers());
  1026.                 a.actionPerformed(ae);
  1027.                 e.consume();
  1028.             }
  1029.             }
  1030.         }
  1031.         break;
  1032.     case KeyEvent.KEY_PRESSED:
  1033.         mapEventToAction(e);
  1034.         break;
  1035.     case KeyEvent.KEY_RELEASED:
  1036.         mapEventToAction(e);
  1037.         break;
  1038.     }
  1039.     } 
  1040.  
  1041.     // --- java.awt.TextComponent methods ------------------------
  1042.  
  1043.     /**
  1044.      * Sets the position of the text insertion caret for the TextComponent.
  1045.      * Note that the caret tracks change, so this may move if the underlying
  1046.      * text of the component is changed.
  1047.      *
  1048.      * @param position the position
  1049.      * @exception IllegalArgumentException if position is less than 0 
  1050.      *  or greater than the length of the associated document
  1051.      * @beaninfo
  1052.      * description: the caret position
  1053.      */
  1054.     public void setCaretPosition(int position) {
  1055.         Document doc = getDocument();
  1056.         if (doc != null) {
  1057.             caret.setDot(position);
  1058.         }
  1059.     }
  1060.  
  1061.     /**
  1062.      * Returns the position of the text insertion caret for the 
  1063.      * text component.
  1064.      *
  1065.      * @return the position of the text insertion caret for the
  1066.      *  text component
  1067.      */
  1068.     public int getCaretPosition() {
  1069.         return caret.getDot();
  1070.     }
  1071.  
  1072.     /**
  1073.      * Sets the text of this TextComponent to the specified text.
  1074.      * <p>
  1075.      * This method is thread safe, although most Swing methods
  1076.      * are not. Please see 
  1077.      * <A HREF="http://java.sun.com/products/jfc/swingdoc/threads.html">Threads
  1078.      * and Swing</A> for more information.     
  1079.      *
  1080.      * @param t the new text to be set
  1081.      * @see #getText
  1082.      * @beaninfo
  1083.      * description: the text of this component
  1084.      */
  1085.     public void setText(String t) {
  1086.         try {
  1087.             Document doc = getDocument();
  1088.             doc.remove(0, doc.getLength());
  1089.             doc.insertString(0, t, null);
  1090.         } catch (BadLocationException e) {
  1091.             getToolkit().beep();
  1092.         }
  1093.     }
  1094.  
  1095.     /**
  1096.      * Returns the text contained in this TextComponent.
  1097.      *
  1098.      * @return the text
  1099.      * @see #setText
  1100.      */
  1101.     public String getText() {
  1102.         Document doc = getDocument();
  1103.         String txt;
  1104.         try {
  1105.             txt = doc.getText(0, doc.getLength());
  1106.         } catch (BadLocationException e) {
  1107.             txt = null;
  1108.         }
  1109.         return txt;
  1110.     }
  1111.  
  1112.     /**
  1113.      * Returns the selected text contained in this TextComponent.
  1114.      *
  1115.      * @return the text
  1116.      * @exception IllegalArgumentException if the selection doesn't
  1117.      *  have a valid mapping into the document for some reason
  1118.      * @see #setText
  1119.      */
  1120.     public String getSelectedText() {
  1121.         String txt = null;
  1122.         int p0 = Math.min(caret.getDot(), caret.getMark());
  1123.         int p1 = Math.max(caret.getDot(), caret.getMark());
  1124.         if (p0 != p1) {
  1125.             try {
  1126.                 Document doc = getDocument();
  1127.                 txt = doc.getText(p0, p1 - p0);
  1128.             } catch (BadLocationException e) {
  1129.                 throw illegalDocumentPosition;
  1130.             }
  1131.         }
  1132.         return txt;
  1133.     }
  1134.  
  1135.     /**
  1136.      * Returns the boolean indicating whether this TextComponent is
  1137.      * editable or not.
  1138.      *
  1139.      * @return the boolean value
  1140.      * @see #setEditable
  1141.      */
  1142.     public boolean isEditable() {
  1143.         return editable;
  1144.     }
  1145.  
  1146.     /**
  1147.      * Sets the specified boolean to indicate whether or not this
  1148.      * TextComponent should be editable.
  1149.      *
  1150.      * @param b the boolean to be set
  1151.      * @see #isEditable
  1152.      * @beaninfo
  1153.      * description: specifies if the text can be edited
  1154.      */
  1155.     public void setEditable(boolean b) {
  1156.         editable = b;
  1157.     }
  1158.  
  1159.     /**
  1160.      * Returns the selected text's start position.
  1161.      *
  1162.      * @return the start position
  1163.      */
  1164.     public int getSelectionStart() {
  1165.         int start = Math.min(caret.getDot(), caret.getMark());
  1166.         return start;
  1167.     }
  1168.  
  1169.     /**
  1170.      * Sets the selection start to the specified position.  The new
  1171.      * starting point is constrained to be before or at the current
  1172.      * selection end.
  1173.      * <p>
  1174.      * This is available for backward compatiblitity to code 
  1175.      * that called this method on java.awt.TextComponent.  This is
  1176.      * implemented to forward to the Caret implementation which
  1177.      * is where the actual selection is maintained.
  1178.      *
  1179.      * @param selectionStart the start position of the text
  1180.      * @beaninfo
  1181.      * description: starting location of the selection.
  1182.      */
  1183.     public void setSelectionStart(int selectionStart) {
  1184.         /* Route through select method to enforce consistent policy
  1185.          * between selectionStart and selectionEnd.
  1186.          */
  1187.         select(selectionStart, getSelectionEnd());
  1188.     }
  1189.  
  1190.     /**
  1191.      * Returns the selected text's end position.
  1192.      *
  1193.      * @return the end position
  1194.      */
  1195.     public int getSelectionEnd() {
  1196.         int end = Math.max(caret.getDot(), caret.getMark());
  1197.         return end;
  1198.     }
  1199.  
  1200.     /**
  1201.      * Sets the selection end to the specified position.  The new
  1202.      * end point is constrained to be at or after the current
  1203.      * selection start.
  1204.      * <p>
  1205.      * This is available for backward compatiblitity to code 
  1206.      * that called this method on java.awt.TextComponent.  This is
  1207.      * implemented to forward to the Caret implementation which
  1208.      * is where the actual selection is maintained.
  1209.      *
  1210.      * @param selectionEnd the start position of the text
  1211.      * @beaninfo
  1212.      * description: ending location of the selection.
  1213.      */
  1214.     public void setSelectionEnd(int selectionEnd) {
  1215.         /* Route through select method to enforce consistent policy
  1216.          * between selectionStart and selectionEnd.
  1217.          */
  1218.         select(getSelectionStart(), selectionEnd);
  1219.     }
  1220.     
  1221.     /**
  1222.      * Selects the text found between the specified start and end 
  1223.      * locations.  This call is provided for backward compatibility.
  1224.      * It is routed to a call to setCaretPosition
  1225.      * followed by a call to moveCaretPostion.  The preferred way
  1226.      * to manage selection is by calling those methods directly.
  1227.      *
  1228.      * @param selectionStart the start position of the text
  1229.      * @param selectionEnd the end position of the text
  1230.      * @see setCaretPosition
  1231.      * @see moveCaretPosition
  1232.      */
  1233.     public void select(int selectionStart, int selectionEnd) {
  1234.         setCaretPosition(selectionStart);
  1235.         moveCaretPosition(selectionEnd);
  1236.     }
  1237.  
  1238.     /**
  1239.      * Selects all the text in the TextComponent.
  1240.      */
  1241.     public void selectAll() {
  1242.         Document doc = getDocument();
  1243.         if (doc != null) {
  1244.             setCaretPosition(0);
  1245.             moveCaretPosition(doc.getLength());
  1246.         }
  1247.     }
  1248.  
  1249.     // --- Scrollable methods ---------------------------------------------
  1250.  
  1251.     /**
  1252.      * Returns the preferred size of the viewport for a view component.
  1253.      * This is implemented to do the default behavior of returning
  1254.      * the preferred size of the component.
  1255.      * 
  1256.      * @return The preferredSize of a JViewport whose view is this Scrollable.
  1257.      */
  1258.     public Dimension getPreferredScrollableViewportSize() {
  1259.         return getPreferredSize();
  1260.     }
  1261.  
  1262.  
  1263.     /**
  1264.      * Components that display logical rows or columns should compute
  1265.      * the scroll increment that will completely expose one new row
  1266.      * or column, depending on the value of orientation.  Ideally, 
  1267.      * components should handle a partially exposed row or column by 
  1268.      * returning the distance required to completely expose the item.
  1269.      * <p>
  1270.      * The default implementation of this is to simply return 10% of
  1271.      * the visible area.  Subclasses are likely to be able to provide
  1272.      * a much more reasonable value.
  1273.      * 
  1274.      * @param visibleRect The view area visible within the viewport
  1275.      * @param orientation Either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
  1276.      * @param direction Less than zero to scroll up/left, greater than zero for down/right.
  1277.      * @return The "unit" increment for scrolling in the specified direction
  1278.      * @see JScrollBar#setUnitIncrement
  1279.      */
  1280.     public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
  1281.         switch(orientation) {
  1282.         case SwingConstants.VERTICAL:
  1283.             return visibleRect.height / 10;
  1284.         case SwingConstants.HORIZONTAL:
  1285.             return visibleRect.width / 10;
  1286.         default:
  1287.             throw new IllegalArgumentException("Invalid orientation: " + orientation);
  1288.         }
  1289.     }
  1290.  
  1291.  
  1292.     /**
  1293.      * Components that display logical rows or columns should compute
  1294.      * the scroll increment that will completely expose one block
  1295.      * of rows or columns, depending on the value of orientation. 
  1296.      * <p>
  1297.      * The default implementation of this is to simply return the visible
  1298.      * area.  Subclasses will likely be able to provide a much more 
  1299.      * reasonable value.
  1300.      * 
  1301.      * @param visibleRect The view area visible within the viewport
  1302.      * @param orientation Either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
  1303.      * @param direction Less than zero to scroll up/left, greater than zero for down/right.
  1304.      * @return The "block" increment for scrolling in the specified direction.
  1305.      * @see JScrollBar#setBlockIncrement
  1306.      */
  1307.     public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
  1308.         switch(orientation) {
  1309.         case SwingConstants.VERTICAL:
  1310.             return visibleRect.height;
  1311.         case SwingConstants.HORIZONTAL:
  1312.             return visibleRect.width;
  1313.         default:
  1314.             throw new IllegalArgumentException("Invalid orientation: " + orientation);
  1315.         }
  1316.     }  
  1317.     
  1318.  
  1319.     /**
  1320.      * Return true if a viewport should always force the width of this 
  1321.      * Scrollable to match the width of the viewport.  For example a noraml 
  1322.      * text view that supported line wrapping would return true here, since it
  1323.      * would be undesirable for wrapped lines to disappear beyond the right
  1324.      * edge of the viewport.  Note that returning true for a Scrollable
  1325.      * whose ancestor is a JScrollPane effectively disables horizontal
  1326.      * scrolling.
  1327.      * <p>
  1328.      * Scrolling containers, like JViewport, will use this method each 
  1329.      * time they are validated.  
  1330.      * 
  1331.      * @return True if a viewport should force the Scrollables width to match its own.
  1332.      */
  1333.     public boolean getScrollableTracksViewportWidth() {
  1334.         return false;
  1335.     }
  1336.  
  1337.     /**
  1338.      * Return true if a viewport should always force the height of this 
  1339.      * Scrollable to match the height of the viewport.  For example a 
  1340.      * columnar text view that flowed text in left to right columns 
  1341.      * could effectively disable vertical scrolling by returning
  1342.      * true here.
  1343.      * <p>
  1344.      * Scrolling containers, like JViewport, will use this method each 
  1345.      * time they are validated.  
  1346.      * 
  1347.      * @return True if a viewport should force the Scrollables height to match its own.
  1348.      */
  1349.     public boolean getScrollableTracksViewportHeight() {
  1350.         return false;
  1351.     }
  1352.  
  1353. /////////////////
  1354. // Accessibility support
  1355. ////////////////
  1356.  
  1357.  
  1358.     /**
  1359.      * Get the AccessibleContext associated with this JComponent
  1360.      *
  1361.      * @return the AccessibleContext of this JComponent
  1362.      */
  1363.     public AccessibleContext getAccessibleContext() {
  1364.         if (accessibleContext == null) {
  1365.             accessibleContext = new AccessibleJTextComponent();
  1366.         }
  1367.         return accessibleContext;
  1368.     }
  1369.  
  1370.     /**
  1371.      * Accessibility implementation for JTextComponent
  1372.      * <p>
  1373.      * Warning: serialized objects of this class will not be compatible with
  1374.      * future swing releases.  The current serialization support is appropriate
  1375.      * for short term storage or RMI between Swing1.0 applications.  It will
  1376.      * not be possible to load serialized Swing1.0 objects with future releases
  1377.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  1378.      * baseline for the serialized form of Swing objects.
  1379.      */
  1380.     public class AccessibleJTextComponent extends AccessibleJComponent 
  1381.     implements AccessibleText, CaretListener, DocumentListener {
  1382.  
  1383.     int caretPos;
  1384.  
  1385.     /**
  1386.      * Construct an AccessibleJTextComponent
  1387.      */
  1388.         public AccessibleJTextComponent() {
  1389.             Document doc = JTextComponent.this.getDocument();
  1390.             if (doc != null) {
  1391.                 doc.addDocumentListener(this);
  1392.             }
  1393.             JTextComponent.this.addCaretListener(this);
  1394.         caretPos = getCaretPosition();
  1395.         }
  1396.  
  1397.     /**
  1398.      * Handle caret updates (fire appropriate property change event)
  1399.      *
  1400.      * @param e the CaretEvent
  1401.      */
  1402.         public void caretUpdate(CaretEvent e) {
  1403.             int dot = e.getDot();
  1404.         int mark = e.getMark();
  1405.             if (caretPos != dot) {
  1406.                 // the caret moved
  1407.         firePropertyChange(ACCESSIBLE_CARET_PROPERTY,
  1408.                     new Integer(caretPos), new Integer(dot));
  1409.         caretPos = dot;
  1410.             }
  1411.             if (mark != dot) {
  1412.                 // there is a selection
  1413.         firePropertyChange(ACCESSIBLE_SELECTION_PROPERTY, null, 
  1414.             getSelectedText());
  1415.         }
  1416.         }
  1417.  
  1418.         // DocumentListener methods
  1419.  
  1420.     /**
  1421.      * Handle document insert (fire appropriate property change event)
  1422.      *
  1423.      * @param e the DocumentEvent
  1424.      */
  1425.         public void insertUpdate(DocumentEvent e) {
  1426.             Caret c = JTextComponent.this.getCaret();
  1427.             Integer dot = new Integer(c.getDot());
  1428.         firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, dot);
  1429.         }
  1430.  
  1431.     /**
  1432.      * Handle document remove (fire appropriate property change event)
  1433.      *
  1434.      * @param e the DocumentEvent
  1435.      */
  1436.         public void removeUpdate(DocumentEvent e) {
  1437.             Caret c = JTextComponent.this.getCaret();
  1438.             Integer dot = new Integer(c.getDot());
  1439.         firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, dot);
  1440.         }
  1441.  
  1442.     /**
  1443.      * Handle document remove (fire appropriate property change event)
  1444.      *
  1445.      * @param e the DocumentEvent
  1446.      */
  1447.         public void changedUpdate(DocumentEvent e) {
  1448.             Caret c = JTextComponent.this.getCaret();
  1449.             Integer dot = new Integer(c.getDot());
  1450.         firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, dot);
  1451.         }
  1452.  
  1453.         /**
  1454.      * Get the state set of the JTextComponent.  
  1455.      * The AccessibleStateSet of an object is composed of a set of 
  1456.      * unique AccessibleState's.  A change in the AccessibleStateSet 
  1457.      * of an object will cause a PropertyChangeEvent to
  1458.      * be fired for the ACCESSIBLE_STATE_PROPERTY property.
  1459.      *
  1460.      * @return an instance of AccessibleStateSet containing the
  1461.      * current state set of the object
  1462.      * @see AccessibleStateSet
  1463.      * @see AccessibleState
  1464.      * @see #addPropertyChangeListener
  1465.      */
  1466.     public AccessibleStateSet getAccessibleStateSet() {
  1467.         AccessibleStateSet states = super.getAccessibleStateSet();
  1468.         if (JTextComponent.this.isEditable()) {
  1469.             states.add(AccessibleState.EDITABLE);
  1470.         }
  1471.         return states;
  1472.     }
  1473.  
  1474.  
  1475.     /**
  1476.      * Gets the role of this object.
  1477.      *
  1478.      * @return an instance of AccessibleRole describing the role of the 
  1479.      * object
  1480.      * @see AccessibleRole
  1481.      */
  1482.     public AccessibleRole getAccessibleRole() {
  1483.         return AccessibleRole.TEXT;
  1484.     }
  1485.  
  1486.         /**
  1487.          * Gets the AccessibleText interface associated with this object
  1488.          *
  1489.          * @return an instance of AccessibleText 
  1490.          */
  1491.         public AccessibleText getAccessibleText() {
  1492.             return this;
  1493.         }
  1494.  
  1495.  
  1496.         // --- interface AccessibleText methods ------------------------
  1497.  
  1498.         /**
  1499.          * Many of these methods are just convenience methods; they
  1500.          * just call the equivalent on the parent
  1501.          */
  1502.  
  1503.     /**
  1504.      * Given a point in local coordinates, return the zero-based index
  1505.      * of the character under that Point.  If the point is invalid,
  1506.      * this method returns -1.
  1507.      *
  1508.      * @param p the Point in local coordinates
  1509.      * @return the zero-based index of the character under Point p.
  1510.      */
  1511.     public int getIndexAtPoint(Point p) {
  1512.         if (p == null) {
  1513.         return -1;
  1514.         }
  1515.             return JTextComponent.this.viewToModel(p);
  1516.         }
  1517.  
  1518.     /**
  1519.      * Determine the bounding box of the character at the given
  1520.      * index into the string.  The bounds are returned in local
  1521.      * coordinates.  If the index is invalid an empty rectangle is returned.
  1522.      *
  1523.      * @param i the index into the String
  1524.      * @return the screen coordinates of the character's the bounding box
  1525.      */
  1526.         public Rectangle getCharacterBounds(int i) {
  1527.             if (i < 0 || i > model.getLength()-1) {
  1528.                 return null;
  1529.             }
  1530.             Rectangle rect;
  1531.             try {
  1532.                 rect = modelToView(i);
  1533.             } catch (BadLocationException e) {
  1534.                 rect = null;
  1535.             }
  1536.             return rect;
  1537.         }
  1538.  
  1539.     /**
  1540.      * Return the number of characters (valid indicies)
  1541.      *
  1542.      * @return the number of characters
  1543.      */
  1544.         public int getCharCount() {
  1545.             return model.getLength();
  1546.         }
  1547.  
  1548.     /**
  1549.      * Return the zero-based offset of the caret.
  1550.      *
  1551.      * Note: That to the right of the caret will have the same index
  1552.      * value as the offset (the caret is between two characters).
  1553.      * @return the zero-based offset of the caret.
  1554.      */
  1555.         public int getCaretPosition() {
  1556.             return JTextComponent.this.getCaretPosition();
  1557.         }
  1558.  
  1559.     /**
  1560.      * Return the AttributeSet for a given character (at a given index)
  1561.      *
  1562.      * @param i the zero-based index into the text
  1563.      * @return the AttributeSet of the character
  1564.      */
  1565.         public AttributeSet getCharacterAttribute(int i) {
  1566.             Element e = null;
  1567.             for (e = model.getDefaultRootElement(); ! e.isLeaf(); ) {
  1568.                 int index = e.getElementIndex(i);
  1569.                 e = e.getElement(index);
  1570.             }
  1571.             return e.getAttributes();
  1572.         }
  1573.  
  1574.     /**
  1575.      * Returns the start offset within the selected text.
  1576.      * If there is no selection, but there is
  1577.      * a caret, the start and end offsets will be the same.
  1578.      *
  1579.      * @return the index into the text of the start of the selection
  1580.      */
  1581.         public int getSelectionStart() {
  1582.             return JTextComponent.this.getSelectionStart();
  1583.         }
  1584.  
  1585.     /**
  1586.      * Returns the end offset within the selected text.
  1587.      * If there is no selection, but there is
  1588.      * a caret, the start and end offsets will be the same.
  1589.      *
  1590.      * @return the index into teh text of the end of the selection
  1591.      */
  1592.         public int getSelectionEnd() {
  1593.             return JTextComponent.this.getSelectionEnd();
  1594.         }
  1595.  
  1596.     /**
  1597.      * Returns the portion of the text that is selected.
  1598.      *
  1599.      * @return the portion of the text that is selected
  1600.      */
  1601.         public String getSelectedText() {
  1602.             return JTextComponent.this.getSelectedText();
  1603.         }
  1604.  
  1605.         /**
  1606.          * Return the String at a given index. 
  1607.          *
  1608.          * @param part the CHARACTER, WORD, or SENTENCE to retrieve
  1609.          * @param index an index within the text
  1610.          * @return the letter, word, or sentence
  1611.          */
  1612.         public String getAtIndex(int part, int index) {
  1613.             if (index < 0 || index > model.getLength()-1) {
  1614.                 return null;
  1615.             }
  1616.             switch (part) {
  1617.             case AccessibleText.CHARACTER:
  1618.                 try {
  1619.                     return model.getText(index, 1);
  1620.                 } catch (BadLocationException e) {
  1621.                     return null;
  1622.                 }
  1623.             case AccessibleText.WORD:
  1624.                 try {
  1625.                     String s = model.getText(0, model.getLength());
  1626.                     BreakIterator words = BreakIterator.getWordInstance();
  1627.                     words.setText(s);
  1628.                     int end = words.following(index);
  1629.                     return s.substring(words.previous(), end);
  1630.                 } catch (BadLocationException e) {
  1631.                     return null;
  1632.                 }
  1633.             case AccessibleText.SENTENCE:
  1634.                 try {
  1635.                     String s = model.getText(0, model.getLength());
  1636.                     BreakIterator sentence = BreakIterator.getSentenceInstance();
  1637.                     sentence.setText(s);
  1638.                     int end = sentence.following(index);
  1639.                     return s.substring(sentence.previous(), end);
  1640.                 } catch (BadLocationException e) {
  1641.                     return null;
  1642.                 }
  1643.             default:
  1644.                 return null;
  1645.             }
  1646.         }
  1647.  
  1648.         /**
  1649.          * Return the String after a given index.
  1650.          *
  1651.          * @param part the CHARACTER, WORD, or SENTENCE to retrieve
  1652.          * @param index an index within the text
  1653.          * @return the letter, word, or sentence
  1654.          */
  1655.         public String getAfterIndex(int part, int index) {
  1656.             if (index < 0 || index > model.getLength()-1) {
  1657.                 return null;
  1658.             }
  1659.             switch (part) {
  1660.             case AccessibleText.CHARACTER:
  1661.                 try {
  1662.                     return model.getText(index+1, 1);
  1663.                 } catch (BadLocationException e) {
  1664.                     return null;
  1665.                 }
  1666.             case AccessibleText.WORD:
  1667.                 try {
  1668.                     String s = model.getText(0, model.getLength());
  1669.                     BreakIterator words = BreakIterator.getWordInstance();
  1670.                     words.setText(s);
  1671.                     int start = words.following(index);
  1672.                     return s.substring(start, words.following(start));
  1673.                 } catch (BadLocationException e) {
  1674.                     return null;
  1675.                 }
  1676.             case AccessibleText.SENTENCE:
  1677.                 try {
  1678.                     String s = model.getText(0, model.getLength());
  1679.                     BreakIterator sentence = BreakIterator.getSentenceInstance();
  1680.                     sentence.setText(s);
  1681.                     int start = sentence.following(index);
  1682.                     return s.substring(start, sentence.following(start));
  1683.                 } catch (BadLocationException e) {
  1684.                     return null;
  1685.                 }
  1686.             default:
  1687.                 return null;
  1688.             }
  1689.         }
  1690.  
  1691.  
  1692.         /**
  1693.          * Return the String before a given index.
  1694.          *
  1695.          * @param part the CHARACTER, WORD, or SENTENCE to retrieve
  1696.          * @param index an index within the text
  1697.          * @return the letter, word, or sentence
  1698.          */
  1699.         public String getBeforeIndex(int part, int index) {
  1700.             if (index < 0 || index > model.getLength()-1) {
  1701.                 return null;
  1702.             }
  1703.             switch (part) {
  1704.             case AccessibleText.CHARACTER:
  1705.                 try {
  1706.                     return model.getText(index-1, 1);
  1707.                 } catch (BadLocationException e) {
  1708.                     return null;
  1709.                 }
  1710.             case AccessibleText.WORD:
  1711.                 try {
  1712.                     String s = model.getText(0, model.getLength());
  1713.                     BreakIterator words = BreakIterator.getWordInstance();
  1714.                     words.setText(s);
  1715.                     int end = words.next(index);
  1716.                     end = words.previous();
  1717.                     return s.substring(words.previous(), end);
  1718.                 } catch (BadLocationException e) {
  1719.                     return null;
  1720.                 }
  1721.             case AccessibleText.SENTENCE:
  1722.                 try {
  1723.                     String s = model.getText(0, model.getLength());
  1724.                     BreakIterator sentence = BreakIterator.getSentenceInstance();
  1725.                     sentence.setText(s);
  1726.                     int end = sentence.next(index);
  1727.                     end = sentence.previous();
  1728.                     return s.substring(sentence.previous(), end);
  1729.                 } catch (BadLocationException e) {
  1730.                     return null;
  1731.                 }
  1732.             default:
  1733.                 return null;
  1734.             }
  1735.         }
  1736.  
  1737.     }
  1738.  
  1739.  
  1740.     // --- serialization ---------------------------------------------
  1741.  
  1742.     private void readObject(ObjectInputStream s)
  1743.       throws ClassNotFoundException, IOException 
  1744.     {
  1745.         s.defaultReadObject();
  1746.         caretEvent = new MutableCaretEvent(this);
  1747.         addMouseListener(caretEvent);
  1748.     addFocusListener(caretEvent);
  1749.  
  1750.         // PENDING(prinz)
  1751.         // This should really be updateUI(), but the ui
  1752.         // is currently being serialized so we'll use it.
  1753.         getUI().installUI(this);
  1754.     }
  1755.  
  1756.     // --- member variables ----------------------------------
  1757.  
  1758.     /**
  1759.      * The document model.
  1760.      */
  1761.     private Document model;
  1762.  
  1763.     /**
  1764.      * The caret used to display the insert position
  1765.      * and navigate throught the document. 
  1766.      *
  1767.      * PENDING(prinz)  
  1768.      * This should be serializable, default installed
  1769.      * by UI.
  1770.      */
  1771.     private transient Caret caret;
  1772.  
  1773.     /**
  1774.      * The object responsible for managing highlights.
  1775.      *
  1776.      * PENDING(prinz)  
  1777.      * This should be serializable, default installed
  1778.      * by UI.
  1779.      */
  1780.     private transient Highlighter highlighter;
  1781.  
  1782.     /**
  1783.      * The current key bindings in effect.
  1784.      *
  1785.      * PENDING(prinz)  
  1786.      * This should be serializable, default installed
  1787.      * by UI.
  1788.      */
  1789.     private transient Keymap keymap;
  1790.  
  1791.     /**
  1792.      * is the component opaque?
  1793.      */
  1794.     private boolean opaque;
  1795.  
  1796.     private transient MutableCaretEvent caretEvent;
  1797.     private Color caretColor;
  1798.     private Color selectionColor;
  1799.     private Color selectedTextColor;
  1800.     private Color disabledTextColor;
  1801.     private boolean editable;
  1802.     private Insets margin;
  1803.     private char focusAccelerator;
  1804.     private Action focusAction = new FocusAction();
  1805.  
  1806.     private static ClipboardOwner defaultClipboardOwner = new ClipboardObserver();
  1807.     static final IllegalArgumentException illegalDocumentPosition =
  1808.         new IllegalArgumentException("Illegal document position");
  1809.  
  1810.     static class ClipboardObserver implements ClipboardOwner {
  1811.  
  1812.         public void lostOwnership(Clipboard clipboard, Transferable contents) {
  1813.         }
  1814.     }
  1815.  
  1816.     /**
  1817.      * package level access to focused text component
  1818.      * so that JTextAction implementations can be 
  1819.      * reused across JTextComponent implementations.
  1820.      */
  1821.     static final JTextComponent getFocusedComponent() {
  1822.     return focusedComponent;
  1823.     }
  1824.  
  1825.     private static Hashtable keymapTable = null;
  1826.     private JTextComponent editor;
  1827.     private static JTextComponent focusedComponent;
  1828.  
  1829.     static class DefaultKeymap implements Keymap {
  1830.  
  1831.     DefaultKeymap(String nm, Keymap parent) {
  1832.         this.nm = nm; 
  1833.         this.parent = parent;
  1834.         bindings = new Hashtable();
  1835.     }
  1836.  
  1837.     /**
  1838.      * Fetch the default action to fire if a 
  1839.      * key is typed (ie a KEY_TYPED KeyEvent is received)
  1840.      * and there is no binding for it.  Typically this
  1841.      * would be some action that inserts text so that 
  1842.      * the keymap doesn't require an action for each 
  1843.      * possible key.
  1844.      */
  1845.         public Action getDefaultAction() {
  1846.         if (defaultAction != null) {
  1847.         return defaultAction;
  1848.         }
  1849.         return (parent != null) ? parent.getDefaultAction() : null;
  1850.     }
  1851.  
  1852.     /**
  1853.      * Set the default action to fire if a key is typed.
  1854.      */
  1855.         public void setDefaultAction(Action a) {
  1856.         defaultAction = a;
  1857.     }
  1858.  
  1859.         public String getName() {
  1860.         return nm;
  1861.     }
  1862.  
  1863.         public Action getAction(KeyStroke key) {
  1864.         Action a = (Action) bindings.get(key);
  1865.         if ((a == null) && (parent != null)) {
  1866.         a = parent.getAction(key);
  1867.         }
  1868.         return a;
  1869.     }
  1870.  
  1871.         public KeyStroke[] getBoundKeyStrokes() {
  1872.         KeyStroke[] keys = new KeyStroke[bindings.size()];
  1873.         int i = 0;
  1874.         for (Enumeration e = bindings.keys() ; e.hasMoreElements() ;) {
  1875.         keys[i++] = (KeyStroke) e.nextElement();
  1876.         }
  1877.         return keys;
  1878.     } 
  1879.  
  1880.         public Action[] getBoundActions() {
  1881.         Action[] actions = new Action[bindings.size()];
  1882.         int i = 0;
  1883.         for (Enumeration e = bindings.elements() ; e.hasMoreElements() ;) {
  1884.         actions[i++] = (Action) e.nextElement();
  1885.         }
  1886.         return actions;
  1887.     } 
  1888.  
  1889.         public KeyStroke[] getKeyStrokesForAction(Action a) {
  1890.         // TBD
  1891.         return null;
  1892.     }
  1893.  
  1894.         public boolean isLocallyDefined(KeyStroke key) {
  1895.         return bindings.containsKey(key);
  1896.     }
  1897.  
  1898.         public void addActionForKeyStroke(KeyStroke key, Action a) {
  1899.         bindings.put(key, a);
  1900.     }
  1901.  
  1902.         public void removeKeyStrokeBinding(KeyStroke key) {
  1903.         bindings.remove(key);
  1904.     }
  1905.  
  1906.         public void removeBindings() {
  1907.         bindings.clear();
  1908.     }
  1909.  
  1910.         public Keymap getResolveParent() {
  1911.         return parent;
  1912.     }
  1913.  
  1914.         public void setResolveParent(Keymap parent) {
  1915.         this.parent = parent;
  1916.     }
  1917.  
  1918.     /**
  1919.      * String representation of the keymap... potentially 
  1920.      * a very long string.
  1921.      */
  1922.         public String toString() {
  1923.         return "Keymap[" + nm + "]" + bindings;
  1924.     }
  1925.  
  1926.     String nm;
  1927.     Keymap parent;
  1928.     Hashtable bindings;
  1929.     Action defaultAction;
  1930.     }
  1931.  
  1932.     /**
  1933.      * This is the name of the default keymap that will be shared by all
  1934.      * JTextComponent instances unless they have had a different
  1935.      * keymap set. 
  1936.      */
  1937.     public static final String DEFAULT_KEYMAP = "default";
  1938.  
  1939.     /**
  1940.      * Default bindings for the default keymap if no other bindings
  1941.      * are given.  
  1942.      */
  1943.     static final KeyBinding[] defaultBindings = {
  1944.     new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0),
  1945.                DefaultEditorKit.deletePrevCharAction),
  1946.     new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0),
  1947.                DefaultEditorKit.deleteNextCharAction),
  1948.     new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0),
  1949.                DefaultEditorKit.beginAction),
  1950.     new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0),
  1951.                DefaultEditorKit.endAction),
  1952.     new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
  1953.                DefaultEditorKit.forwardAction),
  1954.     new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
  1955.                DefaultEditorKit.backwardAction),
  1956.     new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),
  1957.                DefaultEditorKit.upAction),
  1958.     new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),
  1959.                DefaultEditorKit.downAction)
  1960.     };
  1961.  
  1962.     static {
  1963.     try {
  1964.         keymapTable = new Hashtable(17);
  1965.         Keymap binding = addKeymap(DEFAULT_KEYMAP, null);
  1966.         binding.setDefaultAction(new DefaultEditorKit.DefaultKeyTypedAction());
  1967.         EditorKit kit = new DefaultEditorKit();
  1968.         loadKeymap(binding, defaultBindings, kit.getActions());
  1969.     } catch (Throwable e) {
  1970.         e.printStackTrace();
  1971.         keymapTable = new Hashtable(17);
  1972.     }
  1973.     }
  1974.  
  1975.     /**
  1976.      * Event to use when firing a notification of change to caret 
  1977.      * position.  This is mutable so that the event can be reused
  1978.      * since caret events can be fairly high in bandwidth.
  1979.      */
  1980.     static class MutableCaretEvent extends CaretEvent implements ChangeListener, MouseListener, FocusListener {
  1981.  
  1982.         MutableCaretEvent(JTextComponent c) {
  1983.             super(c);
  1984.         }
  1985.  
  1986.         final void fire() {
  1987.             JTextComponent c = (JTextComponent) getSource();
  1988.         if (c != null) {
  1989.         Caret caret = c.getCaret();
  1990.         dot = caret.getDot();
  1991.         mark = caret.getMark();
  1992.         c.fireCaretUpdate(this);
  1993.         }
  1994.         }
  1995.  
  1996.         public final String toString() {
  1997.             return "dot=" + dot + "," + "mark=" + mark;
  1998.         }
  1999.  
  2000.         // --- CaretEvent methods -----------------------
  2001.  
  2002.         public final int getDot() {
  2003.             return dot;
  2004.         }
  2005.  
  2006.         public final int getMark() {
  2007.             return mark;
  2008.         }
  2009.  
  2010.         // --- ChangeListener methods -------------------
  2011.  
  2012.         public final void stateChanged(ChangeEvent e) {
  2013.             if (! dragActive) {
  2014.                 fire();
  2015.             }
  2016.         }
  2017.  
  2018.     // --- FocusListener methods --------------------------------
  2019.  
  2020.     /**
  2021.      * Stashes the current focused JTextComponent reference
  2022.      * for JTextAction instances to use if the ActionEvent
  2023.      * doesn't contain the target text component.
  2024.      *
  2025.      * @param e the focus event
  2026.      * @see JTextAction
  2027.      * @see FocusListener#focusGained
  2028.      */
  2029.         public void focusGained(FocusEvent e) {
  2030.         focusedComponent = (JTextComponent) getSource();
  2031.     }
  2032.  
  2033.     /**
  2034.      * Removes reference to focused text component that
  2035.      * instances of JTextAction use.
  2036.      *
  2037.      * @param e the focus event
  2038.      * @see JTextAction
  2039.      * @see FocusListener#focusLost
  2040.      */
  2041.         public void focusLost(FocusEvent e) {
  2042.         // temp focus loss from menus causes problems
  2043.         //focusedComponent = null;
  2044.     }
  2045.  
  2046.         // --- MouseListener methods -----------------------------------
  2047.     
  2048.         /**
  2049.          * Requests focus on the associated
  2050.          * text component, and try to set the cursor position.
  2051.          *
  2052.          * @param e the mouse event
  2053.          * @see MouseListener#mousePressed
  2054.          */
  2055.         public final void mousePressed(MouseEvent e) {
  2056.             dragActive = true;
  2057.         }
  2058.  
  2059.         /**
  2060.          * Called when the mouse is released.
  2061.          *
  2062.          * @param e the mouse event
  2063.          * @see MouseListener#mouseReleased
  2064.          */
  2065.         public final void mouseReleased(MouseEvent e) {
  2066.             dragActive = false;
  2067.             fire();
  2068.         }
  2069.  
  2070.         public final void mouseClicked(MouseEvent e) {
  2071.         }
  2072.  
  2073.         public final void mouseEntered(MouseEvent e) {
  2074.         }
  2075.  
  2076.         public final void mouseExited(MouseEvent e) {
  2077.         }
  2078.  
  2079.         private boolean dragActive;
  2080.         private int dot;
  2081.         private int mark;
  2082.     }
  2083.  
  2084.     class FocusAction extends AbstractAction {
  2085.  
  2086.         public void actionPerformed(ActionEvent e) {
  2087.             requestFocus();
  2088.         }
  2089.  
  2090.         public boolean isEnabled() {
  2091.             if(isEditable())
  2092.                 return true;
  2093.             else
  2094.                 return false;
  2095.         }
  2096.     }
  2097. }
  2098.  
  2099.  
  2100.