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™
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 >= 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 >= 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 >= 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™
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 >= 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 >= 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 >= 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).
|