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.misc.ManagedLocalsThread;
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>
92 * The caret is a pluggable object in swing text components.
93 * Notification of changes to the caret position and the selection
94 * are sent to implementations of the <code>CaretListener</code>
95 * interface that have been registered with the text component.
96 * The UI will install a default caret unless a customized caret
97 * has been set. <br>
98 * By default the caret tracks all the document changes
99 * performed on the Event Dispatching Thread and updates it's position
100 * accordingly if an insertion occurs before or at the caret position
101 * or a removal occurs before the caret position. <code>DefaultCaret</code>
102 * tries to make itself visible which may lead to scrolling
103 * of a text component within <code>JScrollPane</code>. The default caret
104 * behavior can be changed by the {@link DefaultCaret#setUpdatePolicy} method.
105 * <br>
106 * <b>Note</b>: Non-editable text components also have a caret though
107 * it may not be painted.
108 *
109 * <dt><b>Commands</b>
110 * <dd>
111 * Text components provide a number of commands that can be used
112 * to manipulate the component. This is essentially the way that
113 * the component expresses its capabilities. These are expressed
114 * in terms of the swing <code>Action</code> interface,
115 * using the <code>TextAction</code> implementation.
116 * The set of commands supported by the text component can be
117 * found with the {@link #getActions} method. These actions
118 * can be bound to key events, fired from buttons, etc.
119 *
120 * <dt><b>Text Input</b>
121 * <dd>
122 * The text components support flexible and internationalized text input, using
123 * keymaps and the input method framework, while maintaining compatibility with
124 * the AWT listener model.
125 * <p>
126 * A {@link javax.swing.text.Keymap} lets an application bind key
127 * strokes to actions.
128 * In order to allow keymaps to be shared across multiple text components, they
129 * can use actions that extend <code>TextAction</code>.
130 * <code>TextAction</code> can determine which <code>JTextComponent</code>
131 * most recently has or had focus and therefore is the subject of
132 * the action (In the case that the <code>ActionEvent</code>
133 * sent to the action doesn't contain the target text component as its source).
134 * <p>
135 * The <a href="../../../../technotes/guides/imf/spec.html">input method framework</a>
136 * lets text components interact with input methods, separate software
137 * components that preprocess events to let users enter thousands of
138 * different characters using keyboards with far fewer keys.
139 * <code>JTextComponent</code> is an <em>active client</em> of
140 * the framework, so it implements the preferred user interface for interacting
141 * with input methods. As a consequence, some key events do not reach the text
142 * component because they are handled by an input method, and some text input
143 * reaches the text component as committed text within an {@link
144 * java.awt.event.InputMethodEvent} instead of as a key event.
145 * The complete text input is the combination of the characters in
146 * <code>keyTyped</code> key events and committed text in input method events.
147 * <p>
148 * The AWT listener model lets applications attach event listeners to
149 * components in order to bind events to actions. Swing encourages the
150 * use of keymaps instead of listeners, but maintains compatibility
151 * with listeners by giving the listeners a chance to steal an event
152 * by consuming it.
153 * <p>
154 * Keyboard event and input method events are handled in the following stages,
155 * with each stage capable of consuming the event:
156 *
157 * <table border=1 summary="Stages of keyboard and input method event handling">
158 * <tr>
159 * <th id="stage"><p style="text-align:left">Stage</p></th>
160 * <th id="ke"><p style="text-align:left">KeyEvent</p></th>
161 * <th id="ime"><p style="text-align:left">InputMethodEvent</p></th></tr>
162 * <tr><td headers="stage">1. </td>
163 * <td headers="ke">input methods </td>
164 * <td headers="ime">(generated here)</td></tr>
165 * <tr><td headers="stage">2. </td>
166 * <td headers="ke">focus manager </td>
220 * expression given by SGML, a system used to express a wide variety of
221 * content.
222 * Each modification to the document causes notification of the
223 * details of the change to be sent to all observers in the form of a
224 * {@link DocumentEvent} which allows the views to stay up to date with the model.
225 * This event is sent to observers that have implemented the
226 * {@link DocumentListener}
227 * interface and registered interest with the model being observed.
228 *
229 * <dt><b>Location Information</b>
230 * <dd>
231 * The capability of determining the location of text in
232 * the view is provided. There are two methods, {@link #modelToView}
233 * and {@link #viewToModel} for determining this information.
234 *
235 * <dt><b>Undo/Redo support</b>
236 * <dd>
237 * Support for an edit history mechanism is provided to allow
238 * undo/redo operations. The text component does not itself
239 * provide the history buffer by default, but does provide
240 * the <code>UndoableEdit</code> records that can be used in conjunction
241 * with a history buffer to provide the undo/redo support.
242 * The support is provided by the Document model, which allows
243 * one to attach UndoableEditListener implementations.
244 *
245 * <dt><b>Thread Safety</b>
246 * <dd>
247 * The swing text components provide some support of thread
248 * safe operations. Because of the high level of configurability
249 * of the text components, it is possible to circumvent the
250 * protection provided. The protection primarily comes from
251 * the model, so the documentation of <code>AbstractDocument</code>
252 * describes the assumptions of the protection provided.
253 * The methods that are safe to call asynchronously are marked
254 * with comments.
255 *
256 * <dt><b>Newlines</b>
257 * <dd>
258 * For a discussion on how newlines are handled, see
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 * @beaninfo
280 * attribute: isContainer false
281 *
282 * @author Timothy Prinzing
283 * @author Igor Kushnirskiy (printing support)
284 * @see Document
285 * @see DocumentEvent
286 * @see DocumentListener
287 * @see Caret
288 * @see CaretEvent
289 * @see CaretListener
290 * @see TextUI
291 * @see View
292 * @see ViewFactory
293 */
294 @SuppressWarnings("serial") // Same-version serialization only
295 public abstract class JTextComponent extends JComponent implements Scrollable, Accessible
296 {
297 /**
298 * Creates a new <code>JTextComponent</code>.
299 * Listeners for caret events are established, and the pluggable
300 * UI installed. The component is marked as editable. No layout manager
301 * is used, because layout is managed by the view subsystem of text.
302 * The document model is set to <code>null</code>.
303 */
304 public JTextComponent() {
305 super();
306 // enable InputMethodEvent for on-the-spot pre-editing
307 enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.INPUT_METHOD_EVENT_MASK);
308 caretEvent = new MutableCaretEvent(this);
309 addMouseListener(caretEvent);
310 addFocusListener(caretEvent);
311 setEditable(true);
312 setDragEnabled(false);
313 setLayout(null); // layout is managed by View hierarchy
314 updateUI();
315 }
316
317 /**
318 * Fetches the user-interface factory for this text-oriented editor.
319 *
320 * @return the factory
321 */
322 public TextUI getUI() { return (TextUI)ui; }
323
324 /**
325 * Sets the user-interface factory for this text-oriented editor.
326 *
327 * @param ui the factory
328 */
329 public void setUI(TextUI ui) {
330 super.setUI(ui);
331 }
332
333 /**
334 * Reloads the pluggable UI. The key used to fetch the
335 * new interface is <code>getUIClassID()</code>. The type of
336 * the UI is <code>TextUI</code>. <code>invalidate</code>
337 * is called after setting the UI.
338 */
339 public void updateUI() {
340 setUI((TextUI)UIManager.getUI(this));
341 invalidate();
342 }
343
344 /**
345 * Adds a caret listener for notification of any changes
346 * to the caret.
347 *
348 * @param listener the listener to be added
349 * @see javax.swing.event.CaretEvent
350 */
351 public void addCaretListener(CaretListener listener) {
352 listenerList.add(CaretListener.class, listener);
353 }
354
355 /**
356 * Removes a caret listener.
357 *
358 * @param listener the listener to be removed
359 * @see javax.swing.event.CaretEvent
360 */
361 public void removeCaretListener(CaretListener listener) {
362 listenerList.remove(CaretListener.class, listener);
363 }
364
365 /**
366 * Returns an array of all the caret listeners
367 * registered on this text component.
368 *
369 * @return all of this component's <code>CaretListener</code>s
370 * or an empty
371 * array if no caret listeners are currently registered
372 *
373 * @see #addCaretListener
374 * @see #removeCaretListener
375 *
376 * @since 1.4
377 */
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
485 doc.putProperty( TextAttribute.RUN_DIRECTION, runDir );
486 }
487 super.setComponentOrientation( o );
488 }
489
490 /**
491 * Fetches the command list for the editor. This is
492 * the list of commands supported by the plugged-in UI
493 * augmented by the collection of commands that the
494 * editor itself supports. These are useful for binding
495 * to events, such as in a keymap.
496 *
497 * @return the command list
498 */
499 public Action[] getActions() {
500 return getUI().getEditorKit(this).getActions();
501 }
502
503 /**
504 * Sets margin space between the text component's border
505 * and its text. The text component's default <code>Border</code>
506 * object will use this value to create the proper margin.
507 * However, if a non-default border is set on the text component,
508 * it is that <code>Border</code> object's responsibility to create the
509 * appropriate margin space (else this property will effectively
510 * be ignored). This causes a redraw of the component.
511 * A PropertyChange event ("margin") is sent to all listeners.
512 *
513 * @param m the space between the border and the text
514 * @beaninfo
515 * description: desired space between the border and text area
516 * bound: true
517 */
518 public void setMargin(Insets m) {
519 Insets old = margin;
520 margin = m;
521 firePropertyChange("margin", old, m);
522 invalidate();
523 }
524
525 /**
526 * Returns the margin between the text component's border and
527 * its text.
528 *
529 * @return the margin
530 */
531 public Insets getMargin() {
532 return margin;
533 }
534
535 /**
536 * Sets the <code>NavigationFilter</code>. <code>NavigationFilter</code>
537 * is used by <code>DefaultCaret</code> and the default cursor movement
538 * actions as a way to restrict the cursor movement.
539 * @param filter the filter
540 *
541 * @since 1.4
542 */
543 public void setNavigationFilter(NavigationFilter filter) {
544 navigationFilter = filter;
545 }
546
547 /**
548 * Returns the <code>NavigationFilter</code>. <code>NavigationFilter</code>
549 * is used by <code>DefaultCaret</code> and the default cursor movement
550 * actions as a way to restrict the cursor movement. A null return value
551 * implies the cursor movement and selection should not be restricted.
552 *
553 * @since 1.4
554 * @return the NavigationFilter
555 */
556 public NavigationFilter getNavigationFilter() {
557 return navigationFilter;
558 }
559
560 /**
561 * Fetches the caret that allows text-oriented navigation over
562 * the view.
563 *
564 * @return the caret
565 */
566 @Transient
567 public Caret getCaret() {
568 return caret;
569 }
591 if (caret != null) {
592 caret.install(this);
593 caret.addChangeListener(caretEvent);
594 }
595 firePropertyChange("caret", old, caret);
596 }
597
598 /**
599 * Fetches the object responsible for making highlights.
600 *
601 * @return the highlighter
602 */
603 public Highlighter getHighlighter() {
604 return highlighter;
605 }
606
607 /**
608 * Sets the highlighter to be used. By default this will be set
609 * by the UI that gets installed. This can be changed to
610 * a custom highlighter if desired. The highlighter can be set to
611 * <code>null</code> to disable it.
612 * A PropertyChange event ("highlighter") is fired
613 * when a new highlighter is installed.
614 *
615 * @param h the highlighter
616 * @see #getHighlighter
617 * @beaninfo
618 * description: object responsible for background highlights
619 * bound: true
620 * expert: true
621 */
622 public void setHighlighter(Highlighter h) {
623 if (highlighter != null) {
624 highlighter.deinstall(this);
625 }
626 Highlighter old = highlighter;
627 highlighter = h;
628 if (highlighter != null) {
629 highlighter.install(this);
630 }
631 firePropertyChange("highlighter", old, h);
632 }
633
634 /**
635 * Sets the keymap to use for binding events to
636 * actions. Setting to <code>null</code> effectively disables
637 * keyboard input.
638 * A PropertyChange event ("keymap") is fired when a new keymap
639 * is installed.
640 *
641 * @param map the keymap
642 * @see #getKeymap
643 * @beaninfo
644 * description: set of key event to action bindings to use
645 * bound: true
646 */
647 public void setKeymap(Keymap map) {
648 Keymap old = keymap;
649 keymap = map;
650 firePropertyChange("keymap", old, keymap);
651 updateInputMap(old, map);
652 }
653
654 /**
655 * Turns on or off automatic drag handling. In order to enable automatic
656 * drag handling, this property should be set to {@code true}, and the
657 * component's {@code TransferHandler} needs to be {@code non-null}.
658 * The default value of the {@code dragEnabled} property is {@code false}.
659 * <p>
660 * The job of honoring this property, and recognizing a user drag gesture,
661 * lies with the look and feel implementation, and in particular, the component's
662 * {@code TextUI}. When automatic drag handling is enabled, most look and
663 * feels (including those that subclass {@code BasicLookAndFeel}) begin a
664 * drag and drop operation whenever the user presses the mouse button over
665 * a selection and then moves the mouse a few pixels. Setting this property to
666 * {@code true} can therefore have a subtle effect on how selections behave.
667 * <p>
668 * If a look and feel is used that ignores this property, you can still
669 * begin a drag and drop operation by calling {@code exportAsDrag} on the
670 * component's {@code TransferHandler}.
671 *
672 * @param b whether or not to enable automatic drag handling
673 * @exception HeadlessException if
674 * <code>b</code> is <code>true</code> and
675 * <code>GraphicsEnvironment.isHeadless()</code>
676 * returns <code>true</code>
677 * @see java.awt.GraphicsEnvironment#isHeadless
678 * @see #getDragEnabled
679 * @see #setTransferHandler
680 * @see TransferHandler
681 * @since 1.4
682 *
683 * @beaninfo
684 * description: determines whether automatic drag handling is enabled
685 * bound: false
686 */
687 public void setDragEnabled(boolean b) {
688 checkDragEnabled(b);
689 dragEnabled = b;
690 }
691
692 private static void checkDragEnabled(boolean b) {
693 if (b && GraphicsEnvironment.isHeadless()) {
694 throw new HeadlessException();
695 }
696 }
697
698 /**
699 * Returns whether or not automatic drag handling is enabled.
700 *
701 * @return the value of the {@code dragEnabled} property
702 * @see #setDragEnabled
703 * @since 1.4
704 */
705 public boolean getDragEnabled() {
706 return dragEnabled;
707 }
708
709 /**
710 * Sets the drop mode for this component. For backward compatibility,
711 * the default for this property is <code>DropMode.USE_SELECTION</code>.
712 * Usage of <code>DropMode.INSERT</code> is recommended, however,
713 * for an improved user experience. It offers similar behavior of dropping
714 * between text locations, but does so without affecting the actual text
715 * selection and caret location.
716 * <p>
717 * <code>JTextComponents</code> support the following drop modes:
718 * <ul>
719 * <li><code>DropMode.USE_SELECTION</code></li>
720 * <li><code>DropMode.INSERT</code></li>
721 * </ul>
722 * <p>
723 * The drop mode is only meaningful if this component has a
724 * <code>TransferHandler</code> that accepts drops.
725 *
726 * @param dropMode the drop mode to use
727 * @throws IllegalArgumentException if the drop mode is unsupported
728 * or <code>null</code>
729 * @see #getDropMode
730 * @see #getDropLocation
731 * @see #setTransferHandler
732 * @see javax.swing.TransferHandler
733 * @since 1.6
734 */
735 public final void setDropMode(DropMode dropMode) {
736 checkDropMode(dropMode);
737 this.dropMode = dropMode;
738 }
739
740 private static void checkDropMode(DropMode dropMode) {
741 if (dropMode != null) {
742 switch (dropMode) {
743 case USE_SELECTION:
744 case INSERT:
745 return;
746 }
747 }
748
766 public TransferHandler.DropLocation dropLocationForPoint(JTextComponent textComp,
767 Point p)
768 {
769 return textComp.dropLocationForPoint(p);
770 }
771 public Object setDropLocation(JTextComponent textComp,
772 TransferHandler.DropLocation location,
773 Object state, boolean forDrop)
774 {
775 return textComp.setDropLocation(location, state, forDrop);
776 }
777 });
778 }
779
780
781 /**
782 * Calculates a drop location in this component, representing where a
783 * drop at the given point should insert data.
784 * <p>
785 * Note: This method is meant to override
786 * <code>JComponent.dropLocationForPoint()</code>, which is package-private
787 * in javax.swing. <code>TransferHandler</code> will detect text components
788 * and call this method instead via reflection. It's name should therefore
789 * not be changed.
790 *
791 * @param p the point to calculate a drop location for
792 * @return the drop location, or <code>null</code>
793 */
794 DropLocation dropLocationForPoint(Point p) {
795 Position.Bias[] bias = new Position.Bias[1];
796 int index = getUI().viewToModel(this, p, bias);
797
798 // viewToModel currently returns null for some HTML content
799 // when the point is within the component's top inset
800 if (bias[0] == null) {
801 bias[0] = Position.Bias.Forward;
802 }
803
804 return new DropLocation(p, index, bias[0]);
805 }
806
807 /**
808 * Called to set or clear the drop location during a DnD operation.
809 * In some cases, the component may need to use it's internal selection
810 * temporarily to indicate the drop location. To help facilitate this,
811 * this method returns and accepts as a parameter a state object.
812 * This state object can be used to store, and later restore, the selection
813 * state. Whatever this method returns will be passed back to it in
814 * future calls, as the state parameter. If it wants the DnD system to
815 * continue storing the same state, it must pass it back every time.
816 * Here's how this is used:
817 * <p>
818 * Let's say that on the first call to this method the component decides
819 * to save some state (because it is about to use the selection to show
820 * a drop index). It can return a state object to the caller encapsulating
821 * any saved selection state. On a second call, let's say the drop location
822 * is being changed to something else. The component doesn't need to
823 * restore anything yet, so it simply passes back the same state object
824 * to have the DnD system continue storing it. Finally, let's say this
825 * method is messaged with <code>null</code>. This means DnD
826 * is finished with this component for now, meaning it should restore
827 * state. At this point, it can use the state parameter to restore
828 * said state, and of course return <code>null</code> since there's
829 * no longer anything to store.
830 * <p>
831 * Note: This method is meant to override
832 * <code>JComponent.setDropLocation()</code>, which is package-private
833 * in javax.swing. <code>TransferHandler</code> will detect text components
834 * and call this method instead via reflection. It's name should therefore
835 * not be changed.
836 *
837 * @param location the drop location (as calculated by
838 * <code>dropLocationForPoint</code>) or <code>null</code>
839 * if there's no longer a valid drop location
840 * @param state the state object saved earlier for this component,
841 * or <code>null</code>
842 * @param forDrop whether or not the method is being called because an
843 * actual drop occurred
844 * @return any saved state for this component, or <code>null</code> if none
845 */
846 Object setDropLocation(TransferHandler.DropLocation location,
847 Object state,
848 boolean forDrop) {
849
850 Object retVal = null;
851 DropLocation textLocation = (DropLocation)location;
852
853 if (dropMode == DropMode.USE_SELECTION) {
854 if (textLocation == null) {
855 if (state != null) {
856 /*
857 * This object represents the state saved earlier.
858 * If the caret is a DefaultCaret it will be
859 * an Object array containing, in order:
860 * - the saved caret mark (Integer)
861 * - the saved caret dot (Integer)
862 * - the saved caret visibility (Boolean)
863 * - the saved mark bias (Position.Bias)
864 * - the saved dot bias (Position.Bias)
927 } else {
928 retVal = state;
929 }
930 }
931 }
932
933 DropLocation old = dropLocation;
934 dropLocation = textLocation;
935 firePropertyChange("dropLocation", old, dropLocation);
936
937 return retVal;
938 }
939
940 /**
941 * Returns the location that this component should visually indicate
942 * as the drop location during a DnD operation over the component,
943 * or {@code null} if no location is to currently be shown.
944 * <p>
945 * This method is not meant for querying the drop location
946 * from a {@code TransferHandler}, as the drop location is only
947 * set after the {@code TransferHandler}'s <code>canImport</code>
948 * has returned and has allowed for the location to be shown.
949 * <p>
950 * When this property changes, a property change event with
951 * name "dropLocation" is fired by the component.
952 *
953 * @return the drop location
954 * @see #setDropMode
955 * @see TransferHandler#canImport(TransferHandler.TransferSupport)
956 * @since 1.6
957 */
958 public final DropLocation getDropLocation() {
959 return dropLocation;
960 }
961
962
963 /**
964 * Updates the <code>InputMap</code>s in response to a
965 * <code>Keymap</code> change.
966 * @param oldKm the old <code>Keymap</code>
967 * @param newKm the new <code>Keymap</code>
968 */
969 void updateInputMap(Keymap oldKm, Keymap newKm) {
970 // Locate the current KeymapWrapper.
971 InputMap km = getInputMap(JComponent.WHEN_FOCUSED);
972 InputMap last = km;
973 while (km != null && !(km instanceof KeymapWrapper)) {
974 last = km;
975 km = km.getParent();
976 }
977 if (km != null) {
978 // Found it, tweak the InputMap that points to it, as well
979 // as anything it points to.
980 if (newKm == null) {
981 if (last != km) {
982 last.setParent(km.getParent());
983 }
984 else {
985 last.setParent(null);
986 }
987 }
1042 }
1043 }
1044
1045 /**
1046 * Fetches the keymap currently active in this text
1047 * component.
1048 *
1049 * @return the keymap
1050 */
1051 public Keymap getKeymap() {
1052 return keymap;
1053 }
1054
1055 /**
1056 * Adds a new keymap into the keymap hierarchy. Keymap bindings
1057 * resolve from bottom up so an attribute specified in a child
1058 * will override an attribute specified in the parent.
1059 *
1060 * @param nm the name of the keymap (must be unique within the
1061 * collection of named keymaps in the document); the name may
1062 * be <code>null</code> if the keymap is unnamed,
1063 * but the caller is responsible for managing the reference
1064 * returned as an unnamed keymap can't
1065 * be fetched by name
1066 * @param parent the parent keymap; this may be <code>null</code> if
1067 * unspecified bindings need not be resolved in some other keymap
1068 * @return the keymap
1069 */
1070 public static Keymap addKeymap(String nm, Keymap parent) {
1071 Keymap map = new DefaultKeymap(nm, parent);
1072 if (nm != null) {
1073 // add a named keymap, a class of bindings
1074 getKeymapTable().put(nm, map);
1075 }
1076 return map;
1077 }
1078
1079 /**
1080 * Removes a named keymap previously added to the document. Keymaps
1081 * with <code>null</code> names may not be removed in this way.
1082 *
1083 * @param nm the name of the keymap to remove
1084 * @return the keymap that was removed
1085 */
1086 public static Keymap removeKeymap(String nm) {
1087 return getKeymapTable().remove(nm);
1088 }
1089
1090 /**
1091 * Fetches a named keymap previously added to the document.
1092 * This does not work with <code>null</code>-named keymaps.
1093 *
1094 * @param nm the name of the keymap
1095 * @return the keymap
1096 */
1097 public static Keymap getKeymap(String nm) {
1098 return getKeymapTable().get(nm);
1099 }
1100
1101 private static HashMap<String,Keymap> getKeymapTable() {
1102 synchronized (KEYMAP_TABLE) {
1103 AppContext appContext = AppContext.getAppContext();
1104 @SuppressWarnings("unchecked")
1105 HashMap<String,Keymap> keymapTable =
1106 (HashMap<String,Keymap>)appContext.get(KEYMAP_TABLE);
1107 if (keymapTable == null) {
1108 keymapTable = new HashMap<String,Keymap>(17);
1109 appContext.put(KEYMAP_TABLE, keymapTable);
1110 //initialize default keymap
1111 Keymap binding = addKeymap(DEFAULT_KEYMAP, null);
1112 binding.setDefaultAction(new
1113 DefaultEditorKit.DefaultKeyTypedAction());
1114 }
1115 return keymapTable;
1116 }
1117 }
1118
1119 /**
1120 * Binding record for creating key bindings.
1121 * <p>
1122 * <strong>Warning:</strong>
1123 * Serialized objects of this class will not be compatible with
1124 * future Swing releases. The current serialization support is
1125 * appropriate for short term storage or RMI between applications running
1126 * the same version of Swing. As of 1.4, support for long term storage
1127 * of all JavaBeans™
1128 * has been added to the <code>java.beans</code> package.
1129 * Please see {@link java.beans.XMLEncoder}.
1130 */
1131 @SuppressWarnings("serial") // Same-version serialization only
1132 public static class KeyBinding {
1133
1134 /**
1135 * The key.
1136 */
1137 public KeyStroke key;
1138
1139 /**
1140 * The name of the action for the key.
1141 */
1142 public String actionName;
1143
1144 /**
1145 * Creates a new key binding.
1146 *
1147 * @param key the key
1148 * @param actionName the name of the action for the key
1149 */
1150 public KeyBinding(KeyStroke key, String actionName) {
1151 this.key = key;
1152 this.actionName = actionName;
1153 }
1154 }
1155
1156 /**
1157 * <p>
1158 * Loads a keymap with a bunch of
1159 * bindings. This can be used to take a static table of
1160 * definitions and load them into some keymap. The following
1161 * example illustrates an example of binding some keys to
1162 * the cut, copy, and paste actions associated with a
1163 * JTextComponent. A code fragment to accomplish
1164 * this might look as follows:
1165 * <pre><code>
1166 *
1167 * static final JTextComponent.KeyBinding[] defaultBindings = {
1168 * new JTextComponent.KeyBinding(
1169 * KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK),
1170 * DefaultEditorKit.copyAction),
1171 * new JTextComponent.KeyBinding(
1172 * KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK),
1173 * DefaultEditorKit.pasteAction),
1174 * new JTextComponent.KeyBinding(
1175 * KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK),
1176 * DefaultEditorKit.cutAction),
1177 * };
1178 *
1179 * JTextComponent c = new JTextPane();
1180 * Keymap k = c.getKeymap();
1181 * JTextComponent.loadKeymap(k, defaultBindings, c.getActions());
1182 *
1183 * </code></pre>
1184 * The sets of bindings and actions may be empty but must be
1185 * non-<code>null</code>.
1186 *
1187 * @param map the keymap
1188 * @param bindings the bindings
1189 * @param actions the set of actions
1190 */
1191 public static void loadKeymap(Keymap map, KeyBinding[] bindings, Action[] actions) {
1192 Hashtable<String, Action> h = new Hashtable<String, Action>();
1193 for (Action a : actions) {
1194 String value = (String)a.getValue(Action.NAME);
1195 h.put((value!=null ? value:""), a);
1196 }
1197 for (KeyBinding binding : bindings) {
1198 Action a = h.get(binding.actionName);
1199 if (a != null) {
1200 map.addActionForKeyStroke(binding.key, a);
1201 }
1202 }
1203 }
1204
1205 /**
1206 * Fetches the current color used to render the
1207 * caret.
1208 *
1209 * @return the color
1210 */
1211 public Color getCaretColor() {
1212 return caretColor;
1213 }
1214
1215 /**
1216 * Sets the current color used to render the caret.
1217 * Setting to <code>null</code> effectively restores the default color.
1218 * Setting the color results in a PropertyChange event ("caretColor")
1219 * being fired.
1220 *
1221 * @param c the color
1222 * @see #getCaretColor
1223 * @beaninfo
1224 * description: the color used to render the caret
1225 * bound: true
1226 * preferred: true
1227 */
1228 public void setCaretColor(Color c) {
1229 Color old = caretColor;
1230 caretColor = c;
1231 firePropertyChange("caretColor", old, caretColor);
1232 }
1233
1234 /**
1235 * Fetches the current color used to render the
1236 * selection.
1237 *
1238 * @return the color
1239 */
1240 public Color getSelectionColor() {
1241 return selectionColor;
1242 }
1243
1244 /**
1245 * Sets the current color used to render the selection.
1246 * Setting the color to <code>null</code> is the same as setting
1247 * <code>Color.white</code>. Setting the color results in a
1248 * PropertyChange event ("selectionColor").
1249 *
1250 * @param c the color
1251 * @see #getSelectionColor
1252 * @beaninfo
1253 * description: color used to render selection background
1254 * bound: true
1255 * preferred: true
1256 */
1257 public void setSelectionColor(Color c) {
1258 Color old = selectionColor;
1259 selectionColor = c;
1260 firePropertyChange("selectionColor", old, selectionColor);
1261 }
1262
1263 /**
1264 * Fetches the current color used to render the
1265 * selected text.
1266 *
1267 * @return the color
1268 */
1269 public Color getSelectedTextColor() {
1270 return selectedTextColor;
1271 }
1272
1273 /**
1274 * Sets the current color used to render the selected text.
1275 * Setting the color to <code>null</code> is the same as
1276 * <code>Color.black</code>. Setting the color results in a
1277 * PropertyChange event ("selectedTextColor") being fired.
1278 *
1279 * @param c the color
1280 * @see #getSelectedTextColor
1281 * @beaninfo
1282 * description: color used to render selected text
1283 * bound: true
1284 * preferred: true
1285 */
1286 public void setSelectedTextColor(Color c) {
1287 Color old = selectedTextColor;
1288 selectedTextColor = c;
1289 firePropertyChange("selectedTextColor", old, selectedTextColor);
1290 }
1291
1292 /**
1293 * Fetches the current color used to render the
1294 * disabled text.
1295 *
1296 * @return the color
1395 * to the nearest representative location in the model.
1396 * The component must have a positive size for
1397 * this translation to be computed (i.e. layout cannot
1398 * be computed until the component has been sized). The
1399 * component does not have to be visible or painted.
1400 *
1401 * @param pt the location in the view to translate
1402 * @return the offset ≥ 0 from the start of the document,
1403 * or -1 if the component does not yet have a positive
1404 * size.
1405 * @see TextUI#viewToModel
1406 */
1407 public int viewToModel(Point pt) {
1408 return getUI().viewToModel(this, pt);
1409 }
1410
1411 /**
1412 * Transfers the currently selected range in the associated
1413 * text model to the system clipboard, removing the contents
1414 * from the model. The current selection is reset. Does nothing
1415 * for <code>null</code> selections.
1416 *
1417 * @see java.awt.Toolkit#getSystemClipboard
1418 * @see java.awt.datatransfer.Clipboard
1419 */
1420 public void cut() {
1421 if (isEditable() && isEnabled()) {
1422 invokeAction("cut", TransferHandler.getCutAction());
1423 }
1424 }
1425
1426 /**
1427 * Transfers the currently selected range in the associated
1428 * text model to the system clipboard, leaving the contents
1429 * in the text model. The current selection remains intact.
1430 * Does nothing for <code>null</code> selections.
1431 *
1432 * @see java.awt.Toolkit#getSystemClipboard
1433 * @see java.awt.datatransfer.Clipboard
1434 */
1435 public void copy() {
1436 invokeAction("copy", TransferHandler.getCopyAction());
1437 }
1438
1439 /**
1440 * Transfers the contents of the system clipboard into the
1441 * associated text model. If there is a selection in the
1442 * associated view, it is replaced with the contents of the
1443 * clipboard. If there is no selection, the clipboard contents
1444 * are inserted in front of the current insert position in
1445 * the associated view. If the clipboard is empty, does nothing.
1446 *
1447 * @see #replaceSelection
1448 * @see java.awt.Toolkit#getSystemClipboard
1449 * @see java.awt.datatransfer.Clipboard
1450 */
1451 public void paste() {
1452 if (isEditable() && isEnabled()) {
1453 invokeAction("paste", TransferHandler.getPasteAction());
1454 }
1455 }
1456
1457 /**
1458 * This is a convenience method that is only useful for
1459 * <code>cut</code>, <code>copy</code> and <code>paste</code>. If
1460 * an <code>Action</code> with the name <code>name</code> does not
1461 * exist in the <code>ActionMap</code>, this will attempt to install a
1462 * <code>TransferHandler</code> and then use <code>altAction</code>.
1463 */
1464 private void invokeAction(String name, Action altAction) {
1465 ActionMap map = getActionMap();
1466 Action action = null;
1467
1468 if (map != null) {
1469 action = map.get(name);
1470 }
1471 if (action == null) {
1472 installDefaultTransferHandlerIfNecessary();
1473 action = altAction;
1474 }
1475 action.actionPerformed(new ActionEvent(this,
1476 ActionEvent.ACTION_PERFORMED, (String)action.
1477 getValue(Action.NAME),
1478 EventQueue.getMostRecentEventTime(),
1479 getCurrentEventModifiers()));
1480 }
1481
1482 /**
1483 * If the current <code>TransferHandler</code> is null, this will
1484 * install a new one.
1485 */
1486 private void installDefaultTransferHandlerIfNecessary() {
1487 if (getTransferHandler() == null) {
1488 if (defaultTransferHandler == null) {
1489 defaultTransferHandler = new DefaultTransferHandler();
1490 }
1491 setTransferHandler(defaultTransferHandler);
1492 }
1493 }
1494
1495 /**
1496 * Moves the caret to a new position, leaving behind a mark
1497 * defined by the last time <code>setCaretPosition</code> was
1498 * called. This forms a selection.
1499 * If the document is <code>null</code>, does nothing. The position
1500 * must be between 0 and the length of the component's text or else
1501 * an exception is thrown.
1502 *
1503 * @param pos the position
1504 * @exception IllegalArgumentException if the value supplied
1505 * for <code>position</code> is less than zero or greater
1506 * than the component's text length
1507 * @see #setCaretPosition
1508 */
1509 public void moveCaretPosition(int pos) {
1510 Document doc = getDocument();
1511 if (doc != null) {
1512 if (pos > doc.getLength() || pos < 0) {
1513 throw new IllegalArgumentException("bad position: " + pos);
1514 }
1515 caret.moveDot(pos);
1516 }
1517 }
1518
1519 /**
1520 * The bound property name for the focus accelerator.
1521 */
1522 public static final String FOCUS_ACCELERATOR_KEY = "focusAcceleratorKey";
1523
1524 /**
1525 * Sets the key accelerator that will cause the receiving text
1555 * text component to get the focus. Return '\0' if no focus
1556 * accelerator has been set.
1557 *
1558 * @return the key
1559 */
1560 public char getFocusAccelerator() {
1561 return focusAccelerator;
1562 }
1563
1564 /**
1565 * Initializes from a stream. This creates a
1566 * model of the type appropriate for the component
1567 * and initializes the model from the stream.
1568 * By default this will load the model as plain
1569 * text. Previous contents of the model are discarded.
1570 *
1571 * @param in the stream to read from
1572 * @param desc an object describing the stream; this
1573 * might be a string, a File, a URL, etc. Some kinds
1574 * of documents (such as html for example) might be
1575 * able to make use of this information; if non-<code>null</code>,
1576 * it is added as a property of the document
1577 * @exception IOException as thrown by the stream being
1578 * used to initialize
1579 * @see EditorKit#createDefaultDocument
1580 * @see #setDocument
1581 * @see PlainDocument
1582 */
1583 public void read(Reader in, Object desc) throws IOException {
1584 EditorKit kit = getUI().getEditorKit(this);
1585 Document doc = kit.createDefaultDocument();
1586 if (desc != null) {
1587 doc.putProperty(Document.StreamDescriptionProperty, desc);
1588 }
1589 try {
1590 kit.read(in, doc, 0);
1591 setDocument(doc);
1592 } catch (BadLocationException e) {
1593 throw new IOException(e.getMessage());
1594 }
1595 }
1605 public void write(Writer out) throws IOException {
1606 Document doc = getDocument();
1607 try {
1608 getUI().getEditorKit(this).write(out, doc, 0, doc.getLength());
1609 } catch (BadLocationException e) {
1610 throw new IOException(e.getMessage());
1611 }
1612 }
1613
1614 public void removeNotify() {
1615 super.removeNotify();
1616 if (getFocusedComponent() == this) {
1617 AppContext.getAppContext().remove(FOCUSED_COMPONENT);
1618 }
1619 }
1620
1621 // --- java.awt.TextComponent methods ------------------------
1622
1623 /**
1624 * Sets the position of the text insertion caret for the
1625 * <code>TextComponent</code>. Note that the caret tracks change,
1626 * so this may move if the underlying text of the component is changed.
1627 * If the document is <code>null</code>, does nothing. The position
1628 * must be between 0 and the length of the component's text or else
1629 * an exception is thrown.
1630 *
1631 * @param position the position
1632 * @exception IllegalArgumentException if the value supplied
1633 * for <code>position</code> is less than zero or greater
1634 * than the component's text length
1635 * @beaninfo
1636 * description: the caret position
1637 */
1638 public void setCaretPosition(int position) {
1639 Document doc = getDocument();
1640 if (doc != null) {
1641 if (position > doc.getLength() || position < 0) {
1642 throw new IllegalArgumentException("bad position: " + position);
1643 }
1644 caret.setDot(position);
1645 }
1646 }
1647
1648 /**
1649 * Returns the position of the text insertion caret for the
1650 * text component.
1651 *
1652 * @return the position of the text insertion caret for the
1653 * text component ≥ 0
1654 */
1655 @Transient
1656 public int getCaretPosition() {
1657 return caret.getDot();
1658 }
1659
1660 /**
1661 * Sets the text of this <code>TextComponent</code>
1662 * to the specified text. If the text is <code>null</code>
1663 * or empty, has the effect of simply deleting the old text.
1664 * When text has been inserted, the resulting caret location
1665 * is determined by the implementation of the caret class.
1666 *
1667 * <p>
1668 * Note that text is not a bound property, so no <code>PropertyChangeEvent
1669 * </code> is fired when it changes. To listen for changes to the text,
1670 * use <code>DocumentListener</code>.
1671 *
1672 * @param t the new text to be set
1673 * @see #getText
1674 * @see DefaultCaret
1675 * @beaninfo
1676 * description: the text of this component
1677 */
1678 public void setText(String t) {
1679 try {
1680 Document doc = getDocument();
1681 if (doc instanceof AbstractDocument) {
1682 ((AbstractDocument)doc).replace(0, doc.getLength(), t,null);
1683 }
1684 else {
1685 doc.remove(0, doc.getLength());
1686 doc.insertString(0, t, null);
1687 }
1688 } catch (BadLocationException e) {
1689 UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this);
1690 }
1691 }
1692
1693 /**
1694 * Returns the text contained in this <code>TextComponent</code>.
1695 * If the underlying document is <code>null</code>,
1696 * will give a <code>NullPointerException</code>.
1697 *
1698 * Note that text is not a bound property, so no <code>PropertyChangeEvent
1699 * </code> is fired when it changes. To listen for changes to the text,
1700 * use <code>DocumentListener</code>.
1701 *
1702 * @return the text
1703 * @exception NullPointerException if the document is <code>null</code>
1704 * @see #setText
1705 */
1706 public String getText() {
1707 Document doc = getDocument();
1708 String txt;
1709 try {
1710 txt = doc.getText(0, doc.getLength());
1711 } catch (BadLocationException e) {
1712 txt = null;
1713 }
1714 return txt;
1715 }
1716
1717 /**
1718 * Returns the selected text contained in this
1719 * <code>TextComponent</code>. If the selection is
1720 * <code>null</code> or the document empty, returns <code>null</code>.
1721 *
1722 * @return the text
1723 * @exception IllegalArgumentException if the selection doesn't
1724 * have a valid mapping into the document for some reason
1725 * @see #setText
1726 */
1727 public String getSelectedText() {
1728 String txt = null;
1729 int p0 = Math.min(caret.getDot(), caret.getMark());
1730 int p1 = Math.max(caret.getDot(), caret.getMark());
1731 if (p0 != p1) {
1732 try {
1733 Document doc = getDocument();
1734 txt = doc.getText(p0, p1 - p0);
1735 } catch (BadLocationException e) {
1736 throw new IllegalArgumentException(e.getMessage());
1737 }
1738 }
1739 return txt;
1740 }
1741
1742 /**
1743 * Returns the boolean indicating whether this
1744 * <code>TextComponent</code> is editable or not.
1745 *
1746 * @return the boolean value
1747 * @see #setEditable
1748 */
1749 public boolean isEditable() {
1750 return editable;
1751 }
1752
1753 /**
1754 * Sets the specified boolean to indicate whether or not this
1755 * <code>TextComponent</code> should be editable.
1756 * A PropertyChange event ("editable") is fired when the
1757 * state is changed.
1758 *
1759 * @param b the boolean to be set
1760 * @see #isEditable
1761 * @beaninfo
1762 * description: specifies if the text can be edited
1763 * bound: true
1764 */
1765 public void setEditable(boolean b) {
1766 if (b != editable) {
1767 boolean oldVal = editable;
1768 editable = b;
1769 enableInputMethods(editable);
1770 firePropertyChange("editable", Boolean.valueOf(oldVal), Boolean.valueOf(editable));
1771 repaint();
1772 }
1773 }
1774
1775 /**
1776 * Returns the selected text's start position. Return 0 for an
1777 * empty document, or the value of dot if no selection.
1778 *
1779 * @return the start position ≥ 0
1780 */
1781 @Transient
1782 public int getSelectionStart() {
1783 int start = Math.min(caret.getDot(), caret.getMark());
1784 return start;
1785 }
1786
1787 /**
1788 * Sets the selection start to the specified position. The new
1789 * starting point is constrained to be before or at the current
1790 * selection end.
1791 * <p>
1792 * This is available for backward compatibility to code
1793 * that called this method on <code>java.awt.TextComponent</code>.
1794 * This is implemented to forward to the <code>Caret</code>
1795 * implementation which is where the actual selection is maintained.
1796 *
1797 * @param selectionStart the start position of the text ≥ 0
1798 * @beaninfo
1799 * description: starting location of the selection.
1800 */
1801 public void setSelectionStart(int selectionStart) {
1802 /* Route through select method to enforce consistent policy
1803 * between selectionStart and selectionEnd.
1804 */
1805 select(selectionStart, getSelectionEnd());
1806 }
1807
1808 /**
1809 * Returns the selected text's end position. Return 0 if the document
1810 * is empty, or the value of dot if there is no selection.
1811 *
1812 * @return the end position ≥ 0
1813 */
1814 @Transient
1815 public int getSelectionEnd() {
1816 int end = Math.max(caret.getDot(), caret.getMark());
1817 return end;
1818 }
1819
1820 /**
1821 * Sets the selection end to the specified position. The new
1822 * end point is constrained to be at or after the current
1823 * selection start.
1824 * <p>
1825 * This is available for backward compatibility to code
1826 * that called this method on <code>java.awt.TextComponent</code>.
1827 * This is implemented to forward to the <code>Caret</code>
1828 * implementation which is where the actual selection is maintained.
1829 *
1830 * @param selectionEnd the end position of the text ≥ 0
1831 * @beaninfo
1832 * description: ending location of the selection.
1833 */
1834 public void setSelectionEnd(int selectionEnd) {
1835 /* Route through select method to enforce consistent policy
1836 * between selectionStart and selectionEnd.
1837 */
1838 select(getSelectionStart(), selectionEnd);
1839 }
1840
1841 /**
1842 * Selects the text between the specified start and end positions.
1843 * <p>
1844 * This method sets the start and end positions of the
1845 * selected text, enforcing the restriction that the start position
1846 * must be greater than or equal to zero. The end position must be
1847 * greater than or equal to the start position, and less than or
1848 * equal to the length of the text component's text.
1849 * <p>
1850 * If the caller supplies values that are inconsistent or out of
1851 * bounds, the method enforces these constraints silently, and
1852 * without failure. Specifically, if the start position or end
1853 * position is greater than the length of the text, it is reset to
1854 * equal the text length. If the start position is less than zero,
1855 * it is reset to zero, and if the end position is less than the
1856 * start position, it is reset to the start position.
1857 * <p>
1858 * This call is provided for backward compatibility.
1859 * It is routed to a call to <code>setCaretPosition</code>
1860 * followed by a call to <code>moveCaretPosition</code>.
1861 * The preferred way to manage selection is by calling
1862 * those methods directly.
1863 *
1864 * @param selectionStart the start position of the text
1865 * @param selectionEnd the end position of the text
1866 * @see #setCaretPosition
1867 * @see #moveCaretPosition
1868 */
1869 public void select(int selectionStart, int selectionEnd) {
1870 // argument adjustment done by java.awt.TextComponent
1871 int docLength = getDocument().getLength();
1872
1873 if (selectionStart < 0) {
1874 selectionStart = 0;
1875 }
1876 if (selectionStart > docLength) {
1877 selectionStart = docLength;
1878 }
1879 if (selectionEnd > docLength) {
1880 selectionEnd = docLength;
1881 }
1882 if (selectionEnd < selectionStart) {
1883 selectionEnd = selectionStart;
1884 }
1885
1886 setCaretPosition(selectionStart);
1887 moveCaretPosition(selectionEnd);
1888 }
1889
1890 /**
1891 * Selects all the text in the <code>TextComponent</code>.
1892 * Does nothing on a <code>null</code> or empty document.
1893 */
1894 public void selectAll() {
1895 Document doc = getDocument();
1896 if (doc != null) {
1897 setCaretPosition(0);
1898 moveCaretPosition(doc.getLength());
1899 }
1900 }
1901
1902 // --- Tooltip Methods ---------------------------------------------
1903
1904 /**
1905 * Returns the string to be used as the tooltip for <code>event</code>.
1906 * This will return one of:
1907 * <ol>
1908 * <li>If <code>setToolTipText</code> has been invoked with a
1909 * non-<code>null</code>
1910 * value, it will be returned, otherwise
1911 * <li>The value from invoking <code>getToolTipText</code> on
1912 * the UI will be returned.
1913 * </ol>
1914 * By default <code>JTextComponent</code> does not register
1915 * itself with the <code>ToolTipManager</code>.
1916 * This means that tooltips will NOT be shown from the
1917 * <code>TextUI</code> unless <code>registerComponent</code> has
1918 * been invoked on the <code>ToolTipManager</code>.
1919 *
1920 * @param event the event in question
1921 * @return the string to be used as the tooltip for <code>event</code>
1922 * @see javax.swing.JComponent#setToolTipText
1923 * @see javax.swing.plaf.TextUI#getToolTipText
1924 * @see javax.swing.ToolTipManager#registerComponent
1925 */
1926 public String getToolTipText(MouseEvent event) {
1927 String retValue = super.getToolTipText(event);
1928
1929 if (retValue == null) {
1930 TextUI ui = getUI();
1931 if (ui != null) {
1932 retValue = ui.getToolTipText(this, new Point(event.getX(),
1933 event.getY()));
1934 }
1935 }
1936 return retValue;
1937 }
1938
1939 // --- Scrollable methods ---------------------------------------------
1940
1941 /**
1942 * Returns the preferred size of the viewport for a view component.
1943 * This is implemented to do the default behavior of returning
1944 * the preferred size of the component.
1945 *
1946 * @return the <code>preferredSize</code> of a <code>JViewport</code>
1947 * whose view is this <code>Scrollable</code>
1948 */
1949 public Dimension getPreferredScrollableViewportSize() {
1950 return getPreferredSize();
1951 }
1952
1953
1954 /**
1955 * Components that display logical rows or columns should compute
1956 * the scroll increment that will completely expose one new row
1957 * or column, depending on the value of orientation. Ideally,
1958 * components should handle a partially exposed row or column by
1959 * returning the distance required to completely expose the item.
1960 * <p>
1961 * The default implementation of this is to simply return 10% of
1962 * the visible area. Subclasses are likely to be able to provide
1963 * a much more reasonable value.
1964 *
1965 * @param visibleRect the view area visible within the viewport
1966 * @param orientation either <code>SwingConstants.VERTICAL</code> or
1967 * <code>SwingConstants.HORIZONTAL</code>
1968 * @param direction less than zero to scroll up/left, greater than
1969 * zero for down/right
1970 * @return the "unit" increment for scrolling in the specified direction
1971 * @exception IllegalArgumentException for an invalid orientation
1972 * @see JScrollBar#setUnitIncrement
1973 */
1974 public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
1975 switch(orientation) {
1976 case SwingConstants.VERTICAL:
1977 return visibleRect.height / 10;
1978 case SwingConstants.HORIZONTAL:
1979 return visibleRect.width / 10;
1980 default:
1981 throw new IllegalArgumentException("Invalid orientation: " + orientation);
1982 }
1983 }
1984
1985
1986 /**
1987 * Components that display logical rows or columns should compute
1988 * the scroll increment that will completely expose one block
1989 * of rows or columns, depending on the value of orientation.
1990 * <p>
1991 * The default implementation of this is to simply return the visible
1992 * area. Subclasses will likely be able to provide a much more
1993 * reasonable value.
1994 *
1995 * @param visibleRect the view area visible within the viewport
1996 * @param orientation either <code>SwingConstants.VERTICAL</code> or
1997 * <code>SwingConstants.HORIZONTAL</code>
1998 * @param direction less than zero to scroll up/left, greater than zero
1999 * for down/right
2000 * @return the "block" increment for scrolling in the specified direction
2001 * @exception IllegalArgumentException for an invalid orientation
2002 * @see JScrollBar#setBlockIncrement
2003 */
2004 public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
2005 switch(orientation) {
2006 case SwingConstants.VERTICAL:
2007 return visibleRect.height;
2008 case SwingConstants.HORIZONTAL:
2009 return visibleRect.width;
2010 default:
2011 throw new IllegalArgumentException("Invalid orientation: " + orientation);
2012 }
2013 }
2014
2015
2016 /**
2017 * Returns true if a viewport should always force the width of this
2018 * <code>Scrollable</code> to match the width of the viewport.
2019 * For example a normal text view that supported line wrapping
2020 * would return true here, since it would be undesirable for
2021 * wrapped lines to disappear beyond the right
2022 * edge of the viewport. Note that returning true for a
2023 * <code>Scrollable</code> whose ancestor is a <code>JScrollPane</code>
2024 * effectively disables horizontal scrolling.
2025 * <p>
2026 * Scrolling containers, like <code>JViewport</code>,
2027 * will use this method each time they are validated.
2028 *
2029 * @return true if a viewport should force the <code>Scrollable</code>s
2030 * width to match its own
2031 */
2032 public boolean getScrollableTracksViewportWidth() {
2033 Container parent = SwingUtilities.getUnwrappedParent(this);
2034 if (parent instanceof JViewport) {
2035 return parent.getWidth() > getPreferredSize().width;
2036 }
2037 return false;
2038 }
2039
2040 /**
2041 * Returns true if a viewport should always force the height of this
2042 * <code>Scrollable</code> to match the height of the viewport.
2043 * For example a columnar text view that flowed text in left to
2044 * right columns could effectively disable vertical scrolling by
2045 * returning true here.
2046 * <p>
2047 * Scrolling containers, like <code>JViewport</code>,
2048 * will use this method each time they are validated.
2049 *
2050 * @return true if a viewport should force the Scrollables height
2051 * to match its own
2052 */
2053 public boolean getScrollableTracksViewportHeight() {
2054 Container parent = SwingUtilities.getUnwrappedParent(this);
2055 if (parent instanceof JViewport) {
2056 return parent.getHeight() > getPreferredSize().height;
2057 }
2058 return false;
2059 }
2060
2061
2062 //////////////////
2063 // Printing Support
2064 //////////////////
2065
2066 /**
2067 * A convenience print method that displays a print dialog, and then
2456 *
2457 * @see java.awt.print.Printable
2458 * @see java.awt.print.PageFormat
2459 * @see javax.swing.text.Document#render(java.lang.Runnable)
2460 *
2461 * @since 1.6
2462 */
2463 public Printable getPrintable(final MessageFormat headerFormat,
2464 final MessageFormat footerFormat) {
2465 return TextComponentPrintable.getPrintable(
2466 this, headerFormat, footerFormat);
2467 }
2468
2469
2470 /////////////////
2471 // Accessibility support
2472 ////////////////
2473
2474
2475 /**
2476 * Gets the <code>AccessibleContext</code> associated with this
2477 * <code>JTextComponent</code>. For text components,
2478 * the <code>AccessibleContext</code> takes the form of an
2479 * <code>AccessibleJTextComponent</code>.
2480 * A new <code>AccessibleJTextComponent</code> instance
2481 * is created if necessary.
2482 *
2483 * @return an <code>AccessibleJTextComponent</code> that serves as the
2484 * <code>AccessibleContext</code> of this
2485 * <code>JTextComponent</code>
2486 */
2487 public AccessibleContext getAccessibleContext() {
2488 if (accessibleContext == null) {
2489 accessibleContext = new AccessibleJTextComponent();
2490 }
2491 return accessibleContext;
2492 }
2493
2494 /**
2495 * This class implements accessibility support for the
2496 * <code>JTextComponent</code> class. It provides an implementation of
2497 * the Java Accessibility API appropriate to menu user-interface elements.
2498 * <p>
2499 * <strong>Warning:</strong>
2500 * Serialized objects of this class will not be compatible with
2501 * future Swing releases. The current serialization support is
2502 * appropriate for short term storage or RMI between applications running
2503 * the same version of Swing. As of 1.4, support for long term storage
2504 * of all JavaBeans™
2505 * has been added to the <code>java.beans</code> package.
2506 * Please see {@link java.beans.XMLEncoder}.
2507 */
2508 @SuppressWarnings("serial") // Same-version serialization only
2509 public class AccessibleJTextComponent extends AccessibleJComponent
2510 implements AccessibleText, CaretListener, DocumentListener,
2511 AccessibleAction, AccessibleEditableText,
2512 AccessibleExtendedText {
2513
2514 int caretPos;
2515 Point oldLocationOnScreen;
2516
2517 /**
2518 * Constructs an AccessibleJTextComponent. Adds a listener to track
2519 * caret change.
2520 */
2521 public AccessibleJTextComponent() {
2522 Document doc = JTextComponent.this.getDocument();
2523 if (doc != null) {
2524 doc.addDocumentListener(this);
2525 }
2871 * Return 0 if the text is empty, or the caret position
2872 * if no selection.
2873 *
2874 * @return the index into the text of the end of the selection ≥ 0
2875 */
2876 public int getSelectionEnd() {
2877 return JTextComponent.this.getSelectionEnd();
2878 }
2879
2880 /**
2881 * Returns the portion of the text that is selected.
2882 *
2883 * @return the text, null if no selection
2884 */
2885 public String getSelectedText() {
2886 return JTextComponent.this.getSelectedText();
2887 }
2888
2889 /**
2890 * IndexedSegment extends Segment adding the offset into the
2891 * the model the <code>Segment</code> was asked for.
2892 */
2893 private class IndexedSegment extends Segment {
2894 /**
2895 * Offset into the model that the position represents.
2896 */
2897 public int modelOffset;
2898 }
2899
2900
2901 // TIGER - 4170173
2902 /**
2903 * Returns the String at a given index. Whitespace
2904 * between words is treated as a word.
2905 *
2906 * @param part the CHARACTER, WORD, or SENTENCE to retrieve
2907 * @param index an index within the text
2908 * @return the letter, word, or sentence.
2909 *
2910 */
2911 public String getAtIndex(int part, int index) {
2923 */
2924 public String getAfterIndex(int part, int index) {
2925 return getAtIndex(part, index, 1);
2926 }
2927
2928
2929 /**
2930 * Returns the String before a given index. Whitespace
2931 * between words is treated a word.
2932 *
2933 * @param part the CHARACTER, WORD, or SENTENCE to retrieve
2934 * @param index an index within the text
2935 * @return the letter, word, or sentence.
2936 */
2937 public String getBeforeIndex(int part, int index) {
2938 return getAtIndex(part, index, -1);
2939 }
2940
2941
2942 /**
2943 * Gets the word, sentence, or character at <code>index</code>.
2944 * If <code>direction</code> is non-null this will find the
2945 * next/previous word/sentence/character.
2946 */
2947 private String getAtIndex(int part, int index, int direction) {
2948 if (model instanceof AbstractDocument) {
2949 ((AbstractDocument)model).readLock();
2950 }
2951 try {
2952 if (index < 0 || index >= model.getLength()) {
2953 return null;
2954 }
2955 switch (part) {
2956 case AccessibleText.CHARACTER:
2957 if (index + direction < model.getLength() &&
2958 index + direction >= 0) {
2959 return model.getText(index + direction, 1);
2960 }
2961 break;
2962
2963
2964 case AccessibleText.WORD:
3010 if (model instanceof PlainDocument ) {
3011 PlainDocument sdoc = (PlainDocument)model;
3012 return sdoc.getParagraphElement(index);
3013 } else if (model instanceof StyledDocument) {
3014 StyledDocument sdoc = (StyledDocument)model;
3015 return sdoc.getParagraphElement(index);
3016 } else {
3017 Element para;
3018 for (para = model.getDefaultRootElement(); ! para.isLeaf(); ) {
3019 int pos = para.getElementIndex(index);
3020 para = para.getElement(pos);
3021 }
3022 if (para == null) {
3023 return null;
3024 }
3025 return para.getParentElement();
3026 }
3027 }
3028
3029 /*
3030 * Returns a <code>Segment</code> containing the paragraph text
3031 * at <code>index</code>, or null if <code>index</code> isn't
3032 * valid.
3033 */
3034 private IndexedSegment getParagraphElementText(int index)
3035 throws BadLocationException {
3036 Element para = getParagraphElement(index);
3037
3038
3039 if (para != null) {
3040 IndexedSegment segment = new IndexedSegment();
3041 try {
3042 int length = para.getEndOffset() - para.getStartOffset();
3043 model.getText(para.getStartOffset(), length, segment);
3044 } catch (BadLocationException e) {
3045 return null;
3046 }
3047 segment.modelOffset = para.getStartOffset();
3048 return segment;
3049 }
3050 return null;
3051 }
3052
3053
3054 /**
3055 * Returns the Segment at <code>index</code> representing either
3056 * the paragraph or sentence as identified by <code>part</code>, or
3057 * null if a valid paragraph/sentence can't be found. The offset
3058 * will point to the start of the word/sentence in the array, and
3059 * the modelOffset will point to the location of the word/sentence
3060 * in the model.
3061 */
3062 private IndexedSegment getSegmentAt(int part, int index) throws
3063 BadLocationException {
3064 IndexedSegment seg = getParagraphElementText(index);
3065 if (seg == null) {
3066 return null;
3067 }
3068 BreakIterator iterator;
3069 switch (part) {
3070 case AccessibleText.WORD:
3071 iterator = BreakIterator.getWordInstance(getLocale());
3072 break;
3073 case AccessibleText.SENTENCE:
3074 iterator = BreakIterator.getSentenceInstance(getLocale());
3075 break;
3076 default:
3255 Document doc = JTextComponent.this.getDocument();
3256 if (doc != null && doc instanceof StyledDocument) {
3257 StyledDocument sDoc = (StyledDocument)doc;
3258 int offset = startIndex;
3259 int length = endIndex - startIndex;
3260 sDoc.setCharacterAttributes(offset, length, as, true);
3261 }
3262 }
3263
3264 // ----- end AccessibleEditableText methods
3265
3266
3267 // ----- begin AccessibleExtendedText methods
3268
3269 // Probably should replace the helper method getAtIndex() to return
3270 // instead an AccessibleTextSequence also for LINE & ATTRIBUTE_RUN
3271 // and then make the AccessibleText methods get[At|After|Before]Point
3272 // call this new method instead and return only the string portion
3273
3274 /**
3275 * Returns the AccessibleTextSequence at a given <code>index</code>.
3276 * If <code>direction</code> is non-null this will find the
3277 * next/previous word/sentence/character.
3278 *
3279 * @param part the <code>CHARACTER</code>, <code>WORD</code>,
3280 * <code>SENTENCE</code>, <code>LINE</code> or
3281 * <code>ATTRIBUTE_RUN</code> to retrieve
3282 * @param index an index within the text
3283 * @param direction is either -1, 0, or 1
3284 * @return an <code>AccessibleTextSequence</code> specifying the text
3285 * if <code>part</code> and <code>index</code> are valid. Otherwise,
3286 * <code>null</code> is returned.
3287 *
3288 * @see javax.accessibility.AccessibleText#CHARACTER
3289 * @see javax.accessibility.AccessibleText#WORD
3290 * @see javax.accessibility.AccessibleText#SENTENCE
3291 * @see javax.accessibility.AccessibleExtendedText#LINE
3292 * @see javax.accessibility.AccessibleExtendedText#ATTRIBUTE_RUN
3293 *
3294 * @since 1.6
3295 */
3296 private AccessibleTextSequence getSequenceAtIndex(int part,
3297 int index, int direction) {
3298 if (index < 0 || index >= model.getLength()) {
3299 return null;
3300 }
3301 if (direction < -1 || direction > 1) {
3302 return null; // direction must be 1, 0, or -1
3303 }
3304
3305 switch (part) {
3306 case AccessibleText.CHARACTER:
3486 // we are intentionally silent; our contract says we return
3487 // null if there is any failure in this method
3488 return null;
3489 } finally {
3490 if (model instanceof AbstractDocument) {
3491 ((AbstractDocument)model).readUnlock();
3492 }
3493 }
3494 return new AccessibleTextSequence(attributeRunStartIndex,
3495 attributeRunEndIndex,
3496 runText);
3497
3498 default:
3499 break;
3500 }
3501 return null;
3502 }
3503
3504
3505 /**
3506 * Starting at text position <code>index</code>, and going in
3507 * <code>direction</code>, return the edge of run that shares the
3508 * same <code>AttributeSet</code> and parent element as those at
3509 * <code>index</code>.
3510 *
3511 * Note: we assume the document is already locked...
3512 */
3513 private int getRunEdge(int index, int direction) throws
3514 BadLocationException {
3515 if (index < 0 || index >= model.getLength()) {
3516 throw new BadLocationException("Location out of bounds", index);
3517 }
3518 // locate the Element at index
3519 Element indexElement;
3520 // locate the Element at our index/offset
3521 int elementIndex = -1; // test for initialization
3522 for (indexElement = model.getDefaultRootElement();
3523 ! indexElement.isLeaf(); ) {
3524 elementIndex = indexElement.getElementIndex(index);
3525 indexElement = indexElement.getElement(elementIndex);
3526 }
3527 if (elementIndex == -1) {
3528 throw new AssertionError(index);
3529 }
3549 edgeElement = parent.getElement(edgeElementIndex);
3550 break;
3551 default:
3552 throw new AssertionError(direction);
3553 }
3554 switch (direction) {
3555 case -1:
3556 return edgeElement.getStartOffset();
3557 case 1:
3558 return edgeElement.getEndOffset();
3559 default:
3560 // we already caught this case earlier; this is to satisfy
3561 // the compiler...
3562 return Integer.MIN_VALUE;
3563 }
3564 }
3565
3566 // getTextRange() not needed; defined in AccessibleEditableText
3567
3568 /**
3569 * Returns the <code>AccessibleTextSequence</code> at a given
3570 * <code>index</code>.
3571 *
3572 * @param part the <code>CHARACTER</code>, <code>WORD</code>,
3573 * <code>SENTENCE</code>, <code>LINE</code> or
3574 * <code>ATTRIBUTE_RUN</code> to retrieve
3575 * @param index an index within the text
3576 * @return an <code>AccessibleTextSequence</code> specifying the text if
3577 * <code>part</code> and <code>index</code> are valid. Otherwise,
3578 * <code>null</code> is returned
3579 *
3580 * @see javax.accessibility.AccessibleText#CHARACTER
3581 * @see javax.accessibility.AccessibleText#WORD
3582 * @see javax.accessibility.AccessibleText#SENTENCE
3583 * @see javax.accessibility.AccessibleExtendedText#LINE
3584 * @see javax.accessibility.AccessibleExtendedText#ATTRIBUTE_RUN
3585 *
3586 * @since 1.6
3587 */
3588 public AccessibleTextSequence getTextSequenceAt(int part, int index) {
3589 return getSequenceAtIndex(part, index, 0);
3590 }
3591
3592 /**
3593 * Returns the <code>AccessibleTextSequence</code> after a given
3594 * <code>index</code>.
3595 *
3596 * @param part the <code>CHARACTER</code>, <code>WORD</code>,
3597 * <code>SENTENCE</code>, <code>LINE</code> or
3598 * <code>ATTRIBUTE_RUN</code> to retrieve
3599 * @param index an index within the text
3600 * @return an <code>AccessibleTextSequence</code> specifying the text
3601 * if <code>part</code> and <code>index</code> are valid. Otherwise,
3602 * <code>null</code> is returned
3603 *
3604 * @see javax.accessibility.AccessibleText#CHARACTER
3605 * @see javax.accessibility.AccessibleText#WORD
3606 * @see javax.accessibility.AccessibleText#SENTENCE
3607 * @see javax.accessibility.AccessibleExtendedText#LINE
3608 * @see javax.accessibility.AccessibleExtendedText#ATTRIBUTE_RUN
3609 *
3610 * @since 1.6
3611 */
3612 public AccessibleTextSequence getTextSequenceAfter(int part, int index) {
3613 return getSequenceAtIndex(part, index, 1);
3614 }
3615
3616 /**
3617 * Returns the <code>AccessibleTextSequence</code> before a given
3618 * <code>index</code>.
3619 *
3620 * @param part the <code>CHARACTER</code>, <code>WORD</code>,
3621 * <code>SENTENCE</code>, <code>LINE</code> or
3622 * <code>ATTRIBUTE_RUN</code> to retrieve
3623 * @param index an index within the text
3624 * @return an <code>AccessibleTextSequence</code> specifying the text
3625 * if <code>part</code> and <code>index</code> are valid. Otherwise,
3626 * <code>null</code> is returned
3627 *
3628 * @see javax.accessibility.AccessibleText#CHARACTER
3629 * @see javax.accessibility.AccessibleText#WORD
3630 * @see javax.accessibility.AccessibleText#SENTENCE
3631 * @see javax.accessibility.AccessibleExtendedText#LINE
3632 * @see javax.accessibility.AccessibleExtendedText#ATTRIBUTE_RUN
3633 *
3634 * @since 1.6
3635 */
3636 public AccessibleTextSequence getTextSequenceBefore(int part, int index) {
3637 return getSequenceAtIndex(part, index, -1);
3638 }
3639
3640 /**
3641 * Returns the <code>Rectangle</code> enclosing the text between
3642 * two indicies.
3643 *
3644 * @param startIndex the start index in the text
3645 * @param endIndex the end index in the text
3646 * @return the bounding rectangle of the text if the indices are valid.
3647 * Otherwise, <code>null</code> is returned
3648 *
3649 * @since 1.6
3650 */
3651 public Rectangle getTextBounds(int startIndex, int endIndex) {
3652 if (startIndex < 0 || startIndex > model.getLength()-1 ||
3653 endIndex < 0 || endIndex > model.getLength()-1 ||
3654 startIndex > endIndex) {
3655 return null;
3656 }
3657 TextUI ui = getUI();
3658 if (ui == null) {
3659 return null;
3660 }
3661 Rectangle rect = null;
3662 Rectangle alloc = getRootEditorRect();
3663 if (alloc == null) {
3664 return null;
3665 }
3666 if (model instanceof AbstractDocument) {
3667 ((AbstractDocument)model).readLock();
3834 private Color caretColor;
3835 private Color selectionColor;
3836 private Color selectedTextColor;
3837 private Color disabledTextColor;
3838 private boolean editable;
3839 private Insets margin;
3840 private char focusAccelerator;
3841 private boolean dragEnabled;
3842
3843 /**
3844 * The drop mode for this component.
3845 */
3846 private DropMode dropMode = DropMode.USE_SELECTION;
3847
3848 /**
3849 * The drop location.
3850 */
3851 private transient DropLocation dropLocation;
3852
3853 /**
3854 * Represents a drop location for <code>JTextComponent</code>s.
3855 *
3856 * @see #getDropLocation
3857 * @since 1.6
3858 */
3859 public static final class DropLocation extends TransferHandler.DropLocation {
3860 private final int index;
3861 private final Position.Bias bias;
3862
3863 private DropLocation(Point p, int index, Position.Bias bias) {
3864 super(p);
3865 this.index = index;
3866 this.bias = bias;
3867 }
3868
3869 /**
3870 * Returns the index where dropped data should be inserted into the
3871 * associated component. This index represents a position between
3872 * characters, as would be interpreted by a caret.
3873 *
3874 * @return the drop index
3892 * and the content and format of the returned string may vary
3893 * between implementations.
3894 *
3895 * @return a string representation of this drop location
3896 */
3897 public String toString() {
3898 return getClass().getName()
3899 + "[dropPoint=" + getDropPoint() + ","
3900 + "index=" + index + ","
3901 + "bias=" + bias + "]";
3902 }
3903 }
3904
3905 /**
3906 * TransferHandler used if one hasn't been supplied by the UI.
3907 */
3908 private static DefaultTransferHandler defaultTransferHandler;
3909
3910 /**
3911 * Maps from class name to Boolean indicating if
3912 * <code>processInputMethodEvent</code> has been overriden.
3913 */
3914 private static Cache<Class<?>,Boolean> METHOD_OVERRIDDEN
3915 = new Cache<Class<?>,Boolean>(Cache.Kind.WEAK, Cache.Kind.STRONG) {
3916 /**
3917 * Returns {@code true} if the specified {@code type} extends {@link JTextComponent}
3918 * and the {@link JTextComponent#processInputMethodEvent} method is overridden.
3919 */
3920 @Override
3921 public Boolean create(final Class<?> type) {
3922 if (JTextComponent.class == type) {
3923 return Boolean.FALSE;
3924 }
3925 if (get(type.getSuperclass())) {
3926 return Boolean.TRUE;
3927 }
3928 return AccessController.doPrivileged(
3929 new PrivilegedAction<Boolean>() {
3930 public Boolean run() {
3931 try {
3932 type.getDeclaredMethod("processInputMethodEvent", InputMethodEvent.class);
3933 return Boolean.TRUE;
3934 } catch (NoSuchMethodException exception) {
3935 return Boolean.FALSE;
3936 }
3937 }
3938 });
3939 }
3940 };
3941
3942 /**
3943 * Returns a string representation of this <code>JTextComponent</code>.
3944 * This method is intended to be used only for debugging purposes, and the
3945 * content and format of the returned string may vary between
3946 * implementations. The returned string may be empty but may not
3947 * be <code>null</code>.
3948 * <P>
3949 * Overriding <code>paramString</code> to provide information about the
3950 * specific new aspects of the JFC components.
3951 *
3952 * @return a string representation of this <code>JTextComponent</code>
3953 */
3954 protected String paramString() {
3955 String editableString = (editable ?
3956 "true" : "false");
3957 String caretColorString = (caretColor != null ?
3958 caretColor.toString() : "");
3959 String selectionColorString = (selectionColor != null ?
3960 selectionColor.toString() : "");
3961 String selectedTextColorString = (selectedTextColor != null ?
3962 selectedTextColor.toString() : "");
3963 String disabledTextColorString = (disabledTextColor != null ?
3964 disabledTextColor.toString() : "");
3965 String marginString = (margin != null ?
3966 margin.toString() : "");
3967
3968 return super.paramString() +
3969 ",caretColor=" + caretColorString +
3970 ",disabledTextColor=" + disabledTextColorString +
3971 ",editable=" + editableString +
3972 ",margin=" + marginString +
4245 * String representation of the keymap... potentially
4246 * a very long string.
4247 */
4248 public String toString() {
4249 return "Keymap[" + nm + "]" + bindings;
4250 }
4251
4252 String nm;
4253 Keymap parent;
4254 Hashtable<KeyStroke, Action> bindings;
4255 Action defaultAction;
4256 }
4257
4258
4259 /**
4260 * KeymapWrapper wraps a Keymap inside an InputMap. For KeymapWrapper
4261 * to be useful it must be used with a KeymapActionMap.
4262 * KeymapWrapper for the most part, is an InputMap with two parents.
4263 * The first parent visited is ALWAYS the Keymap, with the second
4264 * parent being the parent inherited from InputMap. If
4265 * <code>keymap.getAction</code> returns null, implying the Keymap
4266 * does not have a binding for the KeyStroke,
4267 * the parent is then visited. If the Keymap has a binding, the
4268 * Action is returned, if not and the KeyStroke represents a
4269 * KeyTyped event and the Keymap has a defaultAction,
4270 * <code>DefaultActionKey</code> is returned.
4271 * <p>KeymapActionMap is then able to transate the object passed in
4272 * to either message the Keymap, or message its default implementation.
4273 */
4274 static class KeymapWrapper extends InputMap {
4275 static final Object DefaultActionKey = new Object();
4276
4277 private Keymap keymap;
4278
4279 KeymapWrapper(Keymap keymap) {
4280 this.keymap = keymap;
4281 }
4282
4283 public KeyStroke[] keys() {
4284 KeyStroke[] sKeys = super.keys();
4285 KeyStroke[] keymapKeys = keymap.getBoundKeyStrokes();
4286 int sCount = (sKeys == null) ? 0 : sKeys.length;
4287 int keymapCount = (keymapKeys == null) ? 0 : keymapKeys.length;
4288 if (sCount == 0) {
4289 return keymapKeys;
4290 }
4308
4309 public Object get(KeyStroke keyStroke) {
4310 Object retValue = keymap.getAction(keyStroke);
4311 if (retValue == null) {
4312 retValue = super.get(keyStroke);
4313 if (retValue == null &&
4314 keyStroke.getKeyChar() != KeyEvent.CHAR_UNDEFINED &&
4315 keymap.getDefaultAction() != null) {
4316 // Implies this is a KeyTyped event, use the default
4317 // action.
4318 retValue = DefaultActionKey;
4319 }
4320 }
4321 return retValue;
4322 }
4323 }
4324
4325
4326 /**
4327 * Wraps a Keymap inside an ActionMap. This is used with
4328 * a KeymapWrapper. If <code>get</code> is passed in
4329 * <code>KeymapWrapper.DefaultActionKey</code>, the default action is
4330 * returned, otherwise if the key is an Action, it is returned.
4331 */
4332 static class KeymapActionMap extends ActionMap {
4333 private Keymap keymap;
4334
4335 KeymapActionMap(Keymap keymap) {
4336 this.keymap = keymap;
4337 }
4338
4339 public Object[] keys() {
4340 Object[] sKeys = super.keys();
4341 Object[] keymapKeys = keymap.getBoundActions();
4342 int sCount = (sKeys == null) ? 0 : sKeys.length;
4343 int keymapCount = (keymapKeys == null) ? 0 : keymapKeys.length;
4344 boolean hasDefault = (keymap.getDefaultAction() != null);
4345 if (hasDefault) {
4346 keymapCount++;
4347 }
4348 if (sCount == 0) {
4349 if (hasDefault) {
4393 // Try the Keymap.
4394 if (key == KeymapWrapper.DefaultActionKey) {
4395 retValue = keymap.getDefaultAction();
4396 }
4397 else if (key instanceof Action) {
4398 // This is a little iffy, technically an Action is
4399 // a valid Key. We're assuming the Action came from
4400 // the InputMap though.
4401 retValue = (Action)key;
4402 }
4403 }
4404 return retValue;
4405 }
4406 }
4407
4408 private static final Object FOCUSED_COMPONENT =
4409 new StringBuilder("JTextComponent_FocusedComponent");
4410
4411 /**
4412 * The default keymap that will be shared by all
4413 * <code>JTextComponent</code> instances unless they
4414 * have had a different keymap set.
4415 */
4416 public static final String DEFAULT_KEYMAP = "default";
4417
4418 /**
4419 * Event to use when firing a notification of change to caret
4420 * position. This is mutable so that the event can be reused
4421 * since caret events can be fairly high in bandwidth.
4422 */
4423 static class MutableCaretEvent extends CaretEvent implements ChangeListener, FocusListener, MouseListener {
4424
4425 MutableCaretEvent(JTextComponent c) {
4426 super(c);
4427 }
4428
4429 final void fire() {
4430 JTextComponent c = (JTextComponent) getSource();
4431 if (c != null) {
4432 Caret caret = c.getCaret();
4433 dot = caret.getDot();
|
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.misc.ManagedLocalsThread;
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} is the base class for swing text
79 * components. It tries to be compatible with the
80 * {@code java.awt.TextComponent} 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>
92 * The caret is a pluggable object in swing text components.
93 * Notification of changes to the caret position and the selection
94 * are sent to implementations of the {@code CaretListener}
95 * interface that have been registered with the text component.
96 * The UI will install a default caret unless a customized caret
97 * has been set. <br>
98 * By default the caret tracks all the document changes
99 * performed on the Event Dispatching Thread and updates it's position
100 * accordingly if an insertion occurs before or at the caret position
101 * or a removal occurs before the caret position. {@code DefaultCaret}
102 * tries to make itself visible which may lead to scrolling
103 * of a text component within {@code JScrollPane}. The default caret
104 * behavior can be changed by the {@link DefaultCaret#setUpdatePolicy} method.
105 * <br>
106 * <b>Note</b>: Non-editable text components also have a caret though
107 * it may not be painted.
108 *
109 * <dt><b>Commands</b>
110 * <dd>
111 * Text components provide a number of commands that can be used
112 * to manipulate the component. This is essentially the way that
113 * the component expresses its capabilities. These are expressed
114 * in terms of the swing {@code Action} interface,
115 * using the {@code TextAction} implementation.
116 * The set of commands supported by the text component can be
117 * found with the {@link #getActions} method. These actions
118 * can be bound to key events, fired from buttons, etc.
119 *
120 * <dt><b>Text Input</b>
121 * <dd>
122 * The text components support flexible and internationalized text input, using
123 * keymaps and the input method framework, while maintaining compatibility with
124 * the AWT listener model.
125 * <p>
126 * A {@link javax.swing.text.Keymap} lets an application bind key
127 * strokes to actions.
128 * In order to allow keymaps to be shared across multiple text components, they
129 * can use actions that extend {@code TextAction}.
130 * {@code TextAction} can determine which {@code JTextComponent}
131 * most recently has or had focus and therefore is the subject of
132 * the action (In the case that the {@code ActionEvent}
133 * sent to the action doesn't contain the target text component as its source).
134 * <p>
135 * The <a href="../../../../technotes/guides/imf/spec.html">input method framework</a>
136 * lets text components interact with input methods, separate software
137 * components that preprocess events to let users enter thousands of
138 * different characters using keyboards with far fewer keys.
139 * {@code JTextComponent} is an <em>active client</em> of
140 * the framework, so it implements the preferred user interface for interacting
141 * with input methods. As a consequence, some key events do not reach the text
142 * component because they are handled by an input method, and some text input
143 * reaches the text component as committed text within an {@link
144 * java.awt.event.InputMethodEvent} instead of as a key event.
145 * The complete text input is the combination of the characters in
146 * {@code keyTyped} key events and committed text in input method events.
147 * <p>
148 * The AWT listener model lets applications attach event listeners to
149 * components in order to bind events to actions. Swing encourages the
150 * use of keymaps instead of listeners, but maintains compatibility
151 * with listeners by giving the listeners a chance to steal an event
152 * by consuming it.
153 * <p>
154 * Keyboard event and input method events are handled in the following stages,
155 * with each stage capable of consuming the event:
156 *
157 * <table border=1 summary="Stages of keyboard and input method event handling">
158 * <tr>
159 * <th id="stage"><p style="text-align:left">Stage</p></th>
160 * <th id="ke"><p style="text-align:left">KeyEvent</p></th>
161 * <th id="ime"><p style="text-align:left">InputMethodEvent</p></th></tr>
162 * <tr><td headers="stage">1. </td>
163 * <td headers="ke">input methods </td>
164 * <td headers="ime">(generated here)</td></tr>
165 * <tr><td headers="stage">2. </td>
166 * <td headers="ke">focus manager </td>
220 * expression given by SGML, a system used to express a wide variety of
221 * content.
222 * Each modification to the document causes notification of the
223 * details of the change to be sent to all observers in the form of a
224 * {@link DocumentEvent} which allows the views to stay up to date with the model.
225 * This event is sent to observers that have implemented the
226 * {@link DocumentListener}
227 * interface and registered interest with the model being observed.
228 *
229 * <dt><b>Location Information</b>
230 * <dd>
231 * The capability of determining the location of text in
232 * the view is provided. There are two methods, {@link #modelToView}
233 * and {@link #viewToModel} for determining this information.
234 *
235 * <dt><b>Undo/Redo support</b>
236 * <dd>
237 * Support for an edit history mechanism is provided to allow
238 * undo/redo operations. The text component does not itself
239 * provide the history buffer by default, but does provide
240 * the {@code UndoableEdit} records that can be used in conjunction
241 * with a history buffer to provide the undo/redo support.
242 * The support is provided by the Document model, which allows
243 * one to attach UndoableEditListener implementations.
244 *
245 * <dt><b>Thread Safety</b>
246 * <dd>
247 * The swing text components provide some support of thread
248 * safe operations. Because of the high level of configurability
249 * of the text components, it is possible to circumvent the
250 * protection provided. The protection primarily comes from
251 * the model, so the documentation of {@code AbstractDocument}
252 * describes the assumptions of the protection provided.
253 * The methods that are safe to call asynchronously are marked
254 * with comments.
255 *
256 * <dt><b>Newlines</b>
257 * <dd>
258 * For a discussion on how newlines are handled, see
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} package.
277 * Please see {@link java.beans.XMLEncoder}.
278 *
279 * @beaninfo
280 * attribute: isContainer false
281 *
282 * @author Timothy Prinzing
283 * @author Igor Kushnirskiy (printing support)
284 * @see Document
285 * @see DocumentEvent
286 * @see DocumentListener
287 * @see Caret
288 * @see CaretEvent
289 * @see CaretListener
290 * @see TextUI
291 * @see View
292 * @see ViewFactory
293 */
294 @SuppressWarnings("serial") // Same-version serialization only
295 public abstract class JTextComponent extends JComponent implements Scrollable, Accessible
296 {
297 /**
298 * Creates a new {@code JTextComponent}.
299 * Listeners for caret events are established, and the pluggable
300 * UI installed. The component is marked as editable. No layout manager
301 * is used, because layout is managed by the view subsystem of text.
302 * The document model is set to {@code null}.
303 */
304 public JTextComponent() {
305 super();
306 // enable InputMethodEvent for on-the-spot pre-editing
307 enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.INPUT_METHOD_EVENT_MASK);
308 caretEvent = new MutableCaretEvent(this);
309 addMouseListener(caretEvent);
310 addFocusListener(caretEvent);
311 setEditable(true);
312 setDragEnabled(false);
313 setLayout(null); // layout is managed by View hierarchy
314 updateUI();
315 }
316
317 /**
318 * Fetches the user-interface factory for this text-oriented editor.
319 *
320 * @return the factory
321 */
322 public TextUI getUI() { return (TextUI)ui; }
323
324 /**
325 * Sets the user-interface factory for this text-oriented editor.
326 *
327 * @param ui the factory
328 */
329 public void setUI(TextUI ui) {
330 super.setUI(ui);
331 }
332
333 /**
334 * Reloads the pluggable UI. The key used to fetch the
335 * new interface is {@code getUIClassID()}. The type of
336 * the UI is {@code TextUI}. {@code invalidate}
337 * is called after setting the UI.
338 */
339 public void updateUI() {
340 setUI((TextUI)UIManager.getUI(this));
341 invalidate();
342 }
343
344 /**
345 * Adds a caret listener for notification of any changes
346 * to the caret.
347 *
348 * @param listener the listener to be added
349 * @see javax.swing.event.CaretEvent
350 */
351 public void addCaretListener(CaretListener listener) {
352 listenerList.add(CaretListener.class, listener);
353 }
354
355 /**
356 * Removes a caret listener.
357 *
358 * @param listener the listener to be removed
359 * @see javax.swing.event.CaretEvent
360 */
361 public void removeCaretListener(CaretListener listener) {
362 listenerList.remove(CaretListener.class, listener);
363 }
364
365 /**
366 * Returns an array of all the caret listeners
367 * registered on this text component.
368 *
369 * @return all of this component's {@code CaretListener}s
370 * or an empty
371 * array if no caret listeners are currently registered
372 *
373 * @see #addCaretListener
374 * @see #removeCaretListener
375 *
376 * @since 1.4
377 */
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
485 doc.putProperty( TextAttribute.RUN_DIRECTION, runDir );
486 }
487 super.setComponentOrientation( o );
488 }
489
490 /**
491 * Fetches the command list for the editor. This is
492 * the list of commands supported by the plugged-in UI
493 * augmented by the collection of commands that the
494 * editor itself supports. These are useful for binding
495 * to events, such as in a keymap.
496 *
497 * @return the command list
498 */
499 public Action[] getActions() {
500 return getUI().getEditorKit(this).getActions();
501 }
502
503 /**
504 * Sets margin space between the text component's border
505 * and its text. The text component's default {@code Border}
506 * object will use this value to create the proper margin.
507 * However, if a non-default border is set on the text component,
508 * it is that {@code Border} object's responsibility to create the
509 * appropriate margin space (else this property will effectively
510 * be ignored). This causes a redraw of the component.
511 * A PropertyChange event ("margin") is sent to all listeners.
512 *
513 * @param m the space between the border and the text
514 * @beaninfo
515 * description: desired space between the border and text area
516 * bound: true
517 */
518 public void setMargin(Insets m) {
519 Insets old = margin;
520 margin = m;
521 firePropertyChange("margin", old, m);
522 invalidate();
523 }
524
525 /**
526 * Returns the margin between the text component's border and
527 * its text.
528 *
529 * @return the margin
530 */
531 public Insets getMargin() {
532 return margin;
533 }
534
535 /**
536 * Sets the {@code NavigationFilter}. {@code NavigationFilter}
537 * is used by {@code DefaultCaret} and the default cursor movement
538 * actions as a way to restrict the cursor movement.
539 * @param filter the filter
540 *
541 * @since 1.4
542 */
543 public void setNavigationFilter(NavigationFilter filter) {
544 navigationFilter = filter;
545 }
546
547 /**
548 * Returns the {@code NavigationFilter}. {@code NavigationFilter}
549 * is used by {@code DefaultCaret} and the default cursor movement
550 * actions as a way to restrict the cursor movement. A null return value
551 * implies the cursor movement and selection should not be restricted.
552 *
553 * @since 1.4
554 * @return the NavigationFilter
555 */
556 public NavigationFilter getNavigationFilter() {
557 return navigationFilter;
558 }
559
560 /**
561 * Fetches the caret that allows text-oriented navigation over
562 * the view.
563 *
564 * @return the caret
565 */
566 @Transient
567 public Caret getCaret() {
568 return caret;
569 }
591 if (caret != null) {
592 caret.install(this);
593 caret.addChangeListener(caretEvent);
594 }
595 firePropertyChange("caret", old, caret);
596 }
597
598 /**
599 * Fetches the object responsible for making highlights.
600 *
601 * @return the highlighter
602 */
603 public Highlighter getHighlighter() {
604 return highlighter;
605 }
606
607 /**
608 * Sets the highlighter to be used. By default this will be set
609 * by the UI that gets installed. This can be changed to
610 * a custom highlighter if desired. The highlighter can be set to
611 * {@code null} to disable it.
612 * A PropertyChange event ("highlighter") is fired
613 * when a new highlighter is installed.
614 *
615 * @param h the highlighter
616 * @see #getHighlighter
617 * @beaninfo
618 * description: object responsible for background highlights
619 * bound: true
620 * expert: true
621 */
622 public void setHighlighter(Highlighter h) {
623 if (highlighter != null) {
624 highlighter.deinstall(this);
625 }
626 Highlighter old = highlighter;
627 highlighter = h;
628 if (highlighter != null) {
629 highlighter.install(this);
630 }
631 firePropertyChange("highlighter", old, h);
632 }
633
634 /**
635 * Sets the keymap to use for binding events to
636 * actions. Setting to {@code null} effectively disables
637 * keyboard input.
638 * A PropertyChange event ("keymap") is fired when a new keymap
639 * is installed.
640 *
641 * @param map the keymap
642 * @see #getKeymap
643 * @beaninfo
644 * description: set of key event to action bindings to use
645 * bound: true
646 */
647 public void setKeymap(Keymap map) {
648 Keymap old = keymap;
649 keymap = map;
650 firePropertyChange("keymap", old, keymap);
651 updateInputMap(old, map);
652 }
653
654 /**
655 * Turns on or off automatic drag handling. In order to enable automatic
656 * drag handling, this property should be set to {@code true}, and the
657 * component's {@code TransferHandler} needs to be {@code non-null}.
658 * The default value of the {@code dragEnabled} property is {@code false}.
659 * <p>
660 * The job of honoring this property, and recognizing a user drag gesture,
661 * lies with the look and feel implementation, and in particular, the component's
662 * {@code TextUI}. When automatic drag handling is enabled, most look and
663 * feels (including those that subclass {@code BasicLookAndFeel}) begin a
664 * drag and drop operation whenever the user presses the mouse button over
665 * a selection and then moves the mouse a few pixels. Setting this property to
666 * {@code true} can therefore have a subtle effect on how selections behave.
667 * <p>
668 * If a look and feel is used that ignores this property, you can still
669 * begin a drag and drop operation by calling {@code exportAsDrag} on the
670 * component's {@code TransferHandler}.
671 *
672 * @param b whether or not to enable automatic drag handling
673 * @exception HeadlessException if
674 * {@code b} is {@code true} and
675 * {@code GraphicsEnvironment.isHeadless()}
676 * returns {@code true}
677 * @see java.awt.GraphicsEnvironment#isHeadless
678 * @see #getDragEnabled
679 * @see #setTransferHandler
680 * @see TransferHandler
681 * @since 1.4
682 *
683 * @beaninfo
684 * description: determines whether automatic drag handling is enabled
685 * bound: false
686 */
687 public void setDragEnabled(boolean b) {
688 checkDragEnabled(b);
689 dragEnabled = b;
690 }
691
692 private static void checkDragEnabled(boolean b) {
693 if (b && GraphicsEnvironment.isHeadless()) {
694 throw new HeadlessException();
695 }
696 }
697
698 /**
699 * Returns whether or not automatic drag handling is enabled.
700 *
701 * @return the value of the {@code dragEnabled} property
702 * @see #setDragEnabled
703 * @since 1.4
704 */
705 public boolean getDragEnabled() {
706 return dragEnabled;
707 }
708
709 /**
710 * Sets the drop mode for this component. For backward compatibility,
711 * the default for this property is {@code DropMode.USE_SELECTION}.
712 * Usage of {@code DropMode.INSERT} is recommended, however,
713 * for an improved user experience. It offers similar behavior of dropping
714 * between text locations, but does so without affecting the actual text
715 * selection and caret location.
716 * <p>
717 * {@code JTextComponents} support the following drop modes:
718 * <ul>
719 * <li>{@code DropMode.USE_SELECTION}</li>
720 * <li>{@code DropMode.INSERT}</li>
721 * </ul>
722 * <p>
723 * The drop mode is only meaningful if this component has a
724 * {@code TransferHandler} that accepts drops.
725 *
726 * @param dropMode the drop mode to use
727 * @throws IllegalArgumentException if the drop mode is unsupported
728 * or {@code null}
729 * @see #getDropMode
730 * @see #getDropLocation
731 * @see #setTransferHandler
732 * @see javax.swing.TransferHandler
733 * @since 1.6
734 */
735 public final void setDropMode(DropMode dropMode) {
736 checkDropMode(dropMode);
737 this.dropMode = dropMode;
738 }
739
740 private static void checkDropMode(DropMode dropMode) {
741 if (dropMode != null) {
742 switch (dropMode) {
743 case USE_SELECTION:
744 case INSERT:
745 return;
746 }
747 }
748
766 public TransferHandler.DropLocation dropLocationForPoint(JTextComponent textComp,
767 Point p)
768 {
769 return textComp.dropLocationForPoint(p);
770 }
771 public Object setDropLocation(JTextComponent textComp,
772 TransferHandler.DropLocation location,
773 Object state, boolean forDrop)
774 {
775 return textComp.setDropLocation(location, state, forDrop);
776 }
777 });
778 }
779
780
781 /**
782 * Calculates a drop location in this component, representing where a
783 * drop at the given point should insert data.
784 * <p>
785 * Note: This method is meant to override
786 * {@code JComponent.dropLocationForPoint()}, which is package-private
787 * in javax.swing. {@code TransferHandler} will detect text components
788 * and call this method instead via reflection. It's name should therefore
789 * not be changed.
790 *
791 * @param p the point to calculate a drop location for
792 * @return the drop location, or {@code null}
793 */
794 DropLocation dropLocationForPoint(Point p) {
795 Position.Bias[] bias = new Position.Bias[1];
796 int index = getUI().viewToModel(this, p, bias);
797
798 // viewToModel currently returns null for some HTML content
799 // when the point is within the component's top inset
800 if (bias[0] == null) {
801 bias[0] = Position.Bias.Forward;
802 }
803
804 return new DropLocation(p, index, bias[0]);
805 }
806
807 /**
808 * Called to set or clear the drop location during a DnD operation.
809 * In some cases, the component may need to use it's internal selection
810 * temporarily to indicate the drop location. To help facilitate this,
811 * this method returns and accepts as a parameter a state object.
812 * This state object can be used to store, and later restore, the selection
813 * state. Whatever this method returns will be passed back to it in
814 * future calls, as the state parameter. If it wants the DnD system to
815 * continue storing the same state, it must pass it back every time.
816 * Here's how this is used:
817 * <p>
818 * Let's say that on the first call to this method the component decides
819 * to save some state (because it is about to use the selection to show
820 * a drop index). It can return a state object to the caller encapsulating
821 * any saved selection state. On a second call, let's say the drop location
822 * is being changed to something else. The component doesn't need to
823 * restore anything yet, so it simply passes back the same state object
824 * to have the DnD system continue storing it. Finally, let's say this
825 * method is messaged with {@code null}. This means DnD
826 * is finished with this component for now, meaning it should restore
827 * state. At this point, it can use the state parameter to restore
828 * said state, and of course return {@code null} since there's
829 * no longer anything to store.
830 * <p>
831 * Note: This method is meant to override
832 * {@code JComponent.setDropLocation()}, which is package-private
833 * in javax.swing. {@code TransferHandler} will detect text components
834 * and call this method instead via reflection. It's name should therefore
835 * not be changed.
836 *
837 * @param location the drop location (as calculated by
838 * {@code dropLocationForPoint}) or {@code null}
839 * if there's no longer a valid drop location
840 * @param state the state object saved earlier for this component,
841 * or {@code null}
842 * @param forDrop whether or not the method is being called because an
843 * actual drop occurred
844 * @return any saved state for this component, or {@code null} if none
845 */
846 Object setDropLocation(TransferHandler.DropLocation location,
847 Object state,
848 boolean forDrop) {
849
850 Object retVal = null;
851 DropLocation textLocation = (DropLocation)location;
852
853 if (dropMode == DropMode.USE_SELECTION) {
854 if (textLocation == null) {
855 if (state != null) {
856 /*
857 * This object represents the state saved earlier.
858 * If the caret is a DefaultCaret it will be
859 * an Object array containing, in order:
860 * - the saved caret mark (Integer)
861 * - the saved caret dot (Integer)
862 * - the saved caret visibility (Boolean)
863 * - the saved mark bias (Position.Bias)
864 * - the saved dot bias (Position.Bias)
927 } else {
928 retVal = state;
929 }
930 }
931 }
932
933 DropLocation old = dropLocation;
934 dropLocation = textLocation;
935 firePropertyChange("dropLocation", old, dropLocation);
936
937 return retVal;
938 }
939
940 /**
941 * Returns the location that this component should visually indicate
942 * as the drop location during a DnD operation over the component,
943 * or {@code null} if no location is to currently be shown.
944 * <p>
945 * This method is not meant for querying the drop location
946 * from a {@code TransferHandler}, as the drop location is only
947 * set after the {@code TransferHandler}'s {@code canImport}
948 * has returned and has allowed for the location to be shown.
949 * <p>
950 * When this property changes, a property change event with
951 * name "dropLocation" is fired by the component.
952 *
953 * @return the drop location
954 * @see #setDropMode
955 * @see TransferHandler#canImport(TransferHandler.TransferSupport)
956 * @since 1.6
957 */
958 public final DropLocation getDropLocation() {
959 return dropLocation;
960 }
961
962
963 /**
964 * Updates the {@code InputMap}s in response to a
965 * {@code Keymap} change.
966 * @param oldKm the old {@code Keymap}
967 * @param newKm the new {@code Keymap}
968 */
969 void updateInputMap(Keymap oldKm, Keymap newKm) {
970 // Locate the current KeymapWrapper.
971 InputMap km = getInputMap(JComponent.WHEN_FOCUSED);
972 InputMap last = km;
973 while (km != null && !(km instanceof KeymapWrapper)) {
974 last = km;
975 km = km.getParent();
976 }
977 if (km != null) {
978 // Found it, tweak the InputMap that points to it, as well
979 // as anything it points to.
980 if (newKm == null) {
981 if (last != km) {
982 last.setParent(km.getParent());
983 }
984 else {
985 last.setParent(null);
986 }
987 }
1042 }
1043 }
1044
1045 /**
1046 * Fetches the keymap currently active in this text
1047 * component.
1048 *
1049 * @return the keymap
1050 */
1051 public Keymap getKeymap() {
1052 return keymap;
1053 }
1054
1055 /**
1056 * Adds a new keymap into the keymap hierarchy. Keymap bindings
1057 * resolve from bottom up so an attribute specified in a child
1058 * will override an attribute specified in the parent.
1059 *
1060 * @param nm the name of the keymap (must be unique within the
1061 * collection of named keymaps in the document); the name may
1062 * be {@code null} if the keymap is unnamed,
1063 * but the caller is responsible for managing the reference
1064 * returned as an unnamed keymap can't
1065 * be fetched by name
1066 * @param parent the parent keymap; this may be {@code null} if
1067 * unspecified bindings need not be resolved in some other keymap
1068 * @return the keymap
1069 */
1070 public static Keymap addKeymap(String nm, Keymap parent) {
1071 Keymap map = new DefaultKeymap(nm, parent);
1072 if (nm != null) {
1073 // add a named keymap, a class of bindings
1074 getKeymapTable().put(nm, map);
1075 }
1076 return map;
1077 }
1078
1079 /**
1080 * Removes a named keymap previously added to the document. Keymaps
1081 * with {@code null} names may not be removed in this way.
1082 *
1083 * @param nm the name of the keymap to remove
1084 * @return the keymap that was removed
1085 */
1086 public static Keymap removeKeymap(String nm) {
1087 return getKeymapTable().remove(nm);
1088 }
1089
1090 /**
1091 * Fetches a named keymap previously added to the document.
1092 * This does not work with {@code null}-named keymaps.
1093 *
1094 * @param nm the name of the keymap
1095 * @return the keymap
1096 */
1097 public static Keymap getKeymap(String nm) {
1098 return getKeymapTable().get(nm);
1099 }
1100
1101 private static HashMap<String,Keymap> getKeymapTable() {
1102 synchronized (KEYMAP_TABLE) {
1103 AppContext appContext = AppContext.getAppContext();
1104 @SuppressWarnings("unchecked")
1105 HashMap<String,Keymap> keymapTable =
1106 (HashMap<String,Keymap>)appContext.get(KEYMAP_TABLE);
1107 if (keymapTable == null) {
1108 keymapTable = new HashMap<String,Keymap>(17);
1109 appContext.put(KEYMAP_TABLE, keymapTable);
1110 //initialize default keymap
1111 Keymap binding = addKeymap(DEFAULT_KEYMAP, null);
1112 binding.setDefaultAction(new
1113 DefaultEditorKit.DefaultKeyTypedAction());
1114 }
1115 return keymapTable;
1116 }
1117 }
1118
1119 /**
1120 * Binding record for creating key bindings.
1121 * <p>
1122 * <strong>Warning:</strong>
1123 * Serialized objects of this class will not be compatible with
1124 * future Swing releases. The current serialization support is
1125 * appropriate for short term storage or RMI between applications running
1126 * the same version of Swing. As of 1.4, support for long term storage
1127 * of all JavaBeans™
1128 * has been added to the {@code java.beans} package.
1129 * Please see {@link java.beans.XMLEncoder}.
1130 */
1131 @SuppressWarnings("serial") // Same-version serialization only
1132 public static class KeyBinding {
1133
1134 /**
1135 * The key.
1136 */
1137 public KeyStroke key;
1138
1139 /**
1140 * The name of the action for the key.
1141 */
1142 public String actionName;
1143
1144 /**
1145 * Creates a new key binding.
1146 *
1147 * @param key the key
1148 * @param actionName the name of the action for the key
1149 */
1150 public KeyBinding(KeyStroke key, String actionName) {
1151 this.key = key;
1152 this.actionName = actionName;
1153 }
1154 }
1155
1156 /**
1157 * <p>
1158 * Loads a keymap with a bunch of
1159 * bindings. This can be used to take a static table of
1160 * definitions and load them into some keymap. The following
1161 * example illustrates an example of binding some keys to
1162 * the cut, copy, and paste actions associated with a
1163 * JTextComponent. A code fragment to accomplish
1164 * this might look as follows:
1165 * <pre>{@code
1166 *
1167 * static final JTextComponent.KeyBinding[] defaultBindings = {
1168 * new JTextComponent.KeyBinding(
1169 * KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK),
1170 * DefaultEditorKit.copyAction),
1171 * new JTextComponent.KeyBinding(
1172 * KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK),
1173 * DefaultEditorKit.pasteAction),
1174 * new JTextComponent.KeyBinding(
1175 * KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK),
1176 * DefaultEditorKit.cutAction),
1177 * };
1178 *
1179 * JTextComponent c = new JTextPane();
1180 * Keymap k = c.getKeymap();
1181 * JTextComponent.loadKeymap(k, defaultBindings, c.getActions());
1182 *
1183 * }</pre>
1184 * The sets of bindings and actions may be empty but must be
1185 * non-{@code null}.
1186 *
1187 * @param map the keymap
1188 * @param bindings the bindings
1189 * @param actions the set of actions
1190 */
1191 public static void loadKeymap(Keymap map, KeyBinding[] bindings, Action[] actions) {
1192 Hashtable<String, Action> h = new Hashtable<String, Action>();
1193 for (Action a : actions) {
1194 String value = (String)a.getValue(Action.NAME);
1195 h.put((value!=null ? value:""), a);
1196 }
1197 for (KeyBinding binding : bindings) {
1198 Action a = h.get(binding.actionName);
1199 if (a != null) {
1200 map.addActionForKeyStroke(binding.key, a);
1201 }
1202 }
1203 }
1204
1205 /**
1206 * Fetches the current color used to render the
1207 * caret.
1208 *
1209 * @return the color
1210 */
1211 public Color getCaretColor() {
1212 return caretColor;
1213 }
1214
1215 /**
1216 * Sets the current color used to render the caret.
1217 * Setting to {@code null} effectively restores the default color.
1218 * Setting the color results in a PropertyChange event ("caretColor")
1219 * being fired.
1220 *
1221 * @param c the color
1222 * @see #getCaretColor
1223 * @beaninfo
1224 * description: the color used to render the caret
1225 * bound: true
1226 * preferred: true
1227 */
1228 public void setCaretColor(Color c) {
1229 Color old = caretColor;
1230 caretColor = c;
1231 firePropertyChange("caretColor", old, caretColor);
1232 }
1233
1234 /**
1235 * Fetches the current color used to render the
1236 * selection.
1237 *
1238 * @return the color
1239 */
1240 public Color getSelectionColor() {
1241 return selectionColor;
1242 }
1243
1244 /**
1245 * Sets the current color used to render the selection.
1246 * Setting the color to {@code null} is the same as setting
1247 * {@code Color.white}. Setting the color results in a
1248 * PropertyChange event ("selectionColor").
1249 *
1250 * @param c the color
1251 * @see #getSelectionColor
1252 * @beaninfo
1253 * description: color used to render selection background
1254 * bound: true
1255 * preferred: true
1256 */
1257 public void setSelectionColor(Color c) {
1258 Color old = selectionColor;
1259 selectionColor = c;
1260 firePropertyChange("selectionColor", old, selectionColor);
1261 }
1262
1263 /**
1264 * Fetches the current color used to render the
1265 * selected text.
1266 *
1267 * @return the color
1268 */
1269 public Color getSelectedTextColor() {
1270 return selectedTextColor;
1271 }
1272
1273 /**
1274 * Sets the current color used to render the selected text.
1275 * Setting the color to {@code null} is the same as
1276 * {@code Color.black}. Setting the color results in a
1277 * PropertyChange event ("selectedTextColor") being fired.
1278 *
1279 * @param c the color
1280 * @see #getSelectedTextColor
1281 * @beaninfo
1282 * description: color used to render selected text
1283 * bound: true
1284 * preferred: true
1285 */
1286 public void setSelectedTextColor(Color c) {
1287 Color old = selectedTextColor;
1288 selectedTextColor = c;
1289 firePropertyChange("selectedTextColor", old, selectedTextColor);
1290 }
1291
1292 /**
1293 * Fetches the current color used to render the
1294 * disabled text.
1295 *
1296 * @return the color
1395 * to the nearest representative location in the model.
1396 * The component must have a positive size for
1397 * this translation to be computed (i.e. layout cannot
1398 * be computed until the component has been sized). The
1399 * component does not have to be visible or painted.
1400 *
1401 * @param pt the location in the view to translate
1402 * @return the offset ≥ 0 from the start of the document,
1403 * or -1 if the component does not yet have a positive
1404 * size.
1405 * @see TextUI#viewToModel
1406 */
1407 public int viewToModel(Point pt) {
1408 return getUI().viewToModel(this, pt);
1409 }
1410
1411 /**
1412 * Transfers the currently selected range in the associated
1413 * text model to the system clipboard, removing the contents
1414 * from the model. The current selection is reset. Does nothing
1415 * for {@code null} selections.
1416 *
1417 * @see java.awt.Toolkit#getSystemClipboard
1418 * @see java.awt.datatransfer.Clipboard
1419 */
1420 public void cut() {
1421 if (isEditable() && isEnabled()) {
1422 invokeAction("cut", TransferHandler.getCutAction());
1423 }
1424 }
1425
1426 /**
1427 * Transfers the currently selected range in the associated
1428 * text model to the system clipboard, leaving the contents
1429 * in the text model. The current selection remains intact.
1430 * Does nothing for {@code null} selections.
1431 *
1432 * @see java.awt.Toolkit#getSystemClipboard
1433 * @see java.awt.datatransfer.Clipboard
1434 */
1435 public void copy() {
1436 invokeAction("copy", TransferHandler.getCopyAction());
1437 }
1438
1439 /**
1440 * Transfers the contents of the system clipboard into the
1441 * associated text model. If there is a selection in the
1442 * associated view, it is replaced with the contents of the
1443 * clipboard. If there is no selection, the clipboard contents
1444 * are inserted in front of the current insert position in
1445 * the associated view. If the clipboard is empty, does nothing.
1446 *
1447 * @see #replaceSelection
1448 * @see java.awt.Toolkit#getSystemClipboard
1449 * @see java.awt.datatransfer.Clipboard
1450 */
1451 public void paste() {
1452 if (isEditable() && isEnabled()) {
1453 invokeAction("paste", TransferHandler.getPasteAction());
1454 }
1455 }
1456
1457 /**
1458 * This is a convenience method that is only useful for
1459 * {@code cut}, {@code copy} and {@code paste}. If
1460 * an {@code Action} with the name {@code name} does not
1461 * exist in the {@code ActionMap}, this will attempt to install a
1462 * {@code TransferHandler} and then use {@code altAction}.
1463 */
1464 private void invokeAction(String name, Action altAction) {
1465 ActionMap map = getActionMap();
1466 Action action = null;
1467
1468 if (map != null) {
1469 action = map.get(name);
1470 }
1471 if (action == null) {
1472 installDefaultTransferHandlerIfNecessary();
1473 action = altAction;
1474 }
1475 action.actionPerformed(new ActionEvent(this,
1476 ActionEvent.ACTION_PERFORMED, (String)action.
1477 getValue(Action.NAME),
1478 EventQueue.getMostRecentEventTime(),
1479 getCurrentEventModifiers()));
1480 }
1481
1482 /**
1483 * If the current {@code TransferHandler} is null, this will
1484 * install a new one.
1485 */
1486 private void installDefaultTransferHandlerIfNecessary() {
1487 if (getTransferHandler() == null) {
1488 if (defaultTransferHandler == null) {
1489 defaultTransferHandler = new DefaultTransferHandler();
1490 }
1491 setTransferHandler(defaultTransferHandler);
1492 }
1493 }
1494
1495 /**
1496 * Moves the caret to a new position, leaving behind a mark
1497 * defined by the last time {@code setCaretPosition} was
1498 * called. This forms a selection.
1499 * If the document is {@code null}, does nothing. The position
1500 * must be between 0 and the length of the component's text or else
1501 * an exception is thrown.
1502 *
1503 * @param pos the position
1504 * @exception IllegalArgumentException if the value supplied
1505 * for {@code position} is less than zero or greater
1506 * than the component's text length
1507 * @see #setCaretPosition
1508 */
1509 public void moveCaretPosition(int pos) {
1510 Document doc = getDocument();
1511 if (doc != null) {
1512 if (pos > doc.getLength() || pos < 0) {
1513 throw new IllegalArgumentException("bad position: " + pos);
1514 }
1515 caret.moveDot(pos);
1516 }
1517 }
1518
1519 /**
1520 * The bound property name for the focus accelerator.
1521 */
1522 public static final String FOCUS_ACCELERATOR_KEY = "focusAcceleratorKey";
1523
1524 /**
1525 * Sets the key accelerator that will cause the receiving text
1555 * text component to get the focus. Return '\0' if no focus
1556 * accelerator has been set.
1557 *
1558 * @return the key
1559 */
1560 public char getFocusAccelerator() {
1561 return focusAccelerator;
1562 }
1563
1564 /**
1565 * Initializes from a stream. This creates a
1566 * model of the type appropriate for the component
1567 * and initializes the model from the stream.
1568 * By default this will load the model as plain
1569 * text. Previous contents of the model are discarded.
1570 *
1571 * @param in the stream to read from
1572 * @param desc an object describing the stream; this
1573 * might be a string, a File, a URL, etc. Some kinds
1574 * of documents (such as html for example) might be
1575 * able to make use of this information; if non-{@code null},
1576 * it is added as a property of the document
1577 * @exception IOException as thrown by the stream being
1578 * used to initialize
1579 * @see EditorKit#createDefaultDocument
1580 * @see #setDocument
1581 * @see PlainDocument
1582 */
1583 public void read(Reader in, Object desc) throws IOException {
1584 EditorKit kit = getUI().getEditorKit(this);
1585 Document doc = kit.createDefaultDocument();
1586 if (desc != null) {
1587 doc.putProperty(Document.StreamDescriptionProperty, desc);
1588 }
1589 try {
1590 kit.read(in, doc, 0);
1591 setDocument(doc);
1592 } catch (BadLocationException e) {
1593 throw new IOException(e.getMessage());
1594 }
1595 }
1605 public void write(Writer out) throws IOException {
1606 Document doc = getDocument();
1607 try {
1608 getUI().getEditorKit(this).write(out, doc, 0, doc.getLength());
1609 } catch (BadLocationException e) {
1610 throw new IOException(e.getMessage());
1611 }
1612 }
1613
1614 public void removeNotify() {
1615 super.removeNotify();
1616 if (getFocusedComponent() == this) {
1617 AppContext.getAppContext().remove(FOCUSED_COMPONENT);
1618 }
1619 }
1620
1621 // --- java.awt.TextComponent methods ------------------------
1622
1623 /**
1624 * Sets the position of the text insertion caret for the
1625 * {@code TextComponent}. Note that the caret tracks change,
1626 * so this may move if the underlying text of the component is changed.
1627 * If the document is {@code null}, does nothing. The position
1628 * must be between 0 and the length of the component's text or else
1629 * an exception is thrown.
1630 *
1631 * @param position the position
1632 * @exception IllegalArgumentException if the value supplied
1633 * for {@code position} is less than zero or greater
1634 * than the component's text length
1635 * @beaninfo
1636 * description: the caret position
1637 */
1638 public void setCaretPosition(int position) {
1639 Document doc = getDocument();
1640 if (doc != null) {
1641 if (position > doc.getLength() || position < 0) {
1642 throw new IllegalArgumentException("bad position: " + position);
1643 }
1644 caret.setDot(position);
1645 }
1646 }
1647
1648 /**
1649 * Returns the position of the text insertion caret for the
1650 * text component.
1651 *
1652 * @return the position of the text insertion caret for the
1653 * text component ≥ 0
1654 */
1655 @Transient
1656 public int getCaretPosition() {
1657 return caret.getDot();
1658 }
1659
1660 /**
1661 * Sets the text of this {@code TextComponent}
1662 * to the specified text. If the text is {@code null}
1663 * or empty, has the effect of simply deleting the old text.
1664 * When text has been inserted, the resulting caret location
1665 * is determined by the implementation of the caret class.
1666 *
1667 * <p>
1668 * Note that text is not a bound property, so no {@code PropertyChangeEvent}
1669 * is fired when it changes. To listen for changes to the text,
1670 * use {@code DocumentListener}.
1671 *
1672 * @param t the new text to be set
1673 * @see #getText
1674 * @see DefaultCaret
1675 * @beaninfo
1676 * description: the text of this component
1677 */
1678 public void setText(String t) {
1679 try {
1680 Document doc = getDocument();
1681 if (doc instanceof AbstractDocument) {
1682 ((AbstractDocument)doc).replace(0, doc.getLength(), t,null);
1683 }
1684 else {
1685 doc.remove(0, doc.getLength());
1686 doc.insertString(0, t, null);
1687 }
1688 } catch (BadLocationException e) {
1689 UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this);
1690 }
1691 }
1692
1693 /**
1694 * Returns the text contained in this {@code TextComponent}.
1695 * If the underlying document is {@code null},
1696 * will give a {@code NullPointerException}.
1697 *
1698 * Note that text is not a bound property, so no {@code PropertyChangeEvent}
1699 * is fired when it changes. To listen for changes to the text,
1700 * use {@code DocumentListener}.
1701 *
1702 * @return the text
1703 * @exception NullPointerException if the document is {@code null}
1704 * @see #setText
1705 */
1706 public String getText() {
1707 Document doc = getDocument();
1708 String txt;
1709 try {
1710 txt = doc.getText(0, doc.getLength());
1711 } catch (BadLocationException e) {
1712 txt = null;
1713 }
1714 return txt;
1715 }
1716
1717 /**
1718 * Returns the selected text contained in this
1719 * {@code TextComponent}. If the selection is
1720 * {@code null} or the document empty, returns {@code null}.
1721 *
1722 * @return the text
1723 * @exception IllegalArgumentException if the selection doesn't
1724 * have a valid mapping into the document for some reason
1725 * @see #setText
1726 */
1727 public String getSelectedText() {
1728 String txt = null;
1729 int p0 = Math.min(caret.getDot(), caret.getMark());
1730 int p1 = Math.max(caret.getDot(), caret.getMark());
1731 if (p0 != p1) {
1732 try {
1733 Document doc = getDocument();
1734 txt = doc.getText(p0, p1 - p0);
1735 } catch (BadLocationException e) {
1736 throw new IllegalArgumentException(e.getMessage());
1737 }
1738 }
1739 return txt;
1740 }
1741
1742 /**
1743 * Returns the boolean indicating whether this
1744 * {@code TextComponent} is editable or not.
1745 *
1746 * @return the boolean value
1747 * @see #setEditable
1748 */
1749 public boolean isEditable() {
1750 return editable;
1751 }
1752
1753 /**
1754 * Sets the specified boolean to indicate whether or not this
1755 * {@code TextComponent} should be editable.
1756 * A PropertyChange event ("editable") is fired when the
1757 * state is changed.
1758 *
1759 * @param b the boolean to be set
1760 * @see #isEditable
1761 * @beaninfo
1762 * description: specifies if the text can be edited
1763 * bound: true
1764 */
1765 public void setEditable(boolean b) {
1766 if (b != editable) {
1767 boolean oldVal = editable;
1768 editable = b;
1769 enableInputMethods(editable);
1770 firePropertyChange("editable", Boolean.valueOf(oldVal), Boolean.valueOf(editable));
1771 repaint();
1772 }
1773 }
1774
1775 /**
1776 * Returns the selected text's start position. Return 0 for an
1777 * empty document, or the value of dot if no selection.
1778 *
1779 * @return the start position ≥ 0
1780 */
1781 @Transient
1782 public int getSelectionStart() {
1783 int start = Math.min(caret.getDot(), caret.getMark());
1784 return start;
1785 }
1786
1787 /**
1788 * Sets the selection start to the specified position. The new
1789 * starting point is constrained to be before or at the current
1790 * selection end.
1791 * <p>
1792 * This is available for backward compatibility to code
1793 * that called this method on {@code java.awt.TextComponent}.
1794 * This is implemented to forward to the {@code Caret}
1795 * implementation which is where the actual selection is maintained.
1796 *
1797 * @param selectionStart the start position of the text ≥ 0
1798 * @beaninfo
1799 * description: starting location of the selection.
1800 */
1801 public void setSelectionStart(int selectionStart) {
1802 /* Route through select method to enforce consistent policy
1803 * between selectionStart and selectionEnd.
1804 */
1805 select(selectionStart, getSelectionEnd());
1806 }
1807
1808 /**
1809 * Returns the selected text's end position. Return 0 if the document
1810 * is empty, or the value of dot if there is no selection.
1811 *
1812 * @return the end position ≥ 0
1813 */
1814 @Transient
1815 public int getSelectionEnd() {
1816 int end = Math.max(caret.getDot(), caret.getMark());
1817 return end;
1818 }
1819
1820 /**
1821 * Sets the selection end to the specified position. The new
1822 * end point is constrained to be at or after the current
1823 * selection start.
1824 * <p>
1825 * This is available for backward compatibility to code
1826 * that called this method on {@code java.awt.TextComponent}.
1827 * This is implemented to forward to the {@code Caret}
1828 * implementation which is where the actual selection is maintained.
1829 *
1830 * @param selectionEnd the end position of the text ≥ 0
1831 * @beaninfo
1832 * description: ending location of the selection.
1833 */
1834 public void setSelectionEnd(int selectionEnd) {
1835 /* Route through select method to enforce consistent policy
1836 * between selectionStart and selectionEnd.
1837 */
1838 select(getSelectionStart(), selectionEnd);
1839 }
1840
1841 /**
1842 * Selects the text between the specified start and end positions.
1843 * <p>
1844 * This method sets the start and end positions of the
1845 * selected text, enforcing the restriction that the start position
1846 * must be greater than or equal to zero. The end position must be
1847 * greater than or equal to the start position, and less than or
1848 * equal to the length of the text component's text.
1849 * <p>
1850 * If the caller supplies values that are inconsistent or out of
1851 * bounds, the method enforces these constraints silently, and
1852 * without failure. Specifically, if the start position or end
1853 * position is greater than the length of the text, it is reset to
1854 * equal the text length. If the start position is less than zero,
1855 * it is reset to zero, and if the end position is less than the
1856 * start position, it is reset to the start position.
1857 * <p>
1858 * This call is provided for backward compatibility.
1859 * It is routed to a call to {@code setCaretPosition}
1860 * followed by a call to {@code moveCaretPosition}.
1861 * The preferred way to manage selection is by calling
1862 * those methods directly.
1863 *
1864 * @param selectionStart the start position of the text
1865 * @param selectionEnd the end position of the text
1866 * @see #setCaretPosition
1867 * @see #moveCaretPosition
1868 */
1869 public void select(int selectionStart, int selectionEnd) {
1870 // argument adjustment done by java.awt.TextComponent
1871 int docLength = getDocument().getLength();
1872
1873 if (selectionStart < 0) {
1874 selectionStart = 0;
1875 }
1876 if (selectionStart > docLength) {
1877 selectionStart = docLength;
1878 }
1879 if (selectionEnd > docLength) {
1880 selectionEnd = docLength;
1881 }
1882 if (selectionEnd < selectionStart) {
1883 selectionEnd = selectionStart;
1884 }
1885
1886 setCaretPosition(selectionStart);
1887 moveCaretPosition(selectionEnd);
1888 }
1889
1890 /**
1891 * Selects all the text in the {@code TextComponent}.
1892 * Does nothing on a {@code null} or empty document.
1893 */
1894 public void selectAll() {
1895 Document doc = getDocument();
1896 if (doc != null) {
1897 setCaretPosition(0);
1898 moveCaretPosition(doc.getLength());
1899 }
1900 }
1901
1902 // --- Tooltip Methods ---------------------------------------------
1903
1904 /**
1905 * Returns the string to be used as the tooltip for {@code event}.
1906 * This will return one of:
1907 * <ol>
1908 * <li>If {@code setToolTipText} has been invoked with a
1909 * non-{@code null}
1910 * value, it will be returned, otherwise
1911 * <li>The value from invoking {@code getToolTipText} on
1912 * the UI will be returned.
1913 * </ol>
1914 * By default {@code JTextComponent} does not register
1915 * itself with the {@code ToolTipManager}.
1916 * This means that tooltips will NOT be shown from the
1917 * {@code TextUI} unless {@code registerComponent} has
1918 * been invoked on the {@code ToolTipManager}.
1919 *
1920 * @param event the event in question
1921 * @return the string to be used as the tooltip for {@code event}
1922 * @see javax.swing.JComponent#setToolTipText
1923 * @see javax.swing.plaf.TextUI#getToolTipText
1924 * @see javax.swing.ToolTipManager#registerComponent
1925 */
1926 public String getToolTipText(MouseEvent event) {
1927 String retValue = super.getToolTipText(event);
1928
1929 if (retValue == null) {
1930 TextUI ui = getUI();
1931 if (ui != null) {
1932 retValue = ui.getToolTipText(this, new Point(event.getX(),
1933 event.getY()));
1934 }
1935 }
1936 return retValue;
1937 }
1938
1939 // --- Scrollable methods ---------------------------------------------
1940
1941 /**
1942 * Returns the preferred size of the viewport for a view component.
1943 * This is implemented to do the default behavior of returning
1944 * the preferred size of the component.
1945 *
1946 * @return the {@code preferredSize} of a {@code JViewport}
1947 * whose view is this {@code Scrollable}
1948 */
1949 public Dimension getPreferredScrollableViewportSize() {
1950 return getPreferredSize();
1951 }
1952
1953
1954 /**
1955 * Components that display logical rows or columns should compute
1956 * the scroll increment that will completely expose one new row
1957 * or column, depending on the value of orientation. Ideally,
1958 * components should handle a partially exposed row or column by
1959 * returning the distance required to completely expose the item.
1960 * <p>
1961 * The default implementation of this is to simply return 10% of
1962 * the visible area. Subclasses are likely to be able to provide
1963 * a much more reasonable value.
1964 *
1965 * @param visibleRect the view area visible within the viewport
1966 * @param orientation either {@code SwingConstants.VERTICAL} or
1967 * {@code SwingConstants.HORIZONTAL}
1968 * @param direction less than zero to scroll up/left, greater than
1969 * zero for down/right
1970 * @return the "unit" increment for scrolling in the specified direction
1971 * @exception IllegalArgumentException for an invalid orientation
1972 * @see JScrollBar#setUnitIncrement
1973 */
1974 public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
1975 switch(orientation) {
1976 case SwingConstants.VERTICAL:
1977 return visibleRect.height / 10;
1978 case SwingConstants.HORIZONTAL:
1979 return visibleRect.width / 10;
1980 default:
1981 throw new IllegalArgumentException("Invalid orientation: " + orientation);
1982 }
1983 }
1984
1985
1986 /**
1987 * Components that display logical rows or columns should compute
1988 * the scroll increment that will completely expose one block
1989 * of rows or columns, depending on the value of orientation.
1990 * <p>
1991 * The default implementation of this is to simply return the visible
1992 * area. Subclasses will likely be able to provide a much more
1993 * reasonable value.
1994 *
1995 * @param visibleRect the view area visible within the viewport
1996 * @param orientation either {@code SwingConstants.VERTICAL} or
1997 * {@code SwingConstants.HORIZONTAL}
1998 * @param direction less than zero to scroll up/left, greater than zero
1999 * for down/right
2000 * @return the "block" increment for scrolling in the specified direction
2001 * @exception IllegalArgumentException for an invalid orientation
2002 * @see JScrollBar#setBlockIncrement
2003 */
2004 public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
2005 switch(orientation) {
2006 case SwingConstants.VERTICAL:
2007 return visibleRect.height;
2008 case SwingConstants.HORIZONTAL:
2009 return visibleRect.width;
2010 default:
2011 throw new IllegalArgumentException("Invalid orientation: " + orientation);
2012 }
2013 }
2014
2015
2016 /**
2017 * Returns true if a viewport should always force the width of this
2018 * {@code Scrollable} to match the width of the viewport.
2019 * For example a normal text view that supported line wrapping
2020 * would return true here, since it would be undesirable for
2021 * wrapped lines to disappear beyond the right
2022 * edge of the viewport. Note that returning true for a
2023 * {@code Scrollable} whose ancestor is a {@code JScrollPane}
2024 * effectively disables horizontal scrolling.
2025 * <p>
2026 * Scrolling containers, like {@code JViewport},
2027 * will use this method each time they are validated.
2028 *
2029 * @return true if a viewport should force the {@code Scrollable}s
2030 * width to match its own
2031 */
2032 public boolean getScrollableTracksViewportWidth() {
2033 Container parent = SwingUtilities.getUnwrappedParent(this);
2034 if (parent instanceof JViewport) {
2035 return parent.getWidth() > getPreferredSize().width;
2036 }
2037 return false;
2038 }
2039
2040 /**
2041 * Returns true if a viewport should always force the height of this
2042 * {@code Scrollable} to match the height of the viewport.
2043 * For example a columnar text view that flowed text in left to
2044 * right columns could effectively disable vertical scrolling by
2045 * returning true here.
2046 * <p>
2047 * Scrolling containers, like {@code JViewport},
2048 * will use this method each time they are validated.
2049 *
2050 * @return true if a viewport should force the Scrollables height
2051 * to match its own
2052 */
2053 public boolean getScrollableTracksViewportHeight() {
2054 Container parent = SwingUtilities.getUnwrappedParent(this);
2055 if (parent instanceof JViewport) {
2056 return parent.getHeight() > getPreferredSize().height;
2057 }
2058 return false;
2059 }
2060
2061
2062 //////////////////
2063 // Printing Support
2064 //////////////////
2065
2066 /**
2067 * A convenience print method that displays a print dialog, and then
2456 *
2457 * @see java.awt.print.Printable
2458 * @see java.awt.print.PageFormat
2459 * @see javax.swing.text.Document#render(java.lang.Runnable)
2460 *
2461 * @since 1.6
2462 */
2463 public Printable getPrintable(final MessageFormat headerFormat,
2464 final MessageFormat footerFormat) {
2465 return TextComponentPrintable.getPrintable(
2466 this, headerFormat, footerFormat);
2467 }
2468
2469
2470 /////////////////
2471 // Accessibility support
2472 ////////////////
2473
2474
2475 /**
2476 * Gets the {@code AccessibleContext} associated with this
2477 * {@code JTextComponent}. For text components,
2478 * the {@code AccessibleContext} takes the form of an
2479 * {@code AccessibleJTextComponent}.
2480 * A new {@code AccessibleJTextComponent} instance
2481 * is created if necessary.
2482 *
2483 * @return an {@code AccessibleJTextComponent} that serves as the
2484 * {@code AccessibleContext} of this
2485 * {@code JTextComponent}
2486 */
2487 public AccessibleContext getAccessibleContext() {
2488 if (accessibleContext == null) {
2489 accessibleContext = new AccessibleJTextComponent();
2490 }
2491 return accessibleContext;
2492 }
2493
2494 /**
2495 * This class implements accessibility support for the
2496 * {@code JTextComponent} class. It provides an implementation of
2497 * the Java Accessibility API appropriate to menu user-interface elements.
2498 * <p>
2499 * <strong>Warning:</strong>
2500 * Serialized objects of this class will not be compatible with
2501 * future Swing releases. The current serialization support is
2502 * appropriate for short term storage or RMI between applications running
2503 * the same version of Swing. As of 1.4, support for long term storage
2504 * of all JavaBeans™
2505 * has been added to the {@code java.beans} package.
2506 * Please see {@link java.beans.XMLEncoder}.
2507 */
2508 @SuppressWarnings("serial") // Same-version serialization only
2509 public class AccessibleJTextComponent extends AccessibleJComponent
2510 implements AccessibleText, CaretListener, DocumentListener,
2511 AccessibleAction, AccessibleEditableText,
2512 AccessibleExtendedText {
2513
2514 int caretPos;
2515 Point oldLocationOnScreen;
2516
2517 /**
2518 * Constructs an AccessibleJTextComponent. Adds a listener to track
2519 * caret change.
2520 */
2521 public AccessibleJTextComponent() {
2522 Document doc = JTextComponent.this.getDocument();
2523 if (doc != null) {
2524 doc.addDocumentListener(this);
2525 }
2871 * Return 0 if the text is empty, or the caret position
2872 * if no selection.
2873 *
2874 * @return the index into the text of the end of the selection ≥ 0
2875 */
2876 public int getSelectionEnd() {
2877 return JTextComponent.this.getSelectionEnd();
2878 }
2879
2880 /**
2881 * Returns the portion of the text that is selected.
2882 *
2883 * @return the text, null if no selection
2884 */
2885 public String getSelectedText() {
2886 return JTextComponent.this.getSelectedText();
2887 }
2888
2889 /**
2890 * IndexedSegment extends Segment adding the offset into the
2891 * the model the {@code Segment} was asked for.
2892 */
2893 private class IndexedSegment extends Segment {
2894 /**
2895 * Offset into the model that the position represents.
2896 */
2897 public int modelOffset;
2898 }
2899
2900
2901 // TIGER - 4170173
2902 /**
2903 * Returns the String at a given index. Whitespace
2904 * between words is treated as a word.
2905 *
2906 * @param part the CHARACTER, WORD, or SENTENCE to retrieve
2907 * @param index an index within the text
2908 * @return the letter, word, or sentence.
2909 *
2910 */
2911 public String getAtIndex(int part, int index) {
2923 */
2924 public String getAfterIndex(int part, int index) {
2925 return getAtIndex(part, index, 1);
2926 }
2927
2928
2929 /**
2930 * Returns the String before a given index. Whitespace
2931 * between words is treated a word.
2932 *
2933 * @param part the CHARACTER, WORD, or SENTENCE to retrieve
2934 * @param index an index within the text
2935 * @return the letter, word, or sentence.
2936 */
2937 public String getBeforeIndex(int part, int index) {
2938 return getAtIndex(part, index, -1);
2939 }
2940
2941
2942 /**
2943 * Gets the word, sentence, or character at {@code index}.
2944 * If {@code direction} is non-null this will find the
2945 * next/previous word/sentence/character.
2946 */
2947 private String getAtIndex(int part, int index, int direction) {
2948 if (model instanceof AbstractDocument) {
2949 ((AbstractDocument)model).readLock();
2950 }
2951 try {
2952 if (index < 0 || index >= model.getLength()) {
2953 return null;
2954 }
2955 switch (part) {
2956 case AccessibleText.CHARACTER:
2957 if (index + direction < model.getLength() &&
2958 index + direction >= 0) {
2959 return model.getText(index + direction, 1);
2960 }
2961 break;
2962
2963
2964 case AccessibleText.WORD:
3010 if (model instanceof PlainDocument ) {
3011 PlainDocument sdoc = (PlainDocument)model;
3012 return sdoc.getParagraphElement(index);
3013 } else if (model instanceof StyledDocument) {
3014 StyledDocument sdoc = (StyledDocument)model;
3015 return sdoc.getParagraphElement(index);
3016 } else {
3017 Element para;
3018 for (para = model.getDefaultRootElement(); ! para.isLeaf(); ) {
3019 int pos = para.getElementIndex(index);
3020 para = para.getElement(pos);
3021 }
3022 if (para == null) {
3023 return null;
3024 }
3025 return para.getParentElement();
3026 }
3027 }
3028
3029 /*
3030 * Returns a {@code Segment} containing the paragraph text
3031 * at {@code index}, or null if {@code index} isn't
3032 * valid.
3033 */
3034 private IndexedSegment getParagraphElementText(int index)
3035 throws BadLocationException {
3036 Element para = getParagraphElement(index);
3037
3038
3039 if (para != null) {
3040 IndexedSegment segment = new IndexedSegment();
3041 try {
3042 int length = para.getEndOffset() - para.getStartOffset();
3043 model.getText(para.getStartOffset(), length, segment);
3044 } catch (BadLocationException e) {
3045 return null;
3046 }
3047 segment.modelOffset = para.getStartOffset();
3048 return segment;
3049 }
3050 return null;
3051 }
3052
3053
3054 /**
3055 * Returns the Segment at {@code index} representing either
3056 * the paragraph or sentence as identified by {@code part}, or
3057 * null if a valid paragraph/sentence can't be found. The offset
3058 * will point to the start of the word/sentence in the array, and
3059 * the modelOffset will point to the location of the word/sentence
3060 * in the model.
3061 */
3062 private IndexedSegment getSegmentAt(int part, int index) throws
3063 BadLocationException {
3064 IndexedSegment seg = getParagraphElementText(index);
3065 if (seg == null) {
3066 return null;
3067 }
3068 BreakIterator iterator;
3069 switch (part) {
3070 case AccessibleText.WORD:
3071 iterator = BreakIterator.getWordInstance(getLocale());
3072 break;
3073 case AccessibleText.SENTENCE:
3074 iterator = BreakIterator.getSentenceInstance(getLocale());
3075 break;
3076 default:
3255 Document doc = JTextComponent.this.getDocument();
3256 if (doc != null && doc instanceof StyledDocument) {
3257 StyledDocument sDoc = (StyledDocument)doc;
3258 int offset = startIndex;
3259 int length = endIndex - startIndex;
3260 sDoc.setCharacterAttributes(offset, length, as, true);
3261 }
3262 }
3263
3264 // ----- end AccessibleEditableText methods
3265
3266
3267 // ----- begin AccessibleExtendedText methods
3268
3269 // Probably should replace the helper method getAtIndex() to return
3270 // instead an AccessibleTextSequence also for LINE & ATTRIBUTE_RUN
3271 // and then make the AccessibleText methods get[At|After|Before]Point
3272 // call this new method instead and return only the string portion
3273
3274 /**
3275 * Returns the AccessibleTextSequence at a given {@code index}.
3276 * If {@code direction} is non-null this will find the
3277 * next/previous word/sentence/character.
3278 *
3279 * @param part the {@code CHARACTER}, {@code WORD},
3280 * {@code SENTENCE}, {@code LINE} or
3281 * {@code ATTRIBUTE_RUN} to retrieve
3282 * @param index an index within the text
3283 * @param direction is either -1, 0, or 1
3284 * @return an {@code AccessibleTextSequence} specifying the text
3285 * if {@code part} and {@code index} are valid. Otherwise,
3286 * {@code null} is returned.
3287 *
3288 * @see javax.accessibility.AccessibleText#CHARACTER
3289 * @see javax.accessibility.AccessibleText#WORD
3290 * @see javax.accessibility.AccessibleText#SENTENCE
3291 * @see javax.accessibility.AccessibleExtendedText#LINE
3292 * @see javax.accessibility.AccessibleExtendedText#ATTRIBUTE_RUN
3293 *
3294 * @since 1.6
3295 */
3296 private AccessibleTextSequence getSequenceAtIndex(int part,
3297 int index, int direction) {
3298 if (index < 0 || index >= model.getLength()) {
3299 return null;
3300 }
3301 if (direction < -1 || direction > 1) {
3302 return null; // direction must be 1, 0, or -1
3303 }
3304
3305 switch (part) {
3306 case AccessibleText.CHARACTER:
3486 // we are intentionally silent; our contract says we return
3487 // null if there is any failure in this method
3488 return null;
3489 } finally {
3490 if (model instanceof AbstractDocument) {
3491 ((AbstractDocument)model).readUnlock();
3492 }
3493 }
3494 return new AccessibleTextSequence(attributeRunStartIndex,
3495 attributeRunEndIndex,
3496 runText);
3497
3498 default:
3499 break;
3500 }
3501 return null;
3502 }
3503
3504
3505 /**
3506 * Starting at text position {@code index}, and going in
3507 * {@code direction}, return the edge of run that shares the
3508 * same {@code AttributeSet} and parent element as those at
3509 * {@code index}.
3510 *
3511 * Note: we assume the document is already locked...
3512 */
3513 private int getRunEdge(int index, int direction) throws
3514 BadLocationException {
3515 if (index < 0 || index >= model.getLength()) {
3516 throw new BadLocationException("Location out of bounds", index);
3517 }
3518 // locate the Element at index
3519 Element indexElement;
3520 // locate the Element at our index/offset
3521 int elementIndex = -1; // test for initialization
3522 for (indexElement = model.getDefaultRootElement();
3523 ! indexElement.isLeaf(); ) {
3524 elementIndex = indexElement.getElementIndex(index);
3525 indexElement = indexElement.getElement(elementIndex);
3526 }
3527 if (elementIndex == -1) {
3528 throw new AssertionError(index);
3529 }
3549 edgeElement = parent.getElement(edgeElementIndex);
3550 break;
3551 default:
3552 throw new AssertionError(direction);
3553 }
3554 switch (direction) {
3555 case -1:
3556 return edgeElement.getStartOffset();
3557 case 1:
3558 return edgeElement.getEndOffset();
3559 default:
3560 // we already caught this case earlier; this is to satisfy
3561 // the compiler...
3562 return Integer.MIN_VALUE;
3563 }
3564 }
3565
3566 // getTextRange() not needed; defined in AccessibleEditableText
3567
3568 /**
3569 * Returns the {@code AccessibleTextSequence} at a given
3570 * {@code index}.
3571 *
3572 * @param part the {@code CHARACTER}, {@code WORD},
3573 * {@code SENTENCE}, {@code LINE} or
3574 * {@code ATTRIBUTE_RUN} to retrieve
3575 * @param index an index within the text
3576 * @return an {@code AccessibleTextSequence} specifying the text if
3577 * {@code part} and {@code index} are valid. Otherwise,
3578 * {@code null} is returned
3579 *
3580 * @see javax.accessibility.AccessibleText#CHARACTER
3581 * @see javax.accessibility.AccessibleText#WORD
3582 * @see javax.accessibility.AccessibleText#SENTENCE
3583 * @see javax.accessibility.AccessibleExtendedText#LINE
3584 * @see javax.accessibility.AccessibleExtendedText#ATTRIBUTE_RUN
3585 *
3586 * @since 1.6
3587 */
3588 public AccessibleTextSequence getTextSequenceAt(int part, int index) {
3589 return getSequenceAtIndex(part, index, 0);
3590 }
3591
3592 /**
3593 * Returns the {@code AccessibleTextSequence} after a given
3594 * {@code index}.
3595 *
3596 * @param part the {@code CHARACTER}, {@code WORD},
3597 * {@code SENTENCE}, {@code LINE} or
3598 * {@code ATTRIBUTE_RUN} to retrieve
3599 * @param index an index within the text
3600 * @return an {@code AccessibleTextSequence} specifying the text
3601 * if {@code part} and {@code index} are valid. Otherwise,
3602 * {@code null} is returned
3603 *
3604 * @see javax.accessibility.AccessibleText#CHARACTER
3605 * @see javax.accessibility.AccessibleText#WORD
3606 * @see javax.accessibility.AccessibleText#SENTENCE
3607 * @see javax.accessibility.AccessibleExtendedText#LINE
3608 * @see javax.accessibility.AccessibleExtendedText#ATTRIBUTE_RUN
3609 *
3610 * @since 1.6
3611 */
3612 public AccessibleTextSequence getTextSequenceAfter(int part, int index) {
3613 return getSequenceAtIndex(part, index, 1);
3614 }
3615
3616 /**
3617 * Returns the {@code AccessibleTextSequence} before a given
3618 * {@code index}.
3619 *
3620 * @param part the {@code CHARACTER}, {@code WORD},
3621 * {@code SENTENCE}, {@code LINE} or
3622 * {@code ATTRIBUTE_RUN} to retrieve
3623 * @param index an index within the text
3624 * @return an {@code AccessibleTextSequence} specifying the text
3625 * if {@code part} and {@code index} are valid. Otherwise,
3626 * {@code null} is returned
3627 *
3628 * @see javax.accessibility.AccessibleText#CHARACTER
3629 * @see javax.accessibility.AccessibleText#WORD
3630 * @see javax.accessibility.AccessibleText#SENTENCE
3631 * @see javax.accessibility.AccessibleExtendedText#LINE
3632 * @see javax.accessibility.AccessibleExtendedText#ATTRIBUTE_RUN
3633 *
3634 * @since 1.6
3635 */
3636 public AccessibleTextSequence getTextSequenceBefore(int part, int index) {
3637 return getSequenceAtIndex(part, index, -1);
3638 }
3639
3640 /**
3641 * Returns the {@code Rectangle} enclosing the text between
3642 * two indicies.
3643 *
3644 * @param startIndex the start index in the text
3645 * @param endIndex the end index in the text
3646 * @return the bounding rectangle of the text if the indices are valid.
3647 * Otherwise, {@code null} is returned
3648 *
3649 * @since 1.6
3650 */
3651 public Rectangle getTextBounds(int startIndex, int endIndex) {
3652 if (startIndex < 0 || startIndex > model.getLength()-1 ||
3653 endIndex < 0 || endIndex > model.getLength()-1 ||
3654 startIndex > endIndex) {
3655 return null;
3656 }
3657 TextUI ui = getUI();
3658 if (ui == null) {
3659 return null;
3660 }
3661 Rectangle rect = null;
3662 Rectangle alloc = getRootEditorRect();
3663 if (alloc == null) {
3664 return null;
3665 }
3666 if (model instanceof AbstractDocument) {
3667 ((AbstractDocument)model).readLock();
3834 private Color caretColor;
3835 private Color selectionColor;
3836 private Color selectedTextColor;
3837 private Color disabledTextColor;
3838 private boolean editable;
3839 private Insets margin;
3840 private char focusAccelerator;
3841 private boolean dragEnabled;
3842
3843 /**
3844 * The drop mode for this component.
3845 */
3846 private DropMode dropMode = DropMode.USE_SELECTION;
3847
3848 /**
3849 * The drop location.
3850 */
3851 private transient DropLocation dropLocation;
3852
3853 /**
3854 * Represents a drop location for {@code JTextComponent}s.
3855 *
3856 * @see #getDropLocation
3857 * @since 1.6
3858 */
3859 public static final class DropLocation extends TransferHandler.DropLocation {
3860 private final int index;
3861 private final Position.Bias bias;
3862
3863 private DropLocation(Point p, int index, Position.Bias bias) {
3864 super(p);
3865 this.index = index;
3866 this.bias = bias;
3867 }
3868
3869 /**
3870 * Returns the index where dropped data should be inserted into the
3871 * associated component. This index represents a position between
3872 * characters, as would be interpreted by a caret.
3873 *
3874 * @return the drop index
3892 * and the content and format of the returned string may vary
3893 * between implementations.
3894 *
3895 * @return a string representation of this drop location
3896 */
3897 public String toString() {
3898 return getClass().getName()
3899 + "[dropPoint=" + getDropPoint() + ","
3900 + "index=" + index + ","
3901 + "bias=" + bias + "]";
3902 }
3903 }
3904
3905 /**
3906 * TransferHandler used if one hasn't been supplied by the UI.
3907 */
3908 private static DefaultTransferHandler defaultTransferHandler;
3909
3910 /**
3911 * Maps from class name to Boolean indicating if
3912 * {@code processInputMethodEvent} has been overriden.
3913 */
3914 private static Cache<Class<?>,Boolean> METHOD_OVERRIDDEN
3915 = new Cache<Class<?>,Boolean>(Cache.Kind.WEAK, Cache.Kind.STRONG) {
3916 /**
3917 * Returns {@code true} if the specified {@code type} extends {@link JTextComponent}
3918 * and the {@link JTextComponent#processInputMethodEvent} method is overridden.
3919 */
3920 @Override
3921 public Boolean create(final Class<?> type) {
3922 if (JTextComponent.class == type) {
3923 return Boolean.FALSE;
3924 }
3925 if (get(type.getSuperclass())) {
3926 return Boolean.TRUE;
3927 }
3928 return AccessController.doPrivileged(
3929 new PrivilegedAction<Boolean>() {
3930 public Boolean run() {
3931 try {
3932 type.getDeclaredMethod("processInputMethodEvent", InputMethodEvent.class);
3933 return Boolean.TRUE;
3934 } catch (NoSuchMethodException exception) {
3935 return Boolean.FALSE;
3936 }
3937 }
3938 });
3939 }
3940 };
3941
3942 /**
3943 * Returns a string representation of this {@code JTextComponent}.
3944 * This method is intended to be used only for debugging purposes, and the
3945 * content and format of the returned string may vary between
3946 * implementations. The returned string may be empty but may not
3947 * be {@code null}.
3948 * <P>
3949 * Overriding {@code paramString} to provide information about the
3950 * specific new aspects of the JFC components.
3951 *
3952 * @return a string representation of this {@code JTextComponent}
3953 */
3954 protected String paramString() {
3955 String editableString = (editable ?
3956 "true" : "false");
3957 String caretColorString = (caretColor != null ?
3958 caretColor.toString() : "");
3959 String selectionColorString = (selectionColor != null ?
3960 selectionColor.toString() : "");
3961 String selectedTextColorString = (selectedTextColor != null ?
3962 selectedTextColor.toString() : "");
3963 String disabledTextColorString = (disabledTextColor != null ?
3964 disabledTextColor.toString() : "");
3965 String marginString = (margin != null ?
3966 margin.toString() : "");
3967
3968 return super.paramString() +
3969 ",caretColor=" + caretColorString +
3970 ",disabledTextColor=" + disabledTextColorString +
3971 ",editable=" + editableString +
3972 ",margin=" + marginString +
4245 * String representation of the keymap... potentially
4246 * a very long string.
4247 */
4248 public String toString() {
4249 return "Keymap[" + nm + "]" + bindings;
4250 }
4251
4252 String nm;
4253 Keymap parent;
4254 Hashtable<KeyStroke, Action> bindings;
4255 Action defaultAction;
4256 }
4257
4258
4259 /**
4260 * KeymapWrapper wraps a Keymap inside an InputMap. For KeymapWrapper
4261 * to be useful it must be used with a KeymapActionMap.
4262 * KeymapWrapper for the most part, is an InputMap with two parents.
4263 * The first parent visited is ALWAYS the Keymap, with the second
4264 * parent being the parent inherited from InputMap. If
4265 * {@code keymap.getAction} returns null, implying the Keymap
4266 * does not have a binding for the KeyStroke,
4267 * the parent is then visited. If the Keymap has a binding, the
4268 * Action is returned, if not and the KeyStroke represents a
4269 * KeyTyped event and the Keymap has a defaultAction,
4270 * {@code DefaultActionKey} is returned.
4271 * <p>KeymapActionMap is then able to transate the object passed in
4272 * to either message the Keymap, or message its default implementation.
4273 */
4274 static class KeymapWrapper extends InputMap {
4275 static final Object DefaultActionKey = new Object();
4276
4277 private Keymap keymap;
4278
4279 KeymapWrapper(Keymap keymap) {
4280 this.keymap = keymap;
4281 }
4282
4283 public KeyStroke[] keys() {
4284 KeyStroke[] sKeys = super.keys();
4285 KeyStroke[] keymapKeys = keymap.getBoundKeyStrokes();
4286 int sCount = (sKeys == null) ? 0 : sKeys.length;
4287 int keymapCount = (keymapKeys == null) ? 0 : keymapKeys.length;
4288 if (sCount == 0) {
4289 return keymapKeys;
4290 }
4308
4309 public Object get(KeyStroke keyStroke) {
4310 Object retValue = keymap.getAction(keyStroke);
4311 if (retValue == null) {
4312 retValue = super.get(keyStroke);
4313 if (retValue == null &&
4314 keyStroke.getKeyChar() != KeyEvent.CHAR_UNDEFINED &&
4315 keymap.getDefaultAction() != null) {
4316 // Implies this is a KeyTyped event, use the default
4317 // action.
4318 retValue = DefaultActionKey;
4319 }
4320 }
4321 return retValue;
4322 }
4323 }
4324
4325
4326 /**
4327 * Wraps a Keymap inside an ActionMap. This is used with
4328 * a KeymapWrapper. If {@code get} is passed in
4329 * {@code KeymapWrapper.DefaultActionKey}, the default action is
4330 * returned, otherwise if the key is an Action, it is returned.
4331 */
4332 static class KeymapActionMap extends ActionMap {
4333 private Keymap keymap;
4334
4335 KeymapActionMap(Keymap keymap) {
4336 this.keymap = keymap;
4337 }
4338
4339 public Object[] keys() {
4340 Object[] sKeys = super.keys();
4341 Object[] keymapKeys = keymap.getBoundActions();
4342 int sCount = (sKeys == null) ? 0 : sKeys.length;
4343 int keymapCount = (keymapKeys == null) ? 0 : keymapKeys.length;
4344 boolean hasDefault = (keymap.getDefaultAction() != null);
4345 if (hasDefault) {
4346 keymapCount++;
4347 }
4348 if (sCount == 0) {
4349 if (hasDefault) {
4393 // Try the Keymap.
4394 if (key == KeymapWrapper.DefaultActionKey) {
4395 retValue = keymap.getDefaultAction();
4396 }
4397 else if (key instanceof Action) {
4398 // This is a little iffy, technically an Action is
4399 // a valid Key. We're assuming the Action came from
4400 // the InputMap though.
4401 retValue = (Action)key;
4402 }
4403 }
4404 return retValue;
4405 }
4406 }
4407
4408 private static final Object FOCUSED_COMPONENT =
4409 new StringBuilder("JTextComponent_FocusedComponent");
4410
4411 /**
4412 * The default keymap that will be shared by all
4413 * {@code JTextComponent} instances unless they
4414 * have had a different keymap set.
4415 */
4416 public static final String DEFAULT_KEYMAP = "default";
4417
4418 /**
4419 * Event to use when firing a notification of change to caret
4420 * position. This is mutable so that the event can be reused
4421 * since caret events can be fairly high in bandwidth.
4422 */
4423 static class MutableCaretEvent extends CaretEvent implements ChangeListener, FocusListener, MouseListener {
4424
4425 MutableCaretEvent(JTextComponent c) {
4426 super(c);
4427 }
4428
4429 final void fire() {
4430 JTextComponent c = (JTextComponent) getSource();
4431 if (c != null) {
4432 Caret caret = c.getCaret();
4433 dot = caret.getDot();
|