< prev index next >

src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java

Print this page




  32 import java.awt.event.ActionListener;
  33 import java.io.*;
  34 import javax.swing.*;
  35 import javax.swing.event.*;
  36 import javax.swing.plaf.*;
  37 import java.util.EventListener;
  38 import sun.swing.SwingUtilities2;
  39 
  40 /**
  41  * A default implementation of Caret.  The caret is rendered as
  42  * a vertical line in the color specified by the CaretColor property
  43  * of the associated JTextComponent.  It can blink at the rate specified
  44  * by the BlinkRate property.
  45  * <p>
  46  * This implementation expects two sources of asynchronous notification.
  47  * The timer thread fires asynchronously, and causes the caret to simply
  48  * repaint the most recent bounding box.  The caret also tracks change
  49  * as the document is modified.  Typically this will happen on the
  50  * event dispatch thread as a result of some mouse or keyboard event.
  51  * The caret behavior on both synchronous and asynchronous documents updates
  52  * is controlled by <code>UpdatePolicy</code> property. The repaint of the
  53  * new caret location will occur on the event thread in any case, as calls to
  54  * <code>modelToView</code> are only safe on the event thread.
  55  * <p>
  56  * The caret acts as a mouse and focus listener on the text component
  57  * it has been installed in, and defines the caret semantics based upon
  58  * those events.  The listener methods can be reimplemented to change the
  59  * semantics.
  60  * By default, the first mouse button will be used to set focus and caret
  61  * position.  Dragging the mouse pointer with the first mouse button will
  62  * sweep out a selection that is contiguous in the model.  If the associated
  63  * text component is editable, the caret will become visible when focus
  64  * is gained, and invisible when focus is lost.
  65  * <p>
  66  * The Highlighter bound to the associated text component is used to
  67  * render the selection by default.
  68  * Selection appearance can be customized by supplying a
  69  * painter to use for the highlights.  By default a painter is used that
  70  * will render a solid color as specified in the associated text component
  71  * in the <code>SelectionColor</code> property.  This can easily be changed
  72  * by reimplementing the
  73  * {@link #getSelectionPainter getSelectionPainter}
  74  * method.
  75  * <p>
  76  * A customized caret appearance can be achieved by reimplementing
  77  * the paint method.  If the paint method is changed, the damage method
  78  * should also be reimplemented to cause a repaint for the area needed
  79  * to render the caret.  The caret extends the Rectangle class which
  80  * is used to hold the bounding box for where the caret was last rendered.
  81  * This enables the caret to repaint in a thread-safe manner when the
  82  * caret moves without making a call to modelToView which is unstable
  83  * between model updates and view repair (i.e. the order of delivery
  84  * to DocumentListeners is not guaranteed).
  85  * <p>
  86  * The magic caret position is set to null when the caret position changes.
  87  * A timer is used to determine the new location (after the caret change).
  88  * When the timer fires, if the magic caret position is still null it is
  89  * reset to the current caret position. Any actions that change
  90  * the caret position and want the magic caret position to remain the
  91  * same, must remember the magic caret position, change the cursor, and
  92  * then set the magic caret position to its original value. This has the
  93  * benefit that only actions that want the magic caret position to persist
  94  * (such as open/down) need to know about it.
  95  * <p>
  96  * <strong>Warning:</strong>
  97  * Serialized objects of this class will not be compatible with
  98  * future Swing releases. The current serialization support is
  99  * appropriate for short term storage or RMI between applications running
 100  * the same version of Swing.  As of 1.4, support for long term storage
 101  * of all JavaBeans&trade;
 102  * has been added to the <code>java.beans</code> package.
 103  * Please see {@link java.beans.XMLEncoder}.
 104  *
 105  * @author  Timothy Prinzing
 106  * @see     Caret
 107  */
 108 @SuppressWarnings("serial") // Same-version serialization only
 109 public class DefaultCaret extends Rectangle implements Caret, FocusListener, MouseListener, MouseMotionListener {
 110 
 111     /**
 112      * Indicates that the caret position is to be updated only when
 113      * document changes are performed on the Event Dispatching Thread.
 114      * @see #setUpdatePolicy
 115      * @see #getUpdatePolicy
 116      * @since 1.5
 117      */
 118     public static final int UPDATE_WHEN_ON_EDT = 0;
 119 
 120     /**
 121      * Indicates that the caret should remain at the same
 122      * absolute position in the document regardless of any document


 141      * @since 1.5
 142      */
 143     public static final int ALWAYS_UPDATE = 2;
 144 
 145     /**
 146      * Constructs a default caret.
 147      */
 148     public DefaultCaret() {
 149     }
 150 
 151     /**
 152      * Sets the caret movement policy on the document updates. Normally
 153      * the caret updates its absolute position within the document on
 154      * insertions occurred before or at the caret position and
 155      * on removals before the caret position. 'Absolute position'
 156      * means here the position relative to the start of the document.
 157      * For example if
 158      * a character is typed within editable text component it is inserted
 159      * at the caret position and the caret moves to the next absolute
 160      * position within the document due to insertion and if
 161      * <code>BACKSPACE</code> is typed then caret decreases its absolute
 162      * position due to removal of a character before it. Sometimes
 163      * it may be useful to turn off the caret position updates so that
 164      * the caret stays at the same absolute position within the
 165      * document position regardless of any document updates.
 166      * <p>
 167      * The following update policies are allowed:
 168      * <ul>
 169      *   <li><code>NEVER_UPDATE</code>: the caret stays at the same
 170      *       absolute position in the document regardless of any document
 171      *       updates, except when document length becomes less than
 172      *       the current caret position due to removal. In that case caret
 173      *       position is adjusted to the end of the document.
 174      *       The caret doesn't try to keep itself visible by scrolling
 175      *       the associated view when using this policy. </li>
 176      *   <li><code>ALWAYS_UPDATE</code>: the caret always tracks document
 177      *       changes. For regular changes it increases its position
 178      *       if an insertion occurs before or at its current position,
 179      *       and decreases position if a removal occurs before
 180      *       its current position. For undo/redo updates it is always
 181      *       moved to the position where update occurred. The caret
 182      *       also tries to keep itself visible by calling
 183      *       <code>adjustVisibility</code> method.</li>
 184      *   <li><code>UPDATE_WHEN_ON_EDT</code>: acts like <code>ALWAYS_UPDATE</code>
 185      *       if the document updates are performed on the Event Dispatching Thread
 186      *       and like <code>NEVER_UPDATE</code> if updates are performed on
 187      *       other thread. </li>
 188      * </ul> <p>
 189      * The default property value is <code>UPDATE_WHEN_ON_EDT</code>.
 190      *
 191      * @param policy one of the following values : <code>UPDATE_WHEN_ON_EDT</code>,
 192      * <code>NEVER_UPDATE</code>, <code>ALWAYS_UPDATE</code>
 193      * @throws IllegalArgumentException if invalid value is passed
 194      *
 195      * @see #getUpdatePolicy
 196      * @see #adjustVisibility
 197      * @see #UPDATE_WHEN_ON_EDT
 198      * @see #NEVER_UPDATE
 199      * @see #ALWAYS_UPDATE
 200      *
 201      * @since 1.5
 202      */
 203     public void setUpdatePolicy(int policy) {
 204         updatePolicy = policy;
 205     }
 206 
 207     /**
 208      * Gets the caret movement policy on document updates.
 209      *
 210      * @return one of the following values : <code>UPDATE_WHEN_ON_EDT</code>,
 211      * <code>NEVER_UPDATE</code>, <code>ALWAYS_UPDATE</code>
 212      *
 213      * @see #setUpdatePolicy
 214      * @see #UPDATE_WHEN_ON_EDT
 215      * @see #NEVER_UPDATE
 216      * @see #ALWAYS_UPDATE
 217      *
 218      * @since 1.5
 219      */
 220     public int getUpdatePolicy() {
 221         return updatePolicy;
 222     }
 223 
 224     /**
 225      * Gets the text editor component that this caret is
 226      * is bound to.
 227      *
 228      * @return the component
 229      */
 230     protected final JTextComponent getComponent() {
 231         return component;


 752      * @see Caret#addChangeListener
 753      */
 754     public void addChangeListener(ChangeListener l) {
 755         listenerList.add(ChangeListener.class, l);
 756     }
 757 
 758     /**
 759      * Removes a listener that was tracking caret position changes.
 760      *
 761      * @param l the listener
 762      * @see Caret#removeChangeListener
 763      */
 764     public void removeChangeListener(ChangeListener l) {
 765         listenerList.remove(ChangeListener.class, l);
 766     }
 767 
 768     /**
 769      * Returns an array of all the change listeners
 770      * registered on this caret.
 771      *
 772      * @return all of this caret's <code>ChangeListener</code>s
 773      *         or an empty
 774      *         array if no change listeners are currently registered
 775      *
 776      * @see #addChangeListener
 777      * @see #removeChangeListener
 778      *
 779      * @since 1.4
 780      */
 781     public ChangeListener[] getChangeListeners() {
 782         return listenerList.getListeners(ChangeListener.class);
 783     }
 784 
 785     /**
 786      * Notifies all listeners that have registered interest for
 787      * notification on this event type.  The event instance
 788      * is lazily created using the parameters passed into
 789      * the fire method.  The listener list is processed last to first.
 790      *
 791      * @see EventListenerList
 792      */


 797         // those that are interested in this event
 798         for (int i = listeners.length-2; i>=0; i-=2) {
 799             if (listeners[i]==ChangeListener.class) {
 800                 // Lazily create the event:
 801                 if (changeEvent == null)
 802                     changeEvent = new ChangeEvent(this);
 803                 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
 804             }
 805         }
 806     }
 807 
 808     /**
 809      * Returns an array of all the objects currently registered
 810      * as <code><em>Foo</em>Listener</code>s
 811      * upon this caret.
 812      * <code><em>Foo</em>Listener</code>s are registered using the
 813      * <code>add<em>Foo</em>Listener</code> method.
 814      *
 815      * <p>
 816      *
 817      * You can specify the <code>listenerType</code> argument
 818      * with a class literal,
 819      * such as
 820      * <code><em>Foo</em>Listener.class</code>.
 821      * For example, you can query a
 822      * <code>DefaultCaret</code> <code>c</code>
 823      * for its change listeners with the following code:
 824      *
 825      * <pre>ChangeListener[] cls = (ChangeListener[])(c.getListeners(ChangeListener.class));</pre>
 826      *
 827      * If no such listeners exist, this method returns an empty array.
 828      * @param <T> the listener type
 829      * @param listenerType the type of listeners requested
 830      * @return an array of all objects registered as
 831      *          <code><em>Foo</em>Listener</code>s on this component,
 832      *          or an empty array if no such
 833      *          listeners have been added
 834      * @exception ClassCastException if <code>listenerType</code>
 835      *          doesn't specify a class or interface that implements
 836      *          <code>java.util.EventListener</code>
 837      *
 838      * @see #getChangeListeners
 839      *
 840      * @since 1.3
 841      */
 842     public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
 843         return listenerList.getListeners(listenerType);
 844     }
 845 
 846     /**
 847      * Changes the selection visibility.
 848      *
 849      * @param vis the new visibility
 850      */
 851     public void setSelectionVisible(boolean vis) {
 852         if (vis != selectionVisible) {
 853             selectionVisible = vis;
 854             if (selectionVisible) {
 855                 // show
 856                 Highlighter h = component.getHighlighter();


 872                     h.removeHighlight(selectionTag);
 873                     selectionTag = null;
 874                     updateOwnsSelection();
 875                 }
 876             }
 877         }
 878     }
 879 
 880     /**
 881      * Checks whether the current selection is visible.
 882      *
 883      * @return true if the selection is visible
 884      */
 885     public boolean isSelectionVisible() {
 886         return selectionVisible;
 887     }
 888 
 889     /**
 890      * Determines if the caret is currently active.
 891      * <p>
 892      * This method returns whether or not the <code>Caret</code>
 893      * is currently in a blinking state. It does not provide
 894      * information as to whether it is currently blinked on or off.
 895      * To determine if the caret is currently painted use the
 896      * <code>isVisible</code> method.
 897      *
 898      * @return <code>true</code> if active else <code>false</code>
 899      * @see #isVisible
 900      *
 901      * @since 1.5
 902      */
 903     public boolean isActive() {
 904         return active;
 905     }
 906 
 907     /**
 908      * Indicates whether or not the caret is currently visible. As the
 909      * caret flashes on and off the return value of this will change
 910      * between true, when the caret is painted, and false, when the
 911      * caret is not painted. <code>isActive</code> indicates whether
 912      * or not the caret is in a blinking state, such that it <b>can</b>
 913      * be visible, and <code>isVisible</code> indicates whether or not
 914      * the caret <b>is</b> actually visible.
 915      * <p>
 916      * Subclasses that wish to render a different flashing caret
 917      * should override paint and only paint the caret if this method
 918      * returns true.
 919      *
 920      * @return true if visible else false
 921      * @see Caret#isVisible
 922      * @see #isActive
 923      */
 924     public boolean isVisible() {
 925         return visible;
 926     }
 927 
 928     /**
 929      * Sets the caret visibility, and repaints the caret.
 930      * It is important to understand the relationship between this method,
 931      * <code>isVisible</code> and <code>isActive</code>.
 932      * Calling this method with a value of <code>true</code> activates the
 933      * caret blinking. Setting it to <code>false</code> turns it completely off.
 934      * To determine whether the blinking is active, you should call
 935      * <code>isActive</code>. In effect, <code>isActive</code> is an
 936      * appropriate corresponding "getter" method for this one.
 937      * <code>isVisible</code> can be used to fetch the current
 938      * visibility status of the caret, meaning whether or not it is currently
 939      * painted. This status will change as the caret blinks on and off.
 940      * <p>
 941      * Here's a list showing the potential return values of both
 942      * <code>isActive</code> and <code>isVisible</code>
 943      * after calling this method:
 944      * <p>
 945      * <b><code>setVisible(true)</code></b>:
 946      * <ul>
 947      *     <li>isActive(): true</li>
 948      *     <li>isVisible(): true or false depending on whether
 949      *         or not the caret is blinked on or off</li>
 950      * </ul>
 951      * <p>
 952      * <b><code>setVisible(false)</code></b>:
 953      * <ul>
 954      *     <li>isActive(): false</li>
 955      *     <li>isVisible(): false</li>
 956      * </ul>
 957      *
 958      * @param e the visibility specifier
 959      * @see #isActive
 960      * @see Caret#setVisible
 961      */
 962     public void setVisible(boolean e) {
 963         // focus lost notification can come in later after the
 964         // caret has been deinstalled, in which case the component
 965         // will be null.
 966         active = e;
 967         if (component != null) {
 968             TextUI mapper = component.getUI();
 969             if (visible != e) {
 970                 visible = e;
 971                 // repaint the caret
 972                 try {


1054 
1055     /**
1056      * Moves the caret position to the specified position,
1057      * with a forward bias.
1058      *
1059      * @param dot the position &gt;= 0
1060      * @see #moveDot(int, javax.swing.text.Position.Bias)
1061      * @see Caret#moveDot
1062      */
1063     public void moveDot(int dot) {
1064         moveDot(dot, Position.Bias.Forward);
1065     }
1066 
1067     // ---- Bidi methods (we could put these in a subclass)
1068 
1069     /**
1070      * Moves the caret position to the specified position, with the
1071      * specified bias.
1072      *
1073      * @param dot the position &gt;= 0
1074      * @param dotBias the bias for this position, not <code>null</code>
1075      * @throws IllegalArgumentException if the bias is <code>null</code>
1076      * @see Caret#moveDot
1077      * @since 1.6
1078      */
1079     public void moveDot(int dot, Position.Bias dotBias) {
1080         if (dotBias == null) {
1081             throw new IllegalArgumentException("null bias");
1082         }
1083 
1084         if (! component.isEnabled()) {
1085             // don't allow selection on disabled components.
1086             setDot(dot, dotBias);
1087             return;
1088         }
1089         if (dot != this.dot) {
1090             NavigationFilter filter = component.getNavigationFilter();
1091 
1092             if (filter != null) {
1093                 filter.moveDot(getFilterBypass(), dot, dotBias);
1094             }
1095             else {


1121                             h.changeHighlight(selectionTag, p0, p1);
1122                         } else {
1123                             Highlighter.HighlightPainter p = getSelectionPainter();
1124                             selectionTag = h.addHighlight(p0, p1, p);
1125                         }
1126                         updateOwnsSelection();
1127                     } catch (BadLocationException e) {
1128                         throw new StateInvariantError("Bad caret position");
1129                     }
1130                 }
1131             }
1132         }
1133     }
1134 
1135     /**
1136      * Sets the caret position and mark to the specified position, with the
1137      * specified bias. This implicitly sets the selection range
1138      * to zero.
1139      *
1140      * @param dot the position &gt;= 0
1141      * @param dotBias the bias for this position, not <code>null</code>
1142      * @throws IllegalArgumentException if the bias is <code>null</code>
1143      * @see Caret#setDot
1144      * @since 1.6
1145      */
1146     public void setDot(int dot, Position.Bias dotBias) {
1147         if (dotBias == null) {
1148             throw new IllegalArgumentException("null bias");
1149         }
1150 
1151         NavigationFilter filter = component.getNavigationFilter();
1152 
1153         if (filter != null) {
1154             filter.setDot(getFilterBypass(), dot, dotBias);
1155         }
1156         else {
1157             handleSetDot(dot, dotBias);
1158         }
1159     }
1160 
1161     void handleSetDot(int dot, Position.Bias dotBias) {
1162         // move dot, if it changed


1281         updateSystemSelection();
1282 
1283         setMagicCaretPosition(null);
1284 
1285         // We try to repaint the caret later, since things
1286         // may be unstable at the time this is called
1287         // (i.e. we don't want to depend upon notification
1288         // order or the fact that this might happen on
1289         // an unsafe thread).
1290         Runnable callRepaintNewCaret = new Runnable() {
1291             public void run() {
1292                 repaintNewCaret();
1293             }
1294         };
1295         SwingUtilities.invokeLater(callRepaintNewCaret);
1296     }
1297 
1298     /**
1299      * Repaints the new caret position, with the
1300      * assumption that this is happening on the
1301      * event thread so that calling <code>modelToView</code>
1302      * is safe.
1303      */
1304     void repaintNewCaret() {
1305         if (component != null) {
1306             TextUI mapper = component.getUI();
1307             Document doc = component.getDocument();
1308             if ((mapper != null) && (doc != null)) {
1309                 // determine the new location and scroll if
1310                 // not visible.
1311                 Rectangle newLoc;
1312                 try {
1313                     newLoc = mapper.modelToView(component, this.dot, this.dotBias);
1314                 } catch (BadLocationException e) {
1315                     newLoc = null;
1316                 }
1317                 if (newLoc != null) {
1318                     adjustVisibility(newLoc);
1319                     // If there is no magic caret position, make one
1320                     if (getMagicCaretPosition() == null) {
1321                         setMagicCaretPosition(new Point(newLoc.x, newLoc.y));


1368         }
1369     }
1370 
1371     private Clipboard getSystemSelection() {
1372         try {
1373             return component.getToolkit().getSystemSelection();
1374         } catch (HeadlessException he) {
1375             // do nothing... there is no system clipboard
1376         } catch (SecurityException se) {
1377             // do nothing... there is no allowed system clipboard
1378         }
1379         return null;
1380     }
1381 
1382     private ClipboardOwner getClipboardOwner() {
1383         return handler;
1384     }
1385 
1386     /**
1387      * This is invoked after the document changes to verify the current
1388      * dot/mark is valid. We do this in case the <code>NavigationFilter</code>
1389      * changed where to position the dot, that resulted in the current location
1390      * being bogus.
1391      */
1392     private void ensureValidPosition() {
1393         int length = component.getDocument().getLength();
1394         if (dot > length || mark > length) {
1395             // Current location is bogus and filter likely vetoed the
1396             // change, force the reset without giving the filter a
1397             // chance at changing it.
1398             handleSetDot(length, Position.Bias.Forward);
1399         }
1400     }
1401 
1402 
1403     /**
1404      * Saves the current caret position.  This is used when
1405      * caret up/down actions occur, moving between lines
1406      * that have uneven end positions.
1407      *
1408      * @param p the position


1412         magicCaretPosition = p;
1413     }
1414 
1415     /**
1416      * Gets the saved caret position.
1417      *
1418      * @return the position
1419      * see #setMagicCaretPosition
1420      */
1421     public Point getMagicCaretPosition() {
1422         return magicCaretPosition;
1423     }
1424 
1425     /**
1426      * Compares this object to the specified object.
1427      * The superclass behavior of comparing rectangles
1428      * is not desired, so this is changed to the Object
1429      * behavior.
1430      *
1431      * @param     obj   the object to compare this font with
1432      * @return    <code>true</code> if the objects are equal;
1433      *            <code>false</code> otherwise
1434      */
1435     public boolean equals(Object obj) {
1436         return (this == obj);
1437     }
1438 
1439     public String toString() {
1440         String s = "Dot=(" + dot + ", " + dotBias + ")";
1441         s += " Mark=(" + mark + ", " + markBias + ")";
1442         return s;
1443     }
1444 
1445     private NavigationFilter.FilterBypass getFilterBypass() {
1446         if (filterBypass == null) {
1447             filterBypass = new DefaultFilterBypass();
1448         }
1449         return filterBypass;
1450     }
1451 
1452     // Rectangle.contains returns false if passed a rect with a w or h == 0,
1453     // this won't (assuming X,Y are contained with this rectangle).




  32 import java.awt.event.ActionListener;
  33 import java.io.*;
  34 import javax.swing.*;
  35 import javax.swing.event.*;
  36 import javax.swing.plaf.*;
  37 import java.util.EventListener;
  38 import sun.swing.SwingUtilities2;
  39 
  40 /**
  41  * A default implementation of Caret.  The caret is rendered as
  42  * a vertical line in the color specified by the CaretColor property
  43  * of the associated JTextComponent.  It can blink at the rate specified
  44  * by the BlinkRate property.
  45  * <p>
  46  * This implementation expects two sources of asynchronous notification.
  47  * The timer thread fires asynchronously, and causes the caret to simply
  48  * repaint the most recent bounding box.  The caret also tracks change
  49  * as the document is modified.  Typically this will happen on the
  50  * event dispatch thread as a result of some mouse or keyboard event.
  51  * The caret behavior on both synchronous and asynchronous documents updates
  52  * is controlled by {@code UpdatePolicy} property. The repaint of the
  53  * new caret location will occur on the event thread in any case, as calls to
  54  * {@code modelToView} are only safe on the event thread.
  55  * <p>
  56  * The caret acts as a mouse and focus listener on the text component
  57  * it has been installed in, and defines the caret semantics based upon
  58  * those events.  The listener methods can be reimplemented to change the
  59  * semantics.
  60  * By default, the first mouse button will be used to set focus and caret
  61  * position.  Dragging the mouse pointer with the first mouse button will
  62  * sweep out a selection that is contiguous in the model.  If the associated
  63  * text component is editable, the caret will become visible when focus
  64  * is gained, and invisible when focus is lost.
  65  * <p>
  66  * The Highlighter bound to the associated text component is used to
  67  * render the selection by default.
  68  * Selection appearance can be customized by supplying a
  69  * painter to use for the highlights.  By default a painter is used that
  70  * will render a solid color as specified in the associated text component
  71  * in the {@code SelectionColor} property.  This can easily be changed
  72  * by reimplementing the
  73  * {@link #getSelectionPainter getSelectionPainter}
  74  * method.
  75  * <p>
  76  * A customized caret appearance can be achieved by reimplementing
  77  * the paint method.  If the paint method is changed, the damage method
  78  * should also be reimplemented to cause a repaint for the area needed
  79  * to render the caret.  The caret extends the Rectangle class which
  80  * is used to hold the bounding box for where the caret was last rendered.
  81  * This enables the caret to repaint in a thread-safe manner when the
  82  * caret moves without making a call to modelToView which is unstable
  83  * between model updates and view repair (i.e. the order of delivery
  84  * to DocumentListeners is not guaranteed).
  85  * <p>
  86  * The magic caret position is set to null when the caret position changes.
  87  * A timer is used to determine the new location (after the caret change).
  88  * When the timer fires, if the magic caret position is still null it is
  89  * reset to the current caret position. Any actions that change
  90  * the caret position and want the magic caret position to remain the
  91  * same, must remember the magic caret position, change the cursor, and
  92  * then set the magic caret position to its original value. This has the
  93  * benefit that only actions that want the magic caret position to persist
  94  * (such as open/down) need to know about it.
  95  * <p>
  96  * <strong>Warning:</strong>
  97  * Serialized objects of this class will not be compatible with
  98  * future Swing releases. The current serialization support is
  99  * appropriate for short term storage or RMI between applications running
 100  * the same version of Swing.  As of 1.4, support for long term storage
 101  * of all JavaBeans&trade;
 102  * has been added to the {@code java.beans} package.
 103  * Please see {@link java.beans.XMLEncoder}.
 104  *
 105  * @author  Timothy Prinzing
 106  * @see     Caret
 107  */
 108 @SuppressWarnings("serial") // Same-version serialization only
 109 public class DefaultCaret extends Rectangle implements Caret, FocusListener, MouseListener, MouseMotionListener {
 110 
 111     /**
 112      * Indicates that the caret position is to be updated only when
 113      * document changes are performed on the Event Dispatching Thread.
 114      * @see #setUpdatePolicy
 115      * @see #getUpdatePolicy
 116      * @since 1.5
 117      */
 118     public static final int UPDATE_WHEN_ON_EDT = 0;
 119 
 120     /**
 121      * Indicates that the caret should remain at the same
 122      * absolute position in the document regardless of any document


 141      * @since 1.5
 142      */
 143     public static final int ALWAYS_UPDATE = 2;
 144 
 145     /**
 146      * Constructs a default caret.
 147      */
 148     public DefaultCaret() {
 149     }
 150 
 151     /**
 152      * Sets the caret movement policy on the document updates. Normally
 153      * the caret updates its absolute position within the document on
 154      * insertions occurred before or at the caret position and
 155      * on removals before the caret position. 'Absolute position'
 156      * means here the position relative to the start of the document.
 157      * For example if
 158      * a character is typed within editable text component it is inserted
 159      * at the caret position and the caret moves to the next absolute
 160      * position within the document due to insertion and if
 161      * {@code BACKSPACE} is typed then caret decreases its absolute
 162      * position due to removal of a character before it. Sometimes
 163      * it may be useful to turn off the caret position updates so that
 164      * the caret stays at the same absolute position within the
 165      * document position regardless of any document updates.
 166      * <p>
 167      * The following update policies are allowed:
 168      * <ul>
 169      *   <li>{@code NEVER_UPDATE}: the caret stays at the same
 170      *       absolute position in the document regardless of any document
 171      *       updates, except when document length becomes less than
 172      *       the current caret position due to removal. In that case caret
 173      *       position is adjusted to the end of the document.
 174      *       The caret doesn't try to keep itself visible by scrolling
 175      *       the associated view when using this policy. </li>
 176      *   <li>{@code ALWAYS_UPDATE}: the caret always tracks document
 177      *       changes. For regular changes it increases its position
 178      *       if an insertion occurs before or at its current position,
 179      *       and decreases position if a removal occurs before
 180      *       its current position. For undo/redo updates it is always
 181      *       moved to the position where update occurred. The caret
 182      *       also tries to keep itself visible by calling
 183      *       {@code adjustVisibility} method.</li>
 184      *   <li>{@code UPDATE_WHEN_ON_EDT}: acts like {@code ALWAYS_UPDATE}
 185      *       if the document updates are performed on the Event Dispatching Thread
 186      *       and like {@code NEVER_UPDATE} if updates are performed on
 187      *       other thread. </li>
 188      * </ul> <p>
 189      * The default property value is {@code UPDATE_WHEN_ON_EDT}.
 190      *
 191      * @param policy one of the following values : {@code UPDATE_WHEN_ON_EDT},
 192      * {@code NEVER_UPDATE}, {@code ALWAYS_UPDATE}
 193      * @throws IllegalArgumentException if invalid value is passed
 194      *
 195      * @see #getUpdatePolicy
 196      * @see #adjustVisibility
 197      * @see #UPDATE_WHEN_ON_EDT
 198      * @see #NEVER_UPDATE
 199      * @see #ALWAYS_UPDATE
 200      *
 201      * @since 1.5
 202      */
 203     public void setUpdatePolicy(int policy) {
 204         updatePolicy = policy;
 205     }
 206 
 207     /**
 208      * Gets the caret movement policy on document updates.
 209      *
 210      * @return one of the following values : {@code UPDATE_WHEN_ON_EDT},
 211      * {@code NEVER_UPDATE}, {@code ALWAYS_UPDATE}
 212      *
 213      * @see #setUpdatePolicy
 214      * @see #UPDATE_WHEN_ON_EDT
 215      * @see #NEVER_UPDATE
 216      * @see #ALWAYS_UPDATE
 217      *
 218      * @since 1.5
 219      */
 220     public int getUpdatePolicy() {
 221         return updatePolicy;
 222     }
 223 
 224     /**
 225      * Gets the text editor component that this caret is
 226      * is bound to.
 227      *
 228      * @return the component
 229      */
 230     protected final JTextComponent getComponent() {
 231         return component;


 752      * @see Caret#addChangeListener
 753      */
 754     public void addChangeListener(ChangeListener l) {
 755         listenerList.add(ChangeListener.class, l);
 756     }
 757 
 758     /**
 759      * Removes a listener that was tracking caret position changes.
 760      *
 761      * @param l the listener
 762      * @see Caret#removeChangeListener
 763      */
 764     public void removeChangeListener(ChangeListener l) {
 765         listenerList.remove(ChangeListener.class, l);
 766     }
 767 
 768     /**
 769      * Returns an array of all the change listeners
 770      * registered on this caret.
 771      *
 772      * @return all of this caret's {@code ChangeListener}s
 773      *         or an empty
 774      *         array if no change listeners are currently registered
 775      *
 776      * @see #addChangeListener
 777      * @see #removeChangeListener
 778      *
 779      * @since 1.4
 780      */
 781     public ChangeListener[] getChangeListeners() {
 782         return listenerList.getListeners(ChangeListener.class);
 783     }
 784 
 785     /**
 786      * Notifies all listeners that have registered interest for
 787      * notification on this event type.  The event instance
 788      * is lazily created using the parameters passed into
 789      * the fire method.  The listener list is processed last to first.
 790      *
 791      * @see EventListenerList
 792      */


 797         // those that are interested in this event
 798         for (int i = listeners.length-2; i>=0; i-=2) {
 799             if (listeners[i]==ChangeListener.class) {
 800                 // Lazily create the event:
 801                 if (changeEvent == null)
 802                     changeEvent = new ChangeEvent(this);
 803                 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
 804             }
 805         }
 806     }
 807 
 808     /**
 809      * Returns an array of all the objects currently registered
 810      * as <code><em>Foo</em>Listener</code>s
 811      * upon this caret.
 812      * <code><em>Foo</em>Listener</code>s are registered using the
 813      * <code>add<em>Foo</em>Listener</code> method.
 814      *
 815      * <p>
 816      *
 817      * You can specify the {@code listenerType} argument
 818      * with a class literal,
 819      * such as
 820      * <code><em>Foo</em>Listener.class</code>.
 821      * For example, you can query a
 822      * {@code DefaultCaret c}
 823      * for its change listeners with the following code:
 824      *
 825      * <pre>ChangeListener[] cls = (ChangeListener[])(c.getListeners(ChangeListener.class));</pre>
 826      *
 827      * If no such listeners exist, this method returns an empty array.
 828      * @param <T> the listener type
 829      * @param listenerType the type of listeners requested
 830      * @return an array of all objects registered as
 831      *          <code><em>Foo</em>Listener</code>s on this component,
 832      *          or an empty array if no such
 833      *          listeners have been added
 834      * @exception ClassCastException if {@code listenerType}
 835      *          doesn't specify a class or interface that implements
 836      *          {@code java.util.EventListener}
 837      *
 838      * @see #getChangeListeners
 839      *
 840      * @since 1.3
 841      */
 842     public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
 843         return listenerList.getListeners(listenerType);
 844     }
 845 
 846     /**
 847      * Changes the selection visibility.
 848      *
 849      * @param vis the new visibility
 850      */
 851     public void setSelectionVisible(boolean vis) {
 852         if (vis != selectionVisible) {
 853             selectionVisible = vis;
 854             if (selectionVisible) {
 855                 // show
 856                 Highlighter h = component.getHighlighter();


 872                     h.removeHighlight(selectionTag);
 873                     selectionTag = null;
 874                     updateOwnsSelection();
 875                 }
 876             }
 877         }
 878     }
 879 
 880     /**
 881      * Checks whether the current selection is visible.
 882      *
 883      * @return true if the selection is visible
 884      */
 885     public boolean isSelectionVisible() {
 886         return selectionVisible;
 887     }
 888 
 889     /**
 890      * Determines if the caret is currently active.
 891      * <p>
 892      * This method returns whether or not the {@code Caret}
 893      * is currently in a blinking state. It does not provide
 894      * information as to whether it is currently blinked on or off.
 895      * To determine if the caret is currently painted use the
 896      * {@code isVisible} method.
 897      *
 898      * @return {@code true} if active else {@code false}
 899      * @see #isVisible
 900      *
 901      * @since 1.5
 902      */
 903     public boolean isActive() {
 904         return active;
 905     }
 906 
 907     /**
 908      * Indicates whether or not the caret is currently visible. As the
 909      * caret flashes on and off the return value of this will change
 910      * between true, when the caret is painted, and false, when the
 911      * caret is not painted. {@code isActive} indicates whether
 912      * or not the caret is in a blinking state, such that it <b>can</b>
 913      * be visible, and {@code isVisible} indicates whether or not
 914      * the caret <b>is</b> actually visible.
 915      * <p>
 916      * Subclasses that wish to render a different flashing caret
 917      * should override paint and only paint the caret if this method
 918      * returns true.
 919      *
 920      * @return true if visible else false
 921      * @see Caret#isVisible
 922      * @see #isActive
 923      */
 924     public boolean isVisible() {
 925         return visible;
 926     }
 927 
 928     /**
 929      * Sets the caret visibility, and repaints the caret.
 930      * It is important to understand the relationship between this method,
 931      * {@code isVisible} and {@code isActive}.
 932      * Calling this method with a value of {@code true} activates the
 933      * caret blinking. Setting it to {@code false} turns it completely off.
 934      * To determine whether the blinking is active, you should call
 935      * {@code isActive}. In effect, {@code isActive} is an
 936      * appropriate corresponding "getter" method for this one.
 937      * {@code isVisible} can be used to fetch the current
 938      * visibility status of the caret, meaning whether or not it is currently
 939      * painted. This status will change as the caret blinks on and off.
 940      * <p>
 941      * Here's a list showing the potential return values of both
 942      * {@code isActive} and {@code isVisible}
 943      * after calling this method:
 944      * <p>
 945      * <b>{@code setVisible(true)}</b>:
 946      * <ul>
 947      *     <li>isActive(): true</li>
 948      *     <li>isVisible(): true or false depending on whether
 949      *         or not the caret is blinked on or off</li>
 950      * </ul>
 951      * <p>
 952      * <b>{@code setVisible(false)}</b>:
 953      * <ul>
 954      *     <li>isActive(): false</li>
 955      *     <li>isVisible(): false</li>
 956      * </ul>
 957      *
 958      * @param e the visibility specifier
 959      * @see #isActive
 960      * @see Caret#setVisible
 961      */
 962     public void setVisible(boolean e) {
 963         // focus lost notification can come in later after the
 964         // caret has been deinstalled, in which case the component
 965         // will be null.
 966         active = e;
 967         if (component != null) {
 968             TextUI mapper = component.getUI();
 969             if (visible != e) {
 970                 visible = e;
 971                 // repaint the caret
 972                 try {


1054 
1055     /**
1056      * Moves the caret position to the specified position,
1057      * with a forward bias.
1058      *
1059      * @param dot the position &gt;= 0
1060      * @see #moveDot(int, javax.swing.text.Position.Bias)
1061      * @see Caret#moveDot
1062      */
1063     public void moveDot(int dot) {
1064         moveDot(dot, Position.Bias.Forward);
1065     }
1066 
1067     // ---- Bidi methods (we could put these in a subclass)
1068 
1069     /**
1070      * Moves the caret position to the specified position, with the
1071      * specified bias.
1072      *
1073      * @param dot the position &gt;= 0
1074      * @param dotBias the bias for this position, not {@code null}
1075      * @throws IllegalArgumentException if the bias is {@code null}
1076      * @see Caret#moveDot
1077      * @since 1.6
1078      */
1079     public void moveDot(int dot, Position.Bias dotBias) {
1080         if (dotBias == null) {
1081             throw new IllegalArgumentException("null bias");
1082         }
1083 
1084         if (! component.isEnabled()) {
1085             // don't allow selection on disabled components.
1086             setDot(dot, dotBias);
1087             return;
1088         }
1089         if (dot != this.dot) {
1090             NavigationFilter filter = component.getNavigationFilter();
1091 
1092             if (filter != null) {
1093                 filter.moveDot(getFilterBypass(), dot, dotBias);
1094             }
1095             else {


1121                             h.changeHighlight(selectionTag, p0, p1);
1122                         } else {
1123                             Highlighter.HighlightPainter p = getSelectionPainter();
1124                             selectionTag = h.addHighlight(p0, p1, p);
1125                         }
1126                         updateOwnsSelection();
1127                     } catch (BadLocationException e) {
1128                         throw new StateInvariantError("Bad caret position");
1129                     }
1130                 }
1131             }
1132         }
1133     }
1134 
1135     /**
1136      * Sets the caret position and mark to the specified position, with the
1137      * specified bias. This implicitly sets the selection range
1138      * to zero.
1139      *
1140      * @param dot the position &gt;= 0
1141      * @param dotBias the bias for this position, not {@code null}
1142      * @throws IllegalArgumentException if the bias is {@code null}
1143      * @see Caret#setDot
1144      * @since 1.6
1145      */
1146     public void setDot(int dot, Position.Bias dotBias) {
1147         if (dotBias == null) {
1148             throw new IllegalArgumentException("null bias");
1149         }
1150 
1151         NavigationFilter filter = component.getNavigationFilter();
1152 
1153         if (filter != null) {
1154             filter.setDot(getFilterBypass(), dot, dotBias);
1155         }
1156         else {
1157             handleSetDot(dot, dotBias);
1158         }
1159     }
1160 
1161     void handleSetDot(int dot, Position.Bias dotBias) {
1162         // move dot, if it changed


1281         updateSystemSelection();
1282 
1283         setMagicCaretPosition(null);
1284 
1285         // We try to repaint the caret later, since things
1286         // may be unstable at the time this is called
1287         // (i.e. we don't want to depend upon notification
1288         // order or the fact that this might happen on
1289         // an unsafe thread).
1290         Runnable callRepaintNewCaret = new Runnable() {
1291             public void run() {
1292                 repaintNewCaret();
1293             }
1294         };
1295         SwingUtilities.invokeLater(callRepaintNewCaret);
1296     }
1297 
1298     /**
1299      * Repaints the new caret position, with the
1300      * assumption that this is happening on the
1301      * event thread so that calling {@code modelToView}
1302      * is safe.
1303      */
1304     void repaintNewCaret() {
1305         if (component != null) {
1306             TextUI mapper = component.getUI();
1307             Document doc = component.getDocument();
1308             if ((mapper != null) && (doc != null)) {
1309                 // determine the new location and scroll if
1310                 // not visible.
1311                 Rectangle newLoc;
1312                 try {
1313                     newLoc = mapper.modelToView(component, this.dot, this.dotBias);
1314                 } catch (BadLocationException e) {
1315                     newLoc = null;
1316                 }
1317                 if (newLoc != null) {
1318                     adjustVisibility(newLoc);
1319                     // If there is no magic caret position, make one
1320                     if (getMagicCaretPosition() == null) {
1321                         setMagicCaretPosition(new Point(newLoc.x, newLoc.y));


1368         }
1369     }
1370 
1371     private Clipboard getSystemSelection() {
1372         try {
1373             return component.getToolkit().getSystemSelection();
1374         } catch (HeadlessException he) {
1375             // do nothing... there is no system clipboard
1376         } catch (SecurityException se) {
1377             // do nothing... there is no allowed system clipboard
1378         }
1379         return null;
1380     }
1381 
1382     private ClipboardOwner getClipboardOwner() {
1383         return handler;
1384     }
1385 
1386     /**
1387      * This is invoked after the document changes to verify the current
1388      * dot/mark is valid. We do this in case the {@code NavigationFilter}
1389      * changed where to position the dot, that resulted in the current location
1390      * being bogus.
1391      */
1392     private void ensureValidPosition() {
1393         int length = component.getDocument().getLength();
1394         if (dot > length || mark > length) {
1395             // Current location is bogus and filter likely vetoed the
1396             // change, force the reset without giving the filter a
1397             // chance at changing it.
1398             handleSetDot(length, Position.Bias.Forward);
1399         }
1400     }
1401 
1402 
1403     /**
1404      * Saves the current caret position.  This is used when
1405      * caret up/down actions occur, moving between lines
1406      * that have uneven end positions.
1407      *
1408      * @param p the position


1412         magicCaretPosition = p;
1413     }
1414 
1415     /**
1416      * Gets the saved caret position.
1417      *
1418      * @return the position
1419      * see #setMagicCaretPosition
1420      */
1421     public Point getMagicCaretPosition() {
1422         return magicCaretPosition;
1423     }
1424 
1425     /**
1426      * Compares this object to the specified object.
1427      * The superclass behavior of comparing rectangles
1428      * is not desired, so this is changed to the Object
1429      * behavior.
1430      *
1431      * @param     obj   the object to compare this font with
1432      * @return    {@code true} if the objects are equal;
1433      *            {@code false} otherwise
1434      */
1435     public boolean equals(Object obj) {
1436         return (this == obj);
1437     }
1438 
1439     public String toString() {
1440         String s = "Dot=(" + dot + ", " + dotBias + ")";
1441         s += " Mark=(" + mark + ", " + markBias + ")";
1442         return s;
1443     }
1444 
1445     private NavigationFilter.FilterBypass getFilterBypass() {
1446         if (filterBypass == null) {
1447             filterBypass = new DefaultFilterBypass();
1448         }
1449         return filterBypass;
1450     }
1451 
1452     // Rectangle.contains returns false if passed a rect with a w or h == 0,
1453     // this won't (assuming X,Y are contained with this rectangle).


< prev index next >