12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package javax.swing.text;
26
27 import com.sun.beans.util.Cache;
28
29 import java.security.AccessController;
30 import java.security.PrivilegedAction;
31
32 import java.beans.Transient;
33 import java.util.HashMap;
34 import java.util.Hashtable;
35 import java.util.Enumeration;
36 import java.util.Vector;
37
38 import java.util.concurrent.*;
39
40 import java.io.*;
41
42 import java.awt.*;
43 import java.awt.event.*;
44 import java.awt.print.*;
45 import java.awt.datatransfer.*;
46 import java.awt.im.InputContext;
47 import java.awt.im.InputMethodRequests;
48 import java.awt.font.TextHitInfo;
49 import java.awt.font.TextAttribute;
50
51 import java.awt.print.Printable;
52 import java.awt.print.PrinterException;
53
54 import javax.print.PrintService;
55 import javax.print.attribute.PrintRequestAttributeSet;
56
57 import java.text.*;
58 import java.text.AttributedCharacterIterator.Attribute;
59
60 import javax.swing.*;
61 import javax.swing.event.*;
62 import javax.swing.plaf.*;
63
64 import javax.accessibility.*;
65
66 import javax.print.attribute.*;
67
68 import sun.awt.AppContext;
69
70
71 import sun.swing.PrintingStatus;
72 import sun.swing.SwingUtilities2;
73 import sun.swing.text.TextComponentPrintable;
74 import sun.swing.SwingAccessor;
75
76 /**
77 * <code>JTextComponent</code> is the base class for swing text
78 * components. It tries to be compatible with the
79 * <code>java.awt.TextComponent</code> class
80 * where it can reasonably do so. Also provided are other services
81 * for additional flexibility (beyond the pluggable UI and bean
82 * support).
83 * You can find information on how to use the functionality
84 * this class provides in
85 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/generaltext.html">General Rules for Using Text Components</a>,
86 * a section in <em>The Java Tutorial.</em>
87 *
88 * <dl>
89 * <dt><b>Caret Changes</b>
90 * <dd>
258 * <a href="DefaultEditorKit.html">DefaultEditorKit</a>.
259 *
260 *
261 * <dt><b>Printing support</b>
262 * <dd>
263 * Several {@link #print print} methods are provided for basic
264 * document printing. If more advanced printing is needed, use the
265 * {@link #getPrintable} method.
266 * </dl>
267 *
268 * <p>
269 * <strong>Warning:</strong>
270 * Serialized objects of this class will not be compatible with
271 * future Swing releases. The current serialization support is
272 * appropriate for short term storage or RMI between applications running
273 * the same version of Swing. As of 1.4, support for long term storage
274 * of all JavaBeans™
275 * has been added to the <code>java.beans</code> package.
276 * Please see {@link java.beans.XMLEncoder}.
277 *
278 * @beaninfo
279 * attribute: isContainer false
280 *
281 * @author Timothy Prinzing
282 * @author Igor Kushnirskiy (printing support)
283 * @see Document
284 * @see DocumentEvent
285 * @see DocumentListener
286 * @see Caret
287 * @see CaretEvent
288 * @see CaretListener
289 * @see TextUI
290 * @see View
291 * @see ViewFactory
292 */
293 @SuppressWarnings("serial") // Same-version serialization only
294 public abstract class JTextComponent extends JComponent implements Scrollable, Accessible
295 {
296 /**
297 * Creates a new <code>JTextComponent</code>.
298 * Listeners for caret events are established, and the pluggable
299 * UI installed. The component is marked as editable. No layout manager
300 * is used, because layout is managed by the view subsystem of text.
301 * The document model is set to <code>null</code>.
302 */
303 public JTextComponent() {
304 super();
305 // enable InputMethodEvent for on-the-spot pre-editing
306 enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.INPUT_METHOD_EVENT_MASK);
307 caretEvent = new MutableCaretEvent(this);
308 addMouseListener(caretEvent);
309 addFocusListener(caretEvent);
310 setEditable(true);
311 setDragEnabled(false);
312 setLayout(null); // layout is managed by View hierarchy
357 * @param listener the listener to be removed
358 * @see javax.swing.event.CaretEvent
359 */
360 public void removeCaretListener(CaretListener listener) {
361 listenerList.remove(CaretListener.class, listener);
362 }
363
364 /**
365 * Returns an array of all the caret listeners
366 * registered on this text component.
367 *
368 * @return all of this component's <code>CaretListener</code>s
369 * or an empty
370 * array if no caret listeners are currently registered
371 *
372 * @see #addCaretListener
373 * @see #removeCaretListener
374 *
375 * @since 1.4
376 */
377 public CaretListener[] getCaretListeners() {
378 return listenerList.getListeners(CaretListener.class);
379 }
380
381 /**
382 * Notifies all listeners that have registered interest for
383 * notification on this event type. The event instance
384 * is lazily created using the parameters passed into
385 * the fire method. The listener list is processed in a
386 * last-to-first manner.
387 *
388 * @param e the event
389 * @see EventListenerList
390 */
391 protected void fireCaretUpdate(CaretEvent e) {
392 // Guaranteed to return a non-null array
393 Object[] listeners = listenerList.getListenerList();
394 // Process the listeners last to first, notifying
395 // those that are interested in this event
396 for (int i = listeners.length-2; i>=0; i-=2) {
397 if (listeners[i]==CaretListener.class) {
398 ((CaretListener)listeners[i+1]).caretUpdate(e);
399 }
400 }
401 }
402
403 /**
404 * Associates the editor with a text document.
405 * The currently registered factory is used to build a view for
406 * the document, which gets displayed by the editor after revalidation.
407 * A PropertyChange event ("document") is propagated to each listener.
408 *
409 * @param doc the document to display/edit
410 * @see #getDocument
411 * @beaninfo
412 * description: the text document model
413 * bound: true
414 * expert: true
415 */
416 public void setDocument(Document doc) {
417 Document old = model;
418
419 /*
420 * acquire a read lock on the old model to prevent notification of
421 * mutations while we disconnecting the old model.
422 */
423 try {
424 if (old instanceof AbstractDocument) {
425 ((AbstractDocument)old).readLock();
426 }
427 if (accessibleContext != null) {
428 model.removeDocumentListener(
429 ((AccessibleJTextComponent)accessibleContext));
430 }
431 if (inputMethodRequestsHandler != null) {
432 model.removeDocumentListener((DocumentListener)inputMethodRequestsHandler);
433 }
434 model = doc;
435
478 // ComponentOrientation property.
479 Document doc = getDocument();
480 if( doc != null ) {
481 Boolean runDir = o.isLeftToRight()
482 ? TextAttribute.RUN_DIRECTION_LTR
483 : TextAttribute.RUN_DIRECTION_RTL;
484 doc.putProperty( TextAttribute.RUN_DIRECTION, runDir );
485 }
486 super.setComponentOrientation( o );
487 }
488
489 /**
490 * Fetches the command list for the editor. This is
491 * the list of commands supported by the plugged-in UI
492 * augmented by the collection of commands that the
493 * editor itself supports. These are useful for binding
494 * to events, such as in a keymap.
495 *
496 * @return the command list
497 */
498 public Action[] getActions() {
499 return getUI().getEditorKit(this).getActions();
500 }
501
502 /**
503 * Sets margin space between the text component's border
504 * and its text. The text component's default <code>Border</code>
505 * object will use this value to create the proper margin.
506 * However, if a non-default border is set on the text component,
507 * it is that <code>Border</code> object's responsibility to create the
508 * appropriate margin space (else this property will effectively
509 * be ignored). This causes a redraw of the component.
510 * A PropertyChange event ("margin") is sent to all listeners.
511 *
512 * @param m the space between the border and the text
513 * @beaninfo
514 * description: desired space between the border and text area
515 * bound: true
516 */
517 public void setMargin(Insets m) {
518 Insets old = margin;
519 margin = m;
520 firePropertyChange("margin", old, m);
521 invalidate();
522 }
523
524 /**
525 * Returns the margin between the text component's border and
526 * its text.
527 *
528 * @return the margin
529 */
530 public Insets getMargin() {
531 return margin;
532 }
533
534 /**
535 * Sets the <code>NavigationFilter</code>. <code>NavigationFilter</code>
536 * is used by <code>DefaultCaret</code> and the default cursor movement
557
558 /**
559 * Fetches the caret that allows text-oriented navigation over
560 * the view.
561 *
562 * @return the caret
563 */
564 @Transient
565 public Caret getCaret() {
566 return caret;
567 }
568
569 /**
570 * Sets the caret to be used. By default this will be set
571 * by the UI that gets installed. This can be changed to
572 * a custom caret if desired. Setting the caret results in a
573 * PropertyChange event ("caret") being fired.
574 *
575 * @param c the caret
576 * @see #getCaret
577 * @beaninfo
578 * description: the caret used to select/navigate
579 * bound: true
580 * expert: true
581 */
582 public void setCaret(Caret c) {
583 if (caret != null) {
584 caret.removeChangeListener(caretEvent);
585 caret.deinstall(this);
586 }
587 Caret old = caret;
588 caret = c;
589 if (caret != null) {
590 caret.install(this);
591 caret.addChangeListener(caretEvent);
592 }
593 firePropertyChange("caret", old, caret);
594 }
595
596 /**
597 * Fetches the object responsible for making highlights.
598 *
599 * @return the highlighter
600 */
601 public Highlighter getHighlighter() {
602 return highlighter;
603 }
604
605 /**
606 * Sets the highlighter to be used. By default this will be set
607 * by the UI that gets installed. This can be changed to
608 * a custom highlighter if desired. The highlighter can be set to
609 * <code>null</code> to disable it.
610 * A PropertyChange event ("highlighter") is fired
611 * when a new highlighter is installed.
612 *
613 * @param h the highlighter
614 * @see #getHighlighter
615 * @beaninfo
616 * description: object responsible for background highlights
617 * bound: true
618 * expert: true
619 */
620 public void setHighlighter(Highlighter h) {
621 if (highlighter != null) {
622 highlighter.deinstall(this);
623 }
624 Highlighter old = highlighter;
625 highlighter = h;
626 if (highlighter != null) {
627 highlighter.install(this);
628 }
629 firePropertyChange("highlighter", old, h);
630 }
631
632 /**
633 * Sets the keymap to use for binding events to
634 * actions. Setting to <code>null</code> effectively disables
635 * keyboard input.
636 * A PropertyChange event ("keymap") is fired when a new keymap
637 * is installed.
638 *
639 * @param map the keymap
640 * @see #getKeymap
641 * @beaninfo
642 * description: set of key event to action bindings to use
643 * bound: true
644 */
645 public void setKeymap(Keymap map) {
646 Keymap old = keymap;
647 keymap = map;
648 firePropertyChange("keymap", old, keymap);
649 updateInputMap(old, map);
650 }
651
652 /**
653 * Turns on or off automatic drag handling. In order to enable automatic
654 * drag handling, this property should be set to {@code true}, and the
655 * component's {@code TransferHandler} needs to be {@code non-null}.
656 * The default value of the {@code dragEnabled} property is {@code false}.
657 * <p>
658 * The job of honoring this property, and recognizing a user drag gesture,
659 * lies with the look and feel implementation, and in particular, the component's
660 * {@code TextUI}. When automatic drag handling is enabled, most look and
661 * feels (including those that subclass {@code BasicLookAndFeel}) begin a
662 * drag and drop operation whenever the user presses the mouse button over
663 * a selection and then moves the mouse a few pixels. Setting this property to
664 * {@code true} can therefore have a subtle effect on how selections behave.
665 * <p>
666 * If a look and feel is used that ignores this property, you can still
667 * begin a drag and drop operation by calling {@code exportAsDrag} on the
668 * component's {@code TransferHandler}.
669 *
670 * @param b whether or not to enable automatic drag handling
671 * @exception HeadlessException if
672 * <code>b</code> is <code>true</code> and
673 * <code>GraphicsEnvironment.isHeadless()</code>
674 * returns <code>true</code>
675 * @see java.awt.GraphicsEnvironment#isHeadless
676 * @see #getDragEnabled
677 * @see #setTransferHandler
678 * @see TransferHandler
679 * @since 1.4
680 *
681 * @beaninfo
682 * description: determines whether automatic drag handling is enabled
683 * bound: false
684 */
685 public void setDragEnabled(boolean b) {
686 checkDragEnabled(b);
687 dragEnabled = b;
688 }
689
690 private static void checkDragEnabled(boolean b) {
691 if (b && GraphicsEnvironment.isHeadless()) {
692 throw new HeadlessException();
693 }
694 }
695
696 /**
697 * Returns whether or not automatic drag handling is enabled.
698 *
699 * @return the value of the {@code dragEnabled} property
700 * @see #setDragEnabled
701 * @since 1.4
702 */
703 public boolean getDragEnabled() {
704 return dragEnabled;
936 }
937
938 /**
939 * Returns the location that this component should visually indicate
940 * as the drop location during a DnD operation over the component,
941 * or {@code null} if no location is to currently be shown.
942 * <p>
943 * This method is not meant for querying the drop location
944 * from a {@code TransferHandler}, as the drop location is only
945 * set after the {@code TransferHandler}'s <code>canImport</code>
946 * has returned and has allowed for the location to be shown.
947 * <p>
948 * When this property changes, a property change event with
949 * name "dropLocation" is fired by the component.
950 *
951 * @return the drop location
952 * @see #setDropMode
953 * @see TransferHandler#canImport(TransferHandler.TransferSupport)
954 * @since 1.6
955 */
956 public final DropLocation getDropLocation() {
957 return dropLocation;
958 }
959
960
961 /**
962 * Updates the <code>InputMap</code>s in response to a
963 * <code>Keymap</code> change.
964 * @param oldKm the old <code>Keymap</code>
965 * @param newKm the new <code>Keymap</code>
966 */
967 void updateInputMap(Keymap oldKm, Keymap newKm) {
968 // Locate the current KeymapWrapper.
969 InputMap km = getInputMap(JComponent.WHEN_FOCUSED);
970 InputMap last = km;
971 while (km != null && !(km instanceof KeymapWrapper)) {
972 last = km;
973 km = km.getParent();
974 }
975 if (km != null) {
1201 }
1202
1203 /**
1204 * Fetches the current color used to render the
1205 * caret.
1206 *
1207 * @return the color
1208 */
1209 public Color getCaretColor() {
1210 return caretColor;
1211 }
1212
1213 /**
1214 * Sets the current color used to render the caret.
1215 * Setting to <code>null</code> effectively restores the default color.
1216 * Setting the color results in a PropertyChange event ("caretColor")
1217 * being fired.
1218 *
1219 * @param c the color
1220 * @see #getCaretColor
1221 * @beaninfo
1222 * description: the color used to render the caret
1223 * bound: true
1224 * preferred: true
1225 */
1226 public void setCaretColor(Color c) {
1227 Color old = caretColor;
1228 caretColor = c;
1229 firePropertyChange("caretColor", old, caretColor);
1230 }
1231
1232 /**
1233 * Fetches the current color used to render the
1234 * selection.
1235 *
1236 * @return the color
1237 */
1238 public Color getSelectionColor() {
1239 return selectionColor;
1240 }
1241
1242 /**
1243 * Sets the current color used to render the selection.
1244 * Setting the color to <code>null</code> is the same as setting
1245 * <code>Color.white</code>. Setting the color results in a
1246 * PropertyChange event ("selectionColor").
1247 *
1248 * @param c the color
1249 * @see #getSelectionColor
1250 * @beaninfo
1251 * description: color used to render selection background
1252 * bound: true
1253 * preferred: true
1254 */
1255 public void setSelectionColor(Color c) {
1256 Color old = selectionColor;
1257 selectionColor = c;
1258 firePropertyChange("selectionColor", old, selectionColor);
1259 }
1260
1261 /**
1262 * Fetches the current color used to render the
1263 * selected text.
1264 *
1265 * @return the color
1266 */
1267 public Color getSelectedTextColor() {
1268 return selectedTextColor;
1269 }
1270
1271 /**
1272 * Sets the current color used to render the selected text.
1273 * Setting the color to <code>null</code> is the same as
1274 * <code>Color.black</code>. Setting the color results in a
1275 * PropertyChange event ("selectedTextColor") being fired.
1276 *
1277 * @param c the color
1278 * @see #getSelectedTextColor
1279 * @beaninfo
1280 * description: color used to render selected text
1281 * bound: true
1282 * preferred: true
1283 */
1284 public void setSelectedTextColor(Color c) {
1285 Color old = selectedTextColor;
1286 selectedTextColor = c;
1287 firePropertyChange("selectedTextColor", old, selectedTextColor);
1288 }
1289
1290 /**
1291 * Fetches the current color used to render the
1292 * disabled text.
1293 *
1294 * @return the color
1295 */
1296 public Color getDisabledTextColor() {
1297 return disabledTextColor;
1298 }
1299
1300 /**
1301 * Sets the current color used to render the
1302 * disabled text. Setting the color fires off a
1303 * PropertyChange event ("disabledTextColor").
1304 *
1305 * @param c the color
1306 * @see #getDisabledTextColor
1307 * @beaninfo
1308 * description: color used to render disabled text
1309 * bound: true
1310 * preferred: true
1311 */
1312 public void setDisabledTextColor(Color c) {
1313 Color old = disabledTextColor;
1314 disabledTextColor = c;
1315 firePropertyChange("disabledTextColor", old, disabledTextColor);
1316 }
1317
1318 /**
1319 * Replaces the currently selected content with new content
1320 * represented by the given string. If there is no selection
1321 * this amounts to an insert of the given text. If there
1322 * is no replacement text this amounts to a removal of the
1323 * current selection.
1324 * <p>
1325 * This is the method that is used by the default implementation
1326 * of the action for inserting content that gets bound to the
1327 * keymap actions.
1328 *
1329 * @param content the content to replace the selection with
1330 */
1331 public void replaceSelection(String content) {
1516
1517 /**
1518 * The bound property name for the focus accelerator.
1519 */
1520 public static final String FOCUS_ACCELERATOR_KEY = "focusAcceleratorKey";
1521
1522 /**
1523 * Sets the key accelerator that will cause the receiving text
1524 * component to get the focus. The accelerator will be the
1525 * key combination of the platform-specific modifier key and
1526 * the character given (converted to upper case). For example,
1527 * the ALT key is used as a modifier on Windows and the CTRL+ALT
1528 * combination is used on Mac. By default, there is no focus
1529 * accelerator key. Any previous key accelerator setting will be
1530 * superseded. A '\0' key setting will be registered, and has the
1531 * effect of turning off the focus accelerator. When the new key
1532 * is set, a PropertyChange event (FOCUS_ACCELERATOR_KEY) will be fired.
1533 *
1534 * @param aKey the key
1535 * @see #getFocusAccelerator
1536 * @beaninfo
1537 * description: accelerator character used to grab focus
1538 * bound: true
1539 */
1540 public void setFocusAccelerator(char aKey) {
1541 aKey = Character.toUpperCase(aKey);
1542 char old = focusAccelerator;
1543 focusAccelerator = aKey;
1544 // Fix for 4341002: value of FOCUS_ACCELERATOR_KEY is wrong.
1545 // So we fire both FOCUS_ACCELERATOR_KEY, for compatibility,
1546 // and the correct event here.
1547 firePropertyChange(FOCUS_ACCELERATOR_KEY, old, focusAccelerator);
1548 firePropertyChange("focusAccelerator", old, focusAccelerator);
1549 }
1550
1551 /**
1552 * Returns the key accelerator that will cause the receiving
1553 * text component to get the focus. Return '\0' if no focus
1554 * accelerator has been set.
1555 *
1556 * @return the key
1557 */
1558 public char getFocusAccelerator() {
1559 return focusAccelerator;
1613 super.removeNotify();
1614 if (getFocusedComponent() == this) {
1615 AppContext.getAppContext().remove(FOCUSED_COMPONENT);
1616 }
1617 }
1618
1619 // --- java.awt.TextComponent methods ------------------------
1620
1621 /**
1622 * Sets the position of the text insertion caret for the
1623 * <code>TextComponent</code>. Note that the caret tracks change,
1624 * so this may move if the underlying text of the component is changed.
1625 * If the document is <code>null</code>, does nothing. The position
1626 * must be between 0 and the length of the component's text or else
1627 * an exception is thrown.
1628 *
1629 * @param position the position
1630 * @exception IllegalArgumentException if the value supplied
1631 * for <code>position</code> is less than zero or greater
1632 * than the component's text length
1633 * @beaninfo
1634 * description: the caret position
1635 */
1636 public void setCaretPosition(int position) {
1637 Document doc = getDocument();
1638 if (doc != null) {
1639 if (position > doc.getLength() || position < 0) {
1640 throw new IllegalArgumentException("bad position: " + position);
1641 }
1642 caret.setDot(position);
1643 }
1644 }
1645
1646 /**
1647 * Returns the position of the text insertion caret for the
1648 * text component.
1649 *
1650 * @return the position of the text insertion caret for the
1651 * text component ≥ 0
1652 */
1653 @Transient
1654 public int getCaretPosition() {
1655 return caret.getDot();
1656 }
1657
1658 /**
1659 * Sets the text of this <code>TextComponent</code>
1660 * to the specified text. If the text is <code>null</code>
1661 * or empty, has the effect of simply deleting the old text.
1662 * When text has been inserted, the resulting caret location
1663 * is determined by the implementation of the caret class.
1664 *
1665 * <p>
1666 * Note that text is not a bound property, so no <code>PropertyChangeEvent
1667 * </code> is fired when it changes. To listen for changes to the text,
1668 * use <code>DocumentListener</code>.
1669 *
1670 * @param t the new text to be set
1671 * @see #getText
1672 * @see DefaultCaret
1673 * @beaninfo
1674 * description: the text of this component
1675 */
1676 public void setText(String t) {
1677 try {
1678 Document doc = getDocument();
1679 if (doc instanceof AbstractDocument) {
1680 ((AbstractDocument)doc).replace(0, doc.getLength(), t,null);
1681 }
1682 else {
1683 doc.remove(0, doc.getLength());
1684 doc.insertString(0, t, null);
1685 }
1686 } catch (BadLocationException e) {
1687 UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this);
1688 }
1689 }
1690
1691 /**
1692 * Returns the text contained in this <code>TextComponent</code>.
1693 * If the underlying document is <code>null</code>,
1694 * will give a <code>NullPointerException</code>.
1695 *
1705 Document doc = getDocument();
1706 String txt;
1707 try {
1708 txt = doc.getText(0, doc.getLength());
1709 } catch (BadLocationException e) {
1710 txt = null;
1711 }
1712 return txt;
1713 }
1714
1715 /**
1716 * Returns the selected text contained in this
1717 * <code>TextComponent</code>. If the selection is
1718 * <code>null</code> or the document empty, returns <code>null</code>.
1719 *
1720 * @return the text
1721 * @exception IllegalArgumentException if the selection doesn't
1722 * have a valid mapping into the document for some reason
1723 * @see #setText
1724 */
1725 public String getSelectedText() {
1726 String txt = null;
1727 int p0 = Math.min(caret.getDot(), caret.getMark());
1728 int p1 = Math.max(caret.getDot(), caret.getMark());
1729 if (p0 != p1) {
1730 try {
1731 Document doc = getDocument();
1732 txt = doc.getText(p0, p1 - p0);
1733 } catch (BadLocationException e) {
1734 throw new IllegalArgumentException(e.getMessage());
1735 }
1736 }
1737 return txt;
1738 }
1739
1740 /**
1741 * Returns the boolean indicating whether this
1742 * <code>TextComponent</code> is editable or not.
1743 *
1744 * @return the boolean value
1745 * @see #setEditable
1746 */
1747 public boolean isEditable() {
1748 return editable;
1749 }
1750
1751 /**
1752 * Sets the specified boolean to indicate whether or not this
1753 * <code>TextComponent</code> should be editable.
1754 * A PropertyChange event ("editable") is fired when the
1755 * state is changed.
1756 *
1757 * @param b the boolean to be set
1758 * @see #isEditable
1759 * @beaninfo
1760 * description: specifies if the text can be edited
1761 * bound: true
1762 */
1763 public void setEditable(boolean b) {
1764 if (b != editable) {
1765 boolean oldVal = editable;
1766 editable = b;
1767 enableInputMethods(editable);
1768 firePropertyChange("editable", Boolean.valueOf(oldVal), Boolean.valueOf(editable));
1769 repaint();
1770 }
1771 }
1772
1773 /**
1774 * Returns the selected text's start position. Return 0 for an
1775 * empty document, or the value of dot if no selection.
1776 *
1777 * @return the start position ≥ 0
1778 */
1779 @Transient
1780 public int getSelectionStart() {
1781 int start = Math.min(caret.getDot(), caret.getMark());
1782 return start;
1783 }
1784
1785 /**
1786 * Sets the selection start to the specified position. The new
1787 * starting point is constrained to be before or at the current
1788 * selection end.
1789 * <p>
1790 * This is available for backward compatibility to code
1791 * that called this method on <code>java.awt.TextComponent</code>.
1792 * This is implemented to forward to the <code>Caret</code>
1793 * implementation which is where the actual selection is maintained.
1794 *
1795 * @param selectionStart the start position of the text ≥ 0
1796 * @beaninfo
1797 * description: starting location of the selection.
1798 */
1799 public void setSelectionStart(int selectionStart) {
1800 /* Route through select method to enforce consistent policy
1801 * between selectionStart and selectionEnd.
1802 */
1803 select(selectionStart, getSelectionEnd());
1804 }
1805
1806 /**
1807 * Returns the selected text's end position. Return 0 if the document
1808 * is empty, or the value of dot if there is no selection.
1809 *
1810 * @return the end position ≥ 0
1811 */
1812 @Transient
1813 public int getSelectionEnd() {
1814 int end = Math.max(caret.getDot(), caret.getMark());
1815 return end;
1816 }
1817
1818 /**
1819 * Sets the selection end to the specified position. The new
1820 * end point is constrained to be at or after the current
1821 * selection start.
1822 * <p>
1823 * This is available for backward compatibility to code
1824 * that called this method on <code>java.awt.TextComponent</code>.
1825 * This is implemented to forward to the <code>Caret</code>
1826 * implementation which is where the actual selection is maintained.
1827 *
1828 * @param selectionEnd the end position of the text ≥ 0
1829 * @beaninfo
1830 * description: ending location of the selection.
1831 */
1832 public void setSelectionEnd(int selectionEnd) {
1833 /* Route through select method to enforce consistent policy
1834 * between selectionStart and selectionEnd.
1835 */
1836 select(getSelectionStart(), selectionEnd);
1837 }
1838
1839 /**
1840 * Selects the text between the specified start and end positions.
1841 * <p>
1842 * This method sets the start and end positions of the
1843 * selected text, enforcing the restriction that the start position
1844 * must be greater than or equal to zero. The end position must be
1845 * greater than or equal to the start position, and less than or
1846 * equal to the length of the text component's text.
1847 * <p>
1848 * If the caller supplies values that are inconsistent or out of
1849 * bounds, the method enforces these constraints silently, and
1850 * without failure. Specifically, if the start position or end
1851 * position is greater than the length of the text, it is reset to
1927 if (retValue == null) {
1928 TextUI ui = getUI();
1929 if (ui != null) {
1930 retValue = ui.getToolTipText(this, new Point(event.getX(),
1931 event.getY()));
1932 }
1933 }
1934 return retValue;
1935 }
1936
1937 // --- Scrollable methods ---------------------------------------------
1938
1939 /**
1940 * Returns the preferred size of the viewport for a view component.
1941 * This is implemented to do the default behavior of returning
1942 * the preferred size of the component.
1943 *
1944 * @return the <code>preferredSize</code> of a <code>JViewport</code>
1945 * whose view is this <code>Scrollable</code>
1946 */
1947 public Dimension getPreferredScrollableViewportSize() {
1948 return getPreferredSize();
1949 }
1950
1951
1952 /**
1953 * Components that display logical rows or columns should compute
1954 * the scroll increment that will completely expose one new row
1955 * or column, depending on the value of orientation. Ideally,
1956 * components should handle a partially exposed row or column by
1957 * returning the distance required to completely expose the item.
1958 * <p>
1959 * The default implementation of this is to simply return 10% of
1960 * the visible area. Subclasses are likely to be able to provide
1961 * a much more reasonable value.
1962 *
1963 * @param visibleRect the view area visible within the viewport
1964 * @param orientation either <code>SwingConstants.VERTICAL</code> or
1965 * <code>SwingConstants.HORIZONTAL</code>
1966 * @param direction less than zero to scroll up/left, greater than
2010 }
2011 }
2012
2013
2014 /**
2015 * Returns true if a viewport should always force the width of this
2016 * <code>Scrollable</code> to match the width of the viewport.
2017 * For example a normal text view that supported line wrapping
2018 * would return true here, since it would be undesirable for
2019 * wrapped lines to disappear beyond the right
2020 * edge of the viewport. Note that returning true for a
2021 * <code>Scrollable</code> whose ancestor is a <code>JScrollPane</code>
2022 * effectively disables horizontal scrolling.
2023 * <p>
2024 * Scrolling containers, like <code>JViewport</code>,
2025 * will use this method each time they are validated.
2026 *
2027 * @return true if a viewport should force the <code>Scrollable</code>s
2028 * width to match its own
2029 */
2030 public boolean getScrollableTracksViewportWidth() {
2031 Container parent = SwingUtilities.getUnwrappedParent(this);
2032 if (parent instanceof JViewport) {
2033 return parent.getWidth() > getPreferredSize().width;
2034 }
2035 return false;
2036 }
2037
2038 /**
2039 * Returns true if a viewport should always force the height of this
2040 * <code>Scrollable</code> to match the height of the viewport.
2041 * For example a columnar text view that flowed text in left to
2042 * right columns could effectively disable vertical scrolling by
2043 * returning true here.
2044 * <p>
2045 * Scrolling containers, like <code>JViewport</code>,
2046 * will use this method each time they are validated.
2047 *
2048 * @return true if a viewport should force the Scrollables height
2049 * to match its own
2050 */
2051 public boolean getScrollableTracksViewportHeight() {
2052 Container parent = SwingUtilities.getUnwrappedParent(this);
2053 if (parent instanceof JViewport) {
2054 return parent.getHeight() > getPreferredSize().height;
2055 }
2056 return false;
2057 }
2058
2059
2060 //////////////////
2061 // Printing Support
2062 //////////////////
2063
2064 /**
2065 * A convenience print method that displays a print dialog, and then
2066 * prints this {@code JTextComponent} in <i>interactive</i> mode with no
2067 * header or footer text. Note: this method
2068 * blocks until printing is done.
2069 * <p>
2070 * Note: In <i>headless</i> mode, no dialogs will be shown.
2465 }
2466
2467
2468 /////////////////
2469 // Accessibility support
2470 ////////////////
2471
2472
2473 /**
2474 * Gets the <code>AccessibleContext</code> associated with this
2475 * <code>JTextComponent</code>. For text components,
2476 * the <code>AccessibleContext</code> takes the form of an
2477 * <code>AccessibleJTextComponent</code>.
2478 * A new <code>AccessibleJTextComponent</code> instance
2479 * is created if necessary.
2480 *
2481 * @return an <code>AccessibleJTextComponent</code> that serves as the
2482 * <code>AccessibleContext</code> of this
2483 * <code>JTextComponent</code>
2484 */
2485 public AccessibleContext getAccessibleContext() {
2486 if (accessibleContext == null) {
2487 accessibleContext = new AccessibleJTextComponent();
2488 }
2489 return accessibleContext;
2490 }
2491
2492 /**
2493 * This class implements accessibility support for the
2494 * <code>JTextComponent</code> class. It provides an implementation of
2495 * the Java Accessibility API appropriate to menu user-interface elements.
2496 * <p>
2497 * <strong>Warning:</strong>
2498 * Serialized objects of this class will not be compatible with
2499 * future Swing releases. The current serialization support is
2500 * appropriate for short term storage or RMI between applications running
2501 * the same version of Swing. As of 1.4, support for long term storage
2502 * of all JavaBeans™
2503 * has been added to the <code>java.beans</code> package.
2504 * Please see {@link java.beans.XMLEncoder}.
4520 } else {
4521 switch (e.getID()) {
4522 case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED:
4523 replaceInputMethodText(e);
4524
4525 // fall through
4526
4527 case InputMethodEvent.CARET_POSITION_CHANGED:
4528 setInputMethodCaretPosition(e);
4529 break;
4530 }
4531 }
4532
4533 e.consume();
4534 }
4535 }
4536
4537 //
4538 // Overrides this method to become an active input method client.
4539 //
4540 public InputMethodRequests getInputMethodRequests() {
4541 if (inputMethodRequestsHandler == null) {
4542 inputMethodRequestsHandler = new InputMethodRequestsHandler();
4543 Document doc = getDocument();
4544 if (doc != null) {
4545 doc.addDocumentListener((DocumentListener)inputMethodRequestsHandler);
4546 }
4547 }
4548
4549 return inputMethodRequestsHandler;
4550 }
4551
4552 //
4553 // Overrides this method to watch the listener installed.
4554 //
4555 public void addInputMethodListener(InputMethodListener l) {
4556 super.addInputMethodListener(l);
4557 if (l != null) {
4558 needToSendKeyTypedEvent = false;
4559 checkedInputOverride = true;
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package javax.swing.text;
26
27 import com.sun.beans.util.Cache;
28
29 import java.security.AccessController;
30 import java.security.PrivilegedAction;
31
32 import java.beans.JavaBean;
33 import java.beans.BeanProperty;
34 import java.beans.Transient;
35 import java.util.HashMap;
36 import java.util.Hashtable;
37 import java.util.Enumeration;
38 import java.util.Vector;
39
40 import java.util.concurrent.*;
41
42 import java.io.*;
43
44 import java.awt.*;
45 import java.awt.event.*;
46 import java.awt.print.*;
47 import java.awt.datatransfer.*;
48 import java.awt.im.InputContext;
49 import java.awt.im.InputMethodRequests;
50 import java.awt.font.TextHitInfo;
51 import java.awt.font.TextAttribute;
52
53 import java.awt.print.Printable;
54 import java.awt.print.PrinterException;
55
56 import javax.print.PrintService;
57 import javax.print.attribute.PrintRequestAttributeSet;
58
59 import java.text.*;
60 import java.text.AttributedCharacterIterator.Attribute;
61
62 import javax.swing.*;
63 import javax.swing.event.*;
64 import javax.swing.plaf.*;
65
66 import javax.accessibility.*;
67
68 import javax.print.attribute.*;
69
70 import sun.awt.AppContext;
71
72 import sun.swing.PrintingStatus;
73 import sun.swing.SwingUtilities2;
74 import sun.swing.text.TextComponentPrintable;
75 import sun.swing.SwingAccessor;
76
77 /**
78 * <code>JTextComponent</code> is the base class for swing text
79 * components. It tries to be compatible with the
80 * <code>java.awt.TextComponent</code> class
81 * where it can reasonably do so. Also provided are other services
82 * for additional flexibility (beyond the pluggable UI and bean
83 * support).
84 * You can find information on how to use the functionality
85 * this class provides in
86 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/generaltext.html">General Rules for Using Text Components</a>,
87 * a section in <em>The Java Tutorial.</em>
88 *
89 * <dl>
90 * <dt><b>Caret Changes</b>
91 * <dd>
259 * <a href="DefaultEditorKit.html">DefaultEditorKit</a>.
260 *
261 *
262 * <dt><b>Printing support</b>
263 * <dd>
264 * Several {@link #print print} methods are provided for basic
265 * document printing. If more advanced printing is needed, use the
266 * {@link #getPrintable} method.
267 * </dl>
268 *
269 * <p>
270 * <strong>Warning:</strong>
271 * Serialized objects of this class will not be compatible with
272 * future Swing releases. The current serialization support is
273 * appropriate for short term storage or RMI between applications running
274 * the same version of Swing. As of 1.4, support for long term storage
275 * of all JavaBeans™
276 * has been added to the <code>java.beans</code> package.
277 * Please see {@link java.beans.XMLEncoder}.
278 *
279 * @author Timothy Prinzing
280 * @author Igor Kushnirskiy (printing support)
281 * @see Document
282 * @see DocumentEvent
283 * @see DocumentListener
284 * @see Caret
285 * @see CaretEvent
286 * @see CaretListener
287 * @see TextUI
288 * @see View
289 * @see ViewFactory
290 */
291 @JavaBean(defaultProperty = "UI")
292 @SwingContainer(false)
293 @SuppressWarnings("serial") // Same-version serialization only
294 public abstract class JTextComponent extends JComponent implements Scrollable, Accessible
295 {
296 /**
297 * Creates a new <code>JTextComponent</code>.
298 * Listeners for caret events are established, and the pluggable
299 * UI installed. The component is marked as editable. No layout manager
300 * is used, because layout is managed by the view subsystem of text.
301 * The document model is set to <code>null</code>.
302 */
303 public JTextComponent() {
304 super();
305 // enable InputMethodEvent for on-the-spot pre-editing
306 enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.INPUT_METHOD_EVENT_MASK);
307 caretEvent = new MutableCaretEvent(this);
308 addMouseListener(caretEvent);
309 addFocusListener(caretEvent);
310 setEditable(true);
311 setDragEnabled(false);
312 setLayout(null); // layout is managed by View hierarchy
357 * @param listener the listener to be removed
358 * @see javax.swing.event.CaretEvent
359 */
360 public void removeCaretListener(CaretListener listener) {
361 listenerList.remove(CaretListener.class, listener);
362 }
363
364 /**
365 * Returns an array of all the caret listeners
366 * registered on this text component.
367 *
368 * @return all of this component's <code>CaretListener</code>s
369 * or an empty
370 * array if no caret listeners are currently registered
371 *
372 * @see #addCaretListener
373 * @see #removeCaretListener
374 *
375 * @since 1.4
376 */
377 @BeanProperty(bound = false)
378 public CaretListener[] getCaretListeners() {
379 return listenerList.getListeners(CaretListener.class);
380 }
381
382 /**
383 * Notifies all listeners that have registered interest for
384 * notification on this event type. The event instance
385 * is lazily created using the parameters passed into
386 * the fire method. The listener list is processed in a
387 * last-to-first manner.
388 *
389 * @param e the event
390 * @see EventListenerList
391 */
392 protected void fireCaretUpdate(CaretEvent e) {
393 // Guaranteed to return a non-null array
394 Object[] listeners = listenerList.getListenerList();
395 // Process the listeners last to first, notifying
396 // those that are interested in this event
397 for (int i = listeners.length-2; i>=0; i-=2) {
398 if (listeners[i]==CaretListener.class) {
399 ((CaretListener)listeners[i+1]).caretUpdate(e);
400 }
401 }
402 }
403
404 /**
405 * Associates the editor with a text document.
406 * The currently registered factory is used to build a view for
407 * the document, which gets displayed by the editor after revalidation.
408 * A PropertyChange event ("document") is propagated to each listener.
409 *
410 * @param doc the document to display/edit
411 * @see #getDocument
412 */
413 @BeanProperty(expert = true, description
414 = "the text document model")
415 public void setDocument(Document doc) {
416 Document old = model;
417
418 /*
419 * acquire a read lock on the old model to prevent notification of
420 * mutations while we disconnecting the old model.
421 */
422 try {
423 if (old instanceof AbstractDocument) {
424 ((AbstractDocument)old).readLock();
425 }
426 if (accessibleContext != null) {
427 model.removeDocumentListener(
428 ((AccessibleJTextComponent)accessibleContext));
429 }
430 if (inputMethodRequestsHandler != null) {
431 model.removeDocumentListener((DocumentListener)inputMethodRequestsHandler);
432 }
433 model = doc;
434
477 // ComponentOrientation property.
478 Document doc = getDocument();
479 if( doc != null ) {
480 Boolean runDir = o.isLeftToRight()
481 ? TextAttribute.RUN_DIRECTION_LTR
482 : TextAttribute.RUN_DIRECTION_RTL;
483 doc.putProperty( TextAttribute.RUN_DIRECTION, runDir );
484 }
485 super.setComponentOrientation( o );
486 }
487
488 /**
489 * Fetches the command list for the editor. This is
490 * the list of commands supported by the plugged-in UI
491 * augmented by the collection of commands that the
492 * editor itself supports. These are useful for binding
493 * to events, such as in a keymap.
494 *
495 * @return the command list
496 */
497 @BeanProperty(bound = false)
498 public Action[] getActions() {
499 return getUI().getEditorKit(this).getActions();
500 }
501
502 /**
503 * Sets margin space between the text component's border
504 * and its text. The text component's default <code>Border</code>
505 * object will use this value to create the proper margin.
506 * However, if a non-default border is set on the text component,
507 * it is that <code>Border</code> object's responsibility to create the
508 * appropriate margin space (else this property will effectively
509 * be ignored). This causes a redraw of the component.
510 * A PropertyChange event ("margin") is sent to all listeners.
511 *
512 * @param m the space between the border and the text
513 */
514 @BeanProperty(description
515 = "desired space between the border and text area")
516 public void setMargin(Insets m) {
517 Insets old = margin;
518 margin = m;
519 firePropertyChange("margin", old, m);
520 invalidate();
521 }
522
523 /**
524 * Returns the margin between the text component's border and
525 * its text.
526 *
527 * @return the margin
528 */
529 public Insets getMargin() {
530 return margin;
531 }
532
533 /**
534 * Sets the <code>NavigationFilter</code>. <code>NavigationFilter</code>
535 * is used by <code>DefaultCaret</code> and the default cursor movement
556
557 /**
558 * Fetches the caret that allows text-oriented navigation over
559 * the view.
560 *
561 * @return the caret
562 */
563 @Transient
564 public Caret getCaret() {
565 return caret;
566 }
567
568 /**
569 * Sets the caret to be used. By default this will be set
570 * by the UI that gets installed. This can be changed to
571 * a custom caret if desired. Setting the caret results in a
572 * PropertyChange event ("caret") being fired.
573 *
574 * @param c the caret
575 * @see #getCaret
576 */
577 @BeanProperty(expert = true, description
578 = "the caret used to select/navigate")
579 public void setCaret(Caret c) {
580 if (caret != null) {
581 caret.removeChangeListener(caretEvent);
582 caret.deinstall(this);
583 }
584 Caret old = caret;
585 caret = c;
586 if (caret != null) {
587 caret.install(this);
588 caret.addChangeListener(caretEvent);
589 }
590 firePropertyChange("caret", old, caret);
591 }
592
593 /**
594 * Fetches the object responsible for making highlights.
595 *
596 * @return the highlighter
597 */
598 public Highlighter getHighlighter() {
599 return highlighter;
600 }
601
602 /**
603 * Sets the highlighter to be used. By default this will be set
604 * by the UI that gets installed. This can be changed to
605 * a custom highlighter if desired. The highlighter can be set to
606 * <code>null</code> to disable it.
607 * A PropertyChange event ("highlighter") is fired
608 * when a new highlighter is installed.
609 *
610 * @param h the highlighter
611 * @see #getHighlighter
612 */
613 @BeanProperty(expert = true, description
614 = "object responsible for background highlights")
615 public void setHighlighter(Highlighter h) {
616 if (highlighter != null) {
617 highlighter.deinstall(this);
618 }
619 Highlighter old = highlighter;
620 highlighter = h;
621 if (highlighter != null) {
622 highlighter.install(this);
623 }
624 firePropertyChange("highlighter", old, h);
625 }
626
627 /**
628 * Sets the keymap to use for binding events to
629 * actions. Setting to <code>null</code> effectively disables
630 * keyboard input.
631 * A PropertyChange event ("keymap") is fired when a new keymap
632 * is installed.
633 *
634 * @param map the keymap
635 * @see #getKeymap
636 */
637 @BeanProperty(description
638 = "set of key event to action bindings to use")
639 public void setKeymap(Keymap map) {
640 Keymap old = keymap;
641 keymap = map;
642 firePropertyChange("keymap", old, keymap);
643 updateInputMap(old, map);
644 }
645
646 /**
647 * Turns on or off automatic drag handling. In order to enable automatic
648 * drag handling, this property should be set to {@code true}, and the
649 * component's {@code TransferHandler} needs to be {@code non-null}.
650 * The default value of the {@code dragEnabled} property is {@code false}.
651 * <p>
652 * The job of honoring this property, and recognizing a user drag gesture,
653 * lies with the look and feel implementation, and in particular, the component's
654 * {@code TextUI}. When automatic drag handling is enabled, most look and
655 * feels (including those that subclass {@code BasicLookAndFeel}) begin a
656 * drag and drop operation whenever the user presses the mouse button over
657 * a selection and then moves the mouse a few pixels. Setting this property to
658 * {@code true} can therefore have a subtle effect on how selections behave.
659 * <p>
660 * If a look and feel is used that ignores this property, you can still
661 * begin a drag and drop operation by calling {@code exportAsDrag} on the
662 * component's {@code TransferHandler}.
663 *
664 * @param b whether or not to enable automatic drag handling
665 * @exception HeadlessException if
666 * <code>b</code> is <code>true</code> and
667 * <code>GraphicsEnvironment.isHeadless()</code>
668 * returns <code>true</code>
669 * @see java.awt.GraphicsEnvironment#isHeadless
670 * @see #getDragEnabled
671 * @see #setTransferHandler
672 * @see TransferHandler
673 * @since 1.4
674 */
675 @BeanProperty(bound = false, description
676 = "determines whether automatic drag handling is enabled")
677 public void setDragEnabled(boolean b) {
678 checkDragEnabled(b);
679 dragEnabled = b;
680 }
681
682 private static void checkDragEnabled(boolean b) {
683 if (b && GraphicsEnvironment.isHeadless()) {
684 throw new HeadlessException();
685 }
686 }
687
688 /**
689 * Returns whether or not automatic drag handling is enabled.
690 *
691 * @return the value of the {@code dragEnabled} property
692 * @see #setDragEnabled
693 * @since 1.4
694 */
695 public boolean getDragEnabled() {
696 return dragEnabled;
928 }
929
930 /**
931 * Returns the location that this component should visually indicate
932 * as the drop location during a DnD operation over the component,
933 * or {@code null} if no location is to currently be shown.
934 * <p>
935 * This method is not meant for querying the drop location
936 * from a {@code TransferHandler}, as the drop location is only
937 * set after the {@code TransferHandler}'s <code>canImport</code>
938 * has returned and has allowed for the location to be shown.
939 * <p>
940 * When this property changes, a property change event with
941 * name "dropLocation" is fired by the component.
942 *
943 * @return the drop location
944 * @see #setDropMode
945 * @see TransferHandler#canImport(TransferHandler.TransferSupport)
946 * @since 1.6
947 */
948 @BeanProperty(bound = false)
949 public final DropLocation getDropLocation() {
950 return dropLocation;
951 }
952
953
954 /**
955 * Updates the <code>InputMap</code>s in response to a
956 * <code>Keymap</code> change.
957 * @param oldKm the old <code>Keymap</code>
958 * @param newKm the new <code>Keymap</code>
959 */
960 void updateInputMap(Keymap oldKm, Keymap newKm) {
961 // Locate the current KeymapWrapper.
962 InputMap km = getInputMap(JComponent.WHEN_FOCUSED);
963 InputMap last = km;
964 while (km != null && !(km instanceof KeymapWrapper)) {
965 last = km;
966 km = km.getParent();
967 }
968 if (km != null) {
1194 }
1195
1196 /**
1197 * Fetches the current color used to render the
1198 * caret.
1199 *
1200 * @return the color
1201 */
1202 public Color getCaretColor() {
1203 return caretColor;
1204 }
1205
1206 /**
1207 * Sets the current color used to render the caret.
1208 * Setting to <code>null</code> effectively restores the default color.
1209 * Setting the color results in a PropertyChange event ("caretColor")
1210 * being fired.
1211 *
1212 * @param c the color
1213 * @see #getCaretColor
1214 */
1215 @BeanProperty(preferred = true, description
1216 = "the color used to render the caret")
1217 public void setCaretColor(Color c) {
1218 Color old = caretColor;
1219 caretColor = c;
1220 firePropertyChange("caretColor", old, caretColor);
1221 }
1222
1223 /**
1224 * Fetches the current color used to render the
1225 * selection.
1226 *
1227 * @return the color
1228 */
1229 public Color getSelectionColor() {
1230 return selectionColor;
1231 }
1232
1233 /**
1234 * Sets the current color used to render the selection.
1235 * Setting the color to <code>null</code> is the same as setting
1236 * <code>Color.white</code>. Setting the color results in a
1237 * PropertyChange event ("selectionColor").
1238 *
1239 * @param c the color
1240 * @see #getSelectionColor
1241 */
1242 @BeanProperty(preferred = true, description
1243 = "color used to render selection background")
1244 public void setSelectionColor(Color c) {
1245 Color old = selectionColor;
1246 selectionColor = c;
1247 firePropertyChange("selectionColor", old, selectionColor);
1248 }
1249
1250 /**
1251 * Fetches the current color used to render the
1252 * selected text.
1253 *
1254 * @return the color
1255 */
1256 public Color getSelectedTextColor() {
1257 return selectedTextColor;
1258 }
1259
1260 /**
1261 * Sets the current color used to render the selected text.
1262 * Setting the color to <code>null</code> is the same as
1263 * <code>Color.black</code>. Setting the color results in a
1264 * PropertyChange event ("selectedTextColor") being fired.
1265 *
1266 * @param c the color
1267 * @see #getSelectedTextColor
1268 */
1269 @BeanProperty(preferred = true, description
1270 = "color used to render selected text")
1271 public void setSelectedTextColor(Color c) {
1272 Color old = selectedTextColor;
1273 selectedTextColor = c;
1274 firePropertyChange("selectedTextColor", old, selectedTextColor);
1275 }
1276
1277 /**
1278 * Fetches the current color used to render the
1279 * disabled text.
1280 *
1281 * @return the color
1282 */
1283 public Color getDisabledTextColor() {
1284 return disabledTextColor;
1285 }
1286
1287 /**
1288 * Sets the current color used to render the
1289 * disabled text. Setting the color fires off a
1290 * PropertyChange event ("disabledTextColor").
1291 *
1292 * @param c the color
1293 * @see #getDisabledTextColor
1294 */
1295 @BeanProperty(preferred = true, description
1296 = "color used to render disabled text")
1297 public void setDisabledTextColor(Color c) {
1298 Color old = disabledTextColor;
1299 disabledTextColor = c;
1300 firePropertyChange("disabledTextColor", old, disabledTextColor);
1301 }
1302
1303 /**
1304 * Replaces the currently selected content with new content
1305 * represented by the given string. If there is no selection
1306 * this amounts to an insert of the given text. If there
1307 * is no replacement text this amounts to a removal of the
1308 * current selection.
1309 * <p>
1310 * This is the method that is used by the default implementation
1311 * of the action for inserting content that gets bound to the
1312 * keymap actions.
1313 *
1314 * @param content the content to replace the selection with
1315 */
1316 public void replaceSelection(String content) {
1501
1502 /**
1503 * The bound property name for the focus accelerator.
1504 */
1505 public static final String FOCUS_ACCELERATOR_KEY = "focusAcceleratorKey";
1506
1507 /**
1508 * Sets the key accelerator that will cause the receiving text
1509 * component to get the focus. The accelerator will be the
1510 * key combination of the platform-specific modifier key and
1511 * the character given (converted to upper case). For example,
1512 * the ALT key is used as a modifier on Windows and the CTRL+ALT
1513 * combination is used on Mac. By default, there is no focus
1514 * accelerator key. Any previous key accelerator setting will be
1515 * superseded. A '\0' key setting will be registered, and has the
1516 * effect of turning off the focus accelerator. When the new key
1517 * is set, a PropertyChange event (FOCUS_ACCELERATOR_KEY) will be fired.
1518 *
1519 * @param aKey the key
1520 * @see #getFocusAccelerator
1521 */
1522 @BeanProperty(description
1523 = "accelerator character used to grab focus")
1524 public void setFocusAccelerator(char aKey) {
1525 aKey = Character.toUpperCase(aKey);
1526 char old = focusAccelerator;
1527 focusAccelerator = aKey;
1528 // Fix for 4341002: value of FOCUS_ACCELERATOR_KEY is wrong.
1529 // So we fire both FOCUS_ACCELERATOR_KEY, for compatibility,
1530 // and the correct event here.
1531 firePropertyChange(FOCUS_ACCELERATOR_KEY, old, focusAccelerator);
1532 firePropertyChange("focusAccelerator", old, focusAccelerator);
1533 }
1534
1535 /**
1536 * Returns the key accelerator that will cause the receiving
1537 * text component to get the focus. Return '\0' if no focus
1538 * accelerator has been set.
1539 *
1540 * @return the key
1541 */
1542 public char getFocusAccelerator() {
1543 return focusAccelerator;
1597 super.removeNotify();
1598 if (getFocusedComponent() == this) {
1599 AppContext.getAppContext().remove(FOCUSED_COMPONENT);
1600 }
1601 }
1602
1603 // --- java.awt.TextComponent methods ------------------------
1604
1605 /**
1606 * Sets the position of the text insertion caret for the
1607 * <code>TextComponent</code>. Note that the caret tracks change,
1608 * so this may move if the underlying text of the component is changed.
1609 * If the document is <code>null</code>, does nothing. The position
1610 * must be between 0 and the length of the component's text or else
1611 * an exception is thrown.
1612 *
1613 * @param position the position
1614 * @exception IllegalArgumentException if the value supplied
1615 * for <code>position</code> is less than zero or greater
1616 * than the component's text length
1617 */
1618 @BeanProperty(bound = false, description
1619 = "the caret position")
1620 public void setCaretPosition(int position) {
1621 Document doc = getDocument();
1622 if (doc != null) {
1623 if (position > doc.getLength() || position < 0) {
1624 throw new IllegalArgumentException("bad position: " + position);
1625 }
1626 caret.setDot(position);
1627 }
1628 }
1629
1630 /**
1631 * Returns the position of the text insertion caret for the
1632 * text component.
1633 *
1634 * @return the position of the text insertion caret for the
1635 * text component ≥ 0
1636 */
1637 @Transient
1638 public int getCaretPosition() {
1639 return caret.getDot();
1640 }
1641
1642 /**
1643 * Sets the text of this <code>TextComponent</code>
1644 * to the specified text. If the text is <code>null</code>
1645 * or empty, has the effect of simply deleting the old text.
1646 * When text has been inserted, the resulting caret location
1647 * is determined by the implementation of the caret class.
1648 *
1649 * <p>
1650 * Note that text is not a bound property, so no <code>PropertyChangeEvent
1651 * </code> is fired when it changes. To listen for changes to the text,
1652 * use <code>DocumentListener</code>.
1653 *
1654 * @param t the new text to be set
1655 * @see #getText
1656 * @see DefaultCaret
1657 */
1658 @BeanProperty(bound = false, description
1659 = "the text of this component")
1660 public void setText(String t) {
1661 try {
1662 Document doc = getDocument();
1663 if (doc instanceof AbstractDocument) {
1664 ((AbstractDocument)doc).replace(0, doc.getLength(), t,null);
1665 }
1666 else {
1667 doc.remove(0, doc.getLength());
1668 doc.insertString(0, t, null);
1669 }
1670 } catch (BadLocationException e) {
1671 UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this);
1672 }
1673 }
1674
1675 /**
1676 * Returns the text contained in this <code>TextComponent</code>.
1677 * If the underlying document is <code>null</code>,
1678 * will give a <code>NullPointerException</code>.
1679 *
1689 Document doc = getDocument();
1690 String txt;
1691 try {
1692 txt = doc.getText(0, doc.getLength());
1693 } catch (BadLocationException e) {
1694 txt = null;
1695 }
1696 return txt;
1697 }
1698
1699 /**
1700 * Returns the selected text contained in this
1701 * <code>TextComponent</code>. If the selection is
1702 * <code>null</code> or the document empty, returns <code>null</code>.
1703 *
1704 * @return the text
1705 * @exception IllegalArgumentException if the selection doesn't
1706 * have a valid mapping into the document for some reason
1707 * @see #setText
1708 */
1709 @BeanProperty(bound = false)
1710 public String getSelectedText() {
1711 String txt = null;
1712 int p0 = Math.min(caret.getDot(), caret.getMark());
1713 int p1 = Math.max(caret.getDot(), caret.getMark());
1714 if (p0 != p1) {
1715 try {
1716 Document doc = getDocument();
1717 txt = doc.getText(p0, p1 - p0);
1718 } catch (BadLocationException e) {
1719 throw new IllegalArgumentException(e.getMessage());
1720 }
1721 }
1722 return txt;
1723 }
1724
1725 /**
1726 * Returns the boolean indicating whether this
1727 * <code>TextComponent</code> is editable or not.
1728 *
1729 * @return the boolean value
1730 * @see #setEditable
1731 */
1732 public boolean isEditable() {
1733 return editable;
1734 }
1735
1736 /**
1737 * Sets the specified boolean to indicate whether or not this
1738 * <code>TextComponent</code> should be editable.
1739 * A PropertyChange event ("editable") is fired when the
1740 * state is changed.
1741 *
1742 * @param b the boolean to be set
1743 * @see #isEditable
1744 */
1745 @BeanProperty(description
1746 = "specifies if the text can be edited")
1747 public void setEditable(boolean b) {
1748 if (b != editable) {
1749 boolean oldVal = editable;
1750 editable = b;
1751 enableInputMethods(editable);
1752 firePropertyChange("editable", Boolean.valueOf(oldVal), Boolean.valueOf(editable));
1753 repaint();
1754 }
1755 }
1756
1757 /**
1758 * Returns the selected text's start position. Return 0 for an
1759 * empty document, or the value of dot if no selection.
1760 *
1761 * @return the start position ≥ 0
1762 */
1763 @Transient
1764 public int getSelectionStart() {
1765 int start = Math.min(caret.getDot(), caret.getMark());
1766 return start;
1767 }
1768
1769 /**
1770 * Sets the selection start to the specified position. The new
1771 * starting point is constrained to be before or at the current
1772 * selection end.
1773 * <p>
1774 * This is available for backward compatibility to code
1775 * that called this method on <code>java.awt.TextComponent</code>.
1776 * This is implemented to forward to the <code>Caret</code>
1777 * implementation which is where the actual selection is maintained.
1778 *
1779 * @param selectionStart the start position of the text ≥ 0
1780 */
1781 @BeanProperty(bound = false, description
1782 = "starting location of the selection.")
1783 public void setSelectionStart(int selectionStart) {
1784 /* Route through select method to enforce consistent policy
1785 * between selectionStart and selectionEnd.
1786 */
1787 select(selectionStart, getSelectionEnd());
1788 }
1789
1790 /**
1791 * Returns the selected text's end position. Return 0 if the document
1792 * is empty, or the value of dot if there is no selection.
1793 *
1794 * @return the end position ≥ 0
1795 */
1796 @Transient
1797 public int getSelectionEnd() {
1798 int end = Math.max(caret.getDot(), caret.getMark());
1799 return end;
1800 }
1801
1802 /**
1803 * Sets the selection end to the specified position. The new
1804 * end point is constrained to be at or after the current
1805 * selection start.
1806 * <p>
1807 * This is available for backward compatibility to code
1808 * that called this method on <code>java.awt.TextComponent</code>.
1809 * This is implemented to forward to the <code>Caret</code>
1810 * implementation which is where the actual selection is maintained.
1811 *
1812 * @param selectionEnd the end position of the text ≥ 0
1813 */
1814 @BeanProperty(bound = false, description
1815 = "ending location of the selection.")
1816 public void setSelectionEnd(int selectionEnd) {
1817 /* Route through select method to enforce consistent policy
1818 * between selectionStart and selectionEnd.
1819 */
1820 select(getSelectionStart(), selectionEnd);
1821 }
1822
1823 /**
1824 * Selects the text between the specified start and end positions.
1825 * <p>
1826 * This method sets the start and end positions of the
1827 * selected text, enforcing the restriction that the start position
1828 * must be greater than or equal to zero. The end position must be
1829 * greater than or equal to the start position, and less than or
1830 * equal to the length of the text component's text.
1831 * <p>
1832 * If the caller supplies values that are inconsistent or out of
1833 * bounds, the method enforces these constraints silently, and
1834 * without failure. Specifically, if the start position or end
1835 * position is greater than the length of the text, it is reset to
1911 if (retValue == null) {
1912 TextUI ui = getUI();
1913 if (ui != null) {
1914 retValue = ui.getToolTipText(this, new Point(event.getX(),
1915 event.getY()));
1916 }
1917 }
1918 return retValue;
1919 }
1920
1921 // --- Scrollable methods ---------------------------------------------
1922
1923 /**
1924 * Returns the preferred size of the viewport for a view component.
1925 * This is implemented to do the default behavior of returning
1926 * the preferred size of the component.
1927 *
1928 * @return the <code>preferredSize</code> of a <code>JViewport</code>
1929 * whose view is this <code>Scrollable</code>
1930 */
1931 @BeanProperty(bound = false)
1932 public Dimension getPreferredScrollableViewportSize() {
1933 return getPreferredSize();
1934 }
1935
1936
1937 /**
1938 * Components that display logical rows or columns should compute
1939 * the scroll increment that will completely expose one new row
1940 * or column, depending on the value of orientation. Ideally,
1941 * components should handle a partially exposed row or column by
1942 * returning the distance required to completely expose the item.
1943 * <p>
1944 * The default implementation of this is to simply return 10% of
1945 * the visible area. Subclasses are likely to be able to provide
1946 * a much more reasonable value.
1947 *
1948 * @param visibleRect the view area visible within the viewport
1949 * @param orientation either <code>SwingConstants.VERTICAL</code> or
1950 * <code>SwingConstants.HORIZONTAL</code>
1951 * @param direction less than zero to scroll up/left, greater than
1995 }
1996 }
1997
1998
1999 /**
2000 * Returns true if a viewport should always force the width of this
2001 * <code>Scrollable</code> to match the width of the viewport.
2002 * For example a normal text view that supported line wrapping
2003 * would return true here, since it would be undesirable for
2004 * wrapped lines to disappear beyond the right
2005 * edge of the viewport. Note that returning true for a
2006 * <code>Scrollable</code> whose ancestor is a <code>JScrollPane</code>
2007 * effectively disables horizontal scrolling.
2008 * <p>
2009 * Scrolling containers, like <code>JViewport</code>,
2010 * will use this method each time they are validated.
2011 *
2012 * @return true if a viewport should force the <code>Scrollable</code>s
2013 * width to match its own
2014 */
2015 @BeanProperty(bound = false)
2016 public boolean getScrollableTracksViewportWidth() {
2017 Container parent = SwingUtilities.getUnwrappedParent(this);
2018 if (parent instanceof JViewport) {
2019 return parent.getWidth() > getPreferredSize().width;
2020 }
2021 return false;
2022 }
2023
2024 /**
2025 * Returns true if a viewport should always force the height of this
2026 * <code>Scrollable</code> to match the height of the viewport.
2027 * For example a columnar text view that flowed text in left to
2028 * right columns could effectively disable vertical scrolling by
2029 * returning true here.
2030 * <p>
2031 * Scrolling containers, like <code>JViewport</code>,
2032 * will use this method each time they are validated.
2033 *
2034 * @return true if a viewport should force the Scrollables height
2035 * to match its own
2036 */
2037 @BeanProperty(bound = false)
2038 public boolean getScrollableTracksViewportHeight() {
2039 Container parent = SwingUtilities.getUnwrappedParent(this);
2040 if (parent instanceof JViewport) {
2041 return parent.getHeight() > getPreferredSize().height;
2042 }
2043 return false;
2044 }
2045
2046
2047 //////////////////
2048 // Printing Support
2049 //////////////////
2050
2051 /**
2052 * A convenience print method that displays a print dialog, and then
2053 * prints this {@code JTextComponent} in <i>interactive</i> mode with no
2054 * header or footer text. Note: this method
2055 * blocks until printing is done.
2056 * <p>
2057 * Note: In <i>headless</i> mode, no dialogs will be shown.
2452 }
2453
2454
2455 /////////////////
2456 // Accessibility support
2457 ////////////////
2458
2459
2460 /**
2461 * Gets the <code>AccessibleContext</code> associated with this
2462 * <code>JTextComponent</code>. For text components,
2463 * the <code>AccessibleContext</code> takes the form of an
2464 * <code>AccessibleJTextComponent</code>.
2465 * A new <code>AccessibleJTextComponent</code> instance
2466 * is created if necessary.
2467 *
2468 * @return an <code>AccessibleJTextComponent</code> that serves as the
2469 * <code>AccessibleContext</code> of this
2470 * <code>JTextComponent</code>
2471 */
2472 @BeanProperty(bound = false)
2473 public AccessibleContext getAccessibleContext() {
2474 if (accessibleContext == null) {
2475 accessibleContext = new AccessibleJTextComponent();
2476 }
2477 return accessibleContext;
2478 }
2479
2480 /**
2481 * This class implements accessibility support for the
2482 * <code>JTextComponent</code> class. It provides an implementation of
2483 * the Java Accessibility API appropriate to menu user-interface elements.
2484 * <p>
2485 * <strong>Warning:</strong>
2486 * Serialized objects of this class will not be compatible with
2487 * future Swing releases. The current serialization support is
2488 * appropriate for short term storage or RMI between applications running
2489 * the same version of Swing. As of 1.4, support for long term storage
2490 * of all JavaBeans™
2491 * has been added to the <code>java.beans</code> package.
2492 * Please see {@link java.beans.XMLEncoder}.
4508 } else {
4509 switch (e.getID()) {
4510 case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED:
4511 replaceInputMethodText(e);
4512
4513 // fall through
4514
4515 case InputMethodEvent.CARET_POSITION_CHANGED:
4516 setInputMethodCaretPosition(e);
4517 break;
4518 }
4519 }
4520
4521 e.consume();
4522 }
4523 }
4524
4525 //
4526 // Overrides this method to become an active input method client.
4527 //
4528 @BeanProperty(bound = false)
4529 public InputMethodRequests getInputMethodRequests() {
4530 if (inputMethodRequestsHandler == null) {
4531 inputMethodRequestsHandler = new InputMethodRequestsHandler();
4532 Document doc = getDocument();
4533 if (doc != null) {
4534 doc.addDocumentListener((DocumentListener)inputMethodRequestsHandler);
4535 }
4536 }
4537
4538 return inputMethodRequestsHandler;
4539 }
4540
4541 //
4542 // Overrides this method to watch the listener installed.
4543 //
4544 public void addInputMethodListener(InputMethodListener l) {
4545 super.addInputMethodListener(l);
4546 if (l != null) {
4547 needToSendKeyTypedEvent = false;
4548 checkedInputOverride = true;
|