/*
 * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package javax.swing.text;

import com.sun.beans.util.Cache;

import java.security.AccessController;
import java.security.PrivilegedAction;

import java.beans.JavaBean;
import java.beans.BeanProperty;
import java.beans.Transient;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Vector;

import java.util.concurrent.*;

import java.io.*;

import java.awt.*;
import java.awt.event.*;
import java.awt.print.*;
import java.awt.datatransfer.*;
import java.awt.im.InputContext;
import java.awt.im.InputMethodRequests;
import java.awt.font.TextHitInfo;
import java.awt.font.TextAttribute;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import java.awt.print.Printable;
import java.awt.print.PrinterException;

import javax.print.PrintService;
import javax.print.attribute.PrintRequestAttributeSet;

import java.text.*;
import java.text.AttributedCharacterIterator.Attribute;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.plaf.*;

import javax.accessibility.*;

import javax.print.attribute.*;

import sun.awt.AppContext;


import sun.swing.PrintingStatus;
import sun.swing.SwingUtilities2;
import sun.swing.text.TextComponentPrintable;
import sun.swing.SwingAccessor;

JTextComponent is the base class for swing text components. It tries to be compatible with the java.awt.TextComponent class where it can reasonably do so. Also provided are other services for additional flexibility (beyond the pluggable UI and bean support). You can find information on how to use the functionality this class provides in General Rules for Using Text Components, a section in The Java Tutorial.
Caret Changes
The caret is a pluggable object in swing text components. Notification of changes to the caret position and the selection are sent to implementations of the CaretListener interface that have been registered with the text component. The UI will install a default caret unless a customized caret has been set.
By default the caret tracks all the document changes performed on the Event Dispatching Thread and updates it's position accordingly if an insertion occurs before or at the caret position or a removal occurs before the caret position. DefaultCaret tries to make itself visible which may lead to scrolling of a text component within JScrollPane. The default caret behavior can be changed by the DefaultCaret.setUpdatePolicy method.
Note: Non-editable text components also have a caret though it may not be painted.
Commands
Text components provide a number of commands that can be used to manipulate the component. This is essentially the way that the component expresses its capabilities. These are expressed in terms of the swing Action interface, using the TextAction implementation. The set of commands supported by the text component can be found with the getActions method. These actions can be bound to key events, fired from buttons, etc.
Text Input
The text components support flexible and internationalized text input, using keymaps and the input method framework, while maintaining compatibility with the AWT listener model.

A Keymap lets an application bind key strokes to actions. In order to allow keymaps to be shared across multiple text components, they can use actions that extend TextAction. TextAction can determine which JTextComponent most recently has or had focus and therefore is the subject of the action (In the case that the ActionEvent sent to the action doesn't contain the target text component as its source).

The {@extLink imf_overview Input Method Framework} lets text components interact with input methods, separate software components that preprocess events to let users enter thousands of different characters using keyboards with far fewer keys. JTextComponent is an active client of the framework, so it implements the preferred user interface for interacting with input methods. As a consequence, some key events do not reach the text component because they are handled by an input method, and some text input reaches the text component as committed text within an InputMethodEvent instead of as a key event. The complete text input is the combination of the characters in keyTyped key events and committed text in input method events.

The AWT listener model lets applications attach event listeners to components in order to bind events to actions. Swing encourages the use of keymaps instead of listeners, but maintains compatibility with listeners by giving the listeners a chance to steal an event by consuming it.

Keyboard event and input method events are handled in the following stages, with each stage capable of consuming the event:

Stages of keyboard and input method event handling
Stage KeyEvent InputMethodEvent
1. input methods (generated here)
2. focus manager
3. registered key listeners registered input method listeners
4. input method handling in JTextComponent
5. keymap handling using the current keymap
6. keyboard handling in JComponent (e.g. accelerators, component navigation, etc.)

To maintain compatibility with applications that listen to key events but are not aware of input method events, the input method handling in stage 4 provides a compatibility mode for components that do not process input method events. For these components, the committed text is converted to keyTyped key events and processed in the key event pipeline starting at stage 3 instead of in the input method event pipeline.

By default the component will create a keymap (named DEFAULT_KEYMAP) that is shared by all JTextComponent instances as the default keymap. Typically a look-and-feel implementation will install a different keymap that resolves to the default keymap for those bindings not found in the different keymap. The minimal bindings include:

  • inserting content into the editor for the printable keys.
  • removing content with the backspace and del keys.
  • caret movement forward and backward
Model/View Split
The text components have a model-view split. A text component pulls together the objects used to represent the model, view, and controller. The text document model may be shared by other views which act as observers of the model (e.g. a document may be shared by multiple components).

The model is defined by the Document interface. This is intended to provide a flexible text storage mechanism that tracks change during edits and can be extended to more sophisticated models. The model interfaces are meant to capture the capabilities of expression given by SGML, a system used to express a wide variety of content. Each modification to the document causes notification of the details of the change to be sent to all observers in the form of a DocumentEvent which allows the views to stay up to date with the model. This event is sent to observers that have implemented the DocumentListener interface and registered interest with the model being observed.

Location Information
The capability of determining the location of text in the view is provided. There are two methods, modelToView and viewToModel for determining this information.
Undo/Redo support
Support for an edit history mechanism is provided to allow undo/redo operations. The text component does not itself provide the history buffer by default, but does provide the UndoableEdit records that can be used in conjunction with a history buffer to provide the undo/redo support. The support is provided by the Document model, which allows one to attach UndoableEditListener implementations.
Thread Safety
The swing text components provide some support of thread safe operations. Because of the high level of configurability of the text components, it is possible to circumvent the protection provided. The protection primarily comes from the model, so the documentation of AbstractDocument describes the assumptions of the protection provided. The methods that are safe to call asynchronously are marked with comments.
Newlines
For a discussion on how newlines are handled, see DefaultEditorKit.
Printing support
Several print methods are provided for basic document printing. If more advanced printing is needed, use the getPrintable method.

Warning: Serialized objects of this class will not be compatible with future Swing releases. The current serialization support is appropriate for short term storage or RMI between applications running the same version of Swing. As of 1.4, support for long term storage of all JavaBeans has been added to the java.beans package. Please see XMLEncoder.

Author: Timothy Prinzing, Igor Kushnirskiy (printing support)
See Also:
/** * <code>JTextComponent</code> is the base class for swing text * components. It tries to be compatible with the * <code>java.awt.TextComponent</code> class * where it can reasonably do so. Also provided are other services * for additional flexibility (beyond the pluggable UI and bean * support). * You can find information on how to use the functionality * this class provides in * <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/generaltext.html">General Rules for Using Text Components</a>, * a section in <em>The Java Tutorial.</em> * * <dl> * <dt><b>Caret Changes</b> * <dd> * The caret is a pluggable object in swing text components. * Notification of changes to the caret position and the selection * are sent to implementations of the <code>CaretListener</code> * interface that have been registered with the text component. * The UI will install a default caret unless a customized caret * has been set. <br> * By default the caret tracks all the document changes * performed on the Event Dispatching Thread and updates it's position * accordingly if an insertion occurs before or at the caret position * or a removal occurs before the caret position. <code>DefaultCaret</code> * tries to make itself visible which may lead to scrolling * of a text component within <code>JScrollPane</code>. The default caret * behavior can be changed by the {@link DefaultCaret#setUpdatePolicy} method. * <br> * <b>Note</b>: Non-editable text components also have a caret though * it may not be painted. * * <dt><b>Commands</b> * <dd> * Text components provide a number of commands that can be used * to manipulate the component. This is essentially the way that * the component expresses its capabilities. These are expressed * in terms of the swing <code>Action</code> interface, * using the <code>TextAction</code> implementation. * The set of commands supported by the text component can be * found with the {@link #getActions} method. These actions * can be bound to key events, fired from buttons, etc. * * <dt><b>Text Input</b> * <dd> * The text components support flexible and internationalized text input, using * keymaps and the input method framework, while maintaining compatibility with * the AWT listener model. * <p> * A {@link javax.swing.text.Keymap} lets an application bind key * strokes to actions. * In order to allow keymaps to be shared across multiple text components, they * can use actions that extend <code>TextAction</code>. * <code>TextAction</code> can determine which <code>JTextComponent</code> * most recently has or had focus and therefore is the subject of * the action (In the case that the <code>ActionEvent</code> * sent to the action doesn't contain the target text component as its source). * <p> * The {@extLink imf_overview Input Method Framework} * lets text components interact with input methods, separate software * components that preprocess events to let users enter thousands of * different characters using keyboards with far fewer keys. * <code>JTextComponent</code> is an <em>active client</em> of * the framework, so it implements the preferred user interface for interacting * with input methods. As a consequence, some key events do not reach the text * component because they are handled by an input method, and some text input * reaches the text component as committed text within an {@link * java.awt.event.InputMethodEvent} instead of as a key event. * The complete text input is the combination of the characters in * <code>keyTyped</code> key events and committed text in input method events. * <p> * The AWT listener model lets applications attach event listeners to * components in order to bind events to actions. Swing encourages the * use of keymaps instead of listeners, but maintains compatibility * with listeners by giving the listeners a chance to steal an event * by consuming it. * <p> * Keyboard event and input method events are handled in the following stages, * with each stage capable of consuming the event: * * <table class="striped"> * <caption>Stages of keyboard and input method event handling</caption> * <thead> * <tr> * <th scope="col">Stage * <th scope="col">KeyEvent * <th scope="col">InputMethodEvent * </thead> * <tbody> * <tr> * <th scope="row">1. * <td>input methods * <td>(generated here) * <tr> * <th scope="row">2. * <td>focus manager * <td> * </tr> * <tr> * <th scope="row">3. * <td>registered key listeners * <td>registered input method listeners * <tr> * <th scope="row">4. * <td> * <td>input method handling in JTextComponent * <tr> * <th scope="row">5. * <td colspan=2>keymap handling using the current keymap * <tr> * <th scope="row">6. * <td>keyboard handling in JComponent (e.g. accelerators, component * navigation, etc.) * <td> * </tbody> * </table> * <p> * To maintain compatibility with applications that listen to key * events but are not aware of input method events, the input * method handling in stage 4 provides a compatibility mode for * components that do not process input method events. For these * components, the committed text is converted to keyTyped key events * and processed in the key event pipeline starting at stage 3 * instead of in the input method event pipeline. * <p> * By default the component will create a keymap (named <b>DEFAULT_KEYMAP</b>) * that is shared by all JTextComponent instances as the default keymap. * Typically a look-and-feel implementation will install a different keymap * that resolves to the default keymap for those bindings not found in the * different keymap. The minimal bindings include: * <ul> * <li>inserting content into the editor for the * printable keys. * <li>removing content with the backspace and del * keys. * <li>caret movement forward and backward * </ul> * * <dt><b>Model/View Split</b> * <dd> * The text components have a model-view split. A text component pulls * together the objects used to represent the model, view, and controller. * The text document model may be shared by other views which act as observers * of the model (e.g. a document may be shared by multiple components). * * <p style="text-align:center"><img src="doc-files/editor.gif" alt="Diagram showing interaction between Controller, Document, events, and ViewFactory" * HEIGHT=358 WIDTH=587></p> * * <p> * The model is defined by the {@link Document} interface. * This is intended to provide a flexible text storage mechanism * that tracks change during edits and can be extended to more sophisticated * models. The model interfaces are meant to capture the capabilities of * expression given by SGML, a system used to express a wide variety of * content. * Each modification to the document causes notification of the * details of the change to be sent to all observers in the form of a * {@link DocumentEvent} which allows the views to stay up to date with the model. * This event is sent to observers that have implemented the * {@link DocumentListener} * interface and registered interest with the model being observed. * * <dt><b>Location Information</b> * <dd> * The capability of determining the location of text in * the view is provided. There are two methods, {@link #modelToView} * and {@link #viewToModel} for determining this information. * * <dt><b>Undo/Redo support</b> * <dd> * Support for an edit history mechanism is provided to allow * undo/redo operations. The text component does not itself * provide the history buffer by default, but does provide * the <code>UndoableEdit</code> records that can be used in conjunction * with a history buffer to provide the undo/redo support. * The support is provided by the Document model, which allows * one to attach UndoableEditListener implementations. * * <dt><b>Thread Safety</b> * <dd> * The swing text components provide some support of thread * safe operations. Because of the high level of configurability * of the text components, it is possible to circumvent the * protection provided. The protection primarily comes from * the model, so the documentation of <code>AbstractDocument</code> * describes the assumptions of the protection provided. * The methods that are safe to call asynchronously are marked * with comments. * * <dt><b>Newlines</b> * <dd> * For a discussion on how newlines are handled, see * <a href="DefaultEditorKit.html">DefaultEditorKit</a>. * * * <dt><b>Printing support</b> * <dd> * Several {@link #print print} methods are provided for basic * document printing. If more advanced printing is needed, use the * {@link #getPrintable} method. * </dl> * * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeans * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. * * @author Timothy Prinzing * @author Igor Kushnirskiy (printing support) * @see Document * @see DocumentEvent * @see DocumentListener * @see Caret * @see CaretEvent * @see CaretListener * @see TextUI * @see View * @see ViewFactory */
@JavaBean(defaultProperty = "UI") @SwingContainer(false) @SuppressWarnings("serial") // Same-version serialization only public abstract class JTextComponent extends JComponent implements Scrollable, Accessible {
Creates a new JTextComponent. Listeners for caret events are established, and the pluggable UI installed. The component is marked as editable. No layout manager is used, because layout is managed by the view subsystem of text. The document model is set to null.
/** * Creates a new <code>JTextComponent</code>. * Listeners for caret events are established, and the pluggable * UI installed. The component is marked as editable. No layout manager * is used, because layout is managed by the view subsystem of text. * The document model is set to <code>null</code>. */
public JTextComponent() { super(); // enable InputMethodEvent for on-the-spot pre-editing enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.INPUT_METHOD_EVENT_MASK); caretEvent = new MutableCaretEvent(this); addMouseListener(caretEvent); addFocusListener(caretEvent); setEditable(true); setDragEnabled(false); setLayout(null); // layout is managed by View hierarchy updateUI(); }
Fetches the user-interface factory for this text-oriented editor.
Returns:the factory
/** * Fetches the user-interface factory for this text-oriented editor. * * @return the factory */
public TextUI getUI() { return (TextUI)ui; }
Sets the user-interface factory for this text-oriented editor.
Params:
  • ui – the factory
/** * Sets the user-interface factory for this text-oriented editor. * * @param ui the factory */
public void setUI(TextUI ui) { super.setUI(ui); }
Reloads the pluggable UI. The key used to fetch the new interface is getUIClassID(). The type of the UI is TextUI. invalidate is called after setting the UI.
/** * Reloads the pluggable UI. The key used to fetch the * new interface is <code>getUIClassID()</code>. The type of * the UI is <code>TextUI</code>. <code>invalidate</code> * is called after setting the UI. */
public void updateUI() { setUI((TextUI)UIManager.getUI(this)); invalidate(); }
Adds a caret listener for notification of any changes to the caret.
Params:
  • listener – the listener to be added
See Also:
/** * Adds a caret listener for notification of any changes * to the caret. * * @param listener the listener to be added * @see javax.swing.event.CaretEvent */
public void addCaretListener(CaretListener listener) { listenerList.add(CaretListener.class, listener); }
Removes a caret listener.
Params:
  • listener – the listener to be removed
See Also:
/** * Removes a caret listener. * * @param listener the listener to be removed * @see javax.swing.event.CaretEvent */
public void removeCaretListener(CaretListener listener) { listenerList.remove(CaretListener.class, listener); }
Returns an array of all the caret listeners registered on this text component.
See Also:
Returns:all of this component's CaretListeners or an empty array if no caret listeners are currently registered
Since:1.4
/** * Returns an array of all the caret listeners * registered on this text component. * * @return all of this component's <code>CaretListener</code>s * or an empty * array if no caret listeners are currently registered * * @see #addCaretListener * @see #removeCaretListener * * @since 1.4 */
@BeanProperty(bound = false) public CaretListener[] getCaretListeners() { return listenerList.getListeners(CaretListener.class); }
Notifies all listeners that have registered interest for notification on this event type. The event instance is lazily created using the parameters passed into the fire method. The listener list is processed in a last-to-first manner.
Params:
  • e – the event
See Also:
/** * Notifies all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. The listener list is processed in a * last-to-first manner. * * @param e the event * @see EventListenerList */
protected void fireCaretUpdate(CaretEvent e) { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==CaretListener.class) { ((CaretListener)listeners[i+1]).caretUpdate(e); } } }
Associates the editor with a text document. The currently registered factory is used to build a view for the document, which gets displayed by the editor after revalidation. A PropertyChange event ("document") is propagated to each listener.
Params:
  • doc – the document to display/edit
See Also:
/** * Associates the editor with a text document. * The currently registered factory is used to build a view for * the document, which gets displayed by the editor after revalidation. * A PropertyChange event ("document") is propagated to each listener. * * @param doc the document to display/edit * @see #getDocument */
@BeanProperty(expert = true, description = "the text document model") public void setDocument(Document doc) { Document old = model; /* * acquire a read lock on the old model to prevent notification of * mutations while we disconnecting the old model. */ try { if (old instanceof AbstractDocument) { ((AbstractDocument)old).readLock(); } if (accessibleContext != null) { model.removeDocumentListener( ((AccessibleJTextComponent)accessibleContext)); } if (inputMethodRequestsHandler != null) { model.removeDocumentListener((DocumentListener)inputMethodRequestsHandler); } model = doc; // Set the document's run direction property to match the // component's ComponentOrientation property. Boolean runDir = getComponentOrientation().isLeftToRight() ? TextAttribute.RUN_DIRECTION_LTR : TextAttribute.RUN_DIRECTION_RTL; if (runDir != doc.getProperty(TextAttribute.RUN_DIRECTION)) { doc.putProperty(TextAttribute.RUN_DIRECTION, runDir ); } firePropertyChange("document", old, doc); } finally { if (old instanceof AbstractDocument) { ((AbstractDocument)old).readUnlock(); } } revalidate(); repaint(); if (accessibleContext != null) { model.addDocumentListener( ((AccessibleJTextComponent)accessibleContext)); } if (inputMethodRequestsHandler != null) { model.addDocumentListener((DocumentListener)inputMethodRequestsHandler); } }
Fetches the model associated with the editor. This is primarily for the UI to get at the minimal amount of state required to be a text editor. Subclasses will return the actual type of the model which will typically be something that extends Document.
Returns:the model
/** * Fetches the model associated with the editor. This is * primarily for the UI to get at the minimal amount of * state required to be a text editor. Subclasses will * return the actual type of the model which will typically * be something that extends Document. * * @return the model */
public Document getDocument() { return model; } // Override of Component.setComponentOrientation public void setComponentOrientation( ComponentOrientation o ) { // Set the document's run direction property to match the // ComponentOrientation property. Document doc = getDocument(); if( doc != null ) { Boolean runDir = o.isLeftToRight() ? TextAttribute.RUN_DIRECTION_LTR : TextAttribute.RUN_DIRECTION_RTL; doc.putProperty( TextAttribute.RUN_DIRECTION, runDir ); } super.setComponentOrientation( o ); }
Fetches the command list for the editor. This is the list of commands supported by the plugged-in UI augmented by the collection of commands that the editor itself supports. These are useful for binding to events, such as in a keymap.
Returns:the command list
/** * Fetches the command list for the editor. This is * the list of commands supported by the plugged-in UI * augmented by the collection of commands that the * editor itself supports. These are useful for binding * to events, such as in a keymap. * * @return the command list */
@BeanProperty(bound = false) public Action[] getActions() { return getUI().getEditorKit(this).getActions(); }
Sets margin space between the text component's border and its text. The text component's default Border object will use this value to create the proper margin. However, if a non-default border is set on the text component, it is that Border object's responsibility to create the appropriate margin space (else this property will effectively be ignored). This causes a redraw of the component. A PropertyChange event ("margin") is sent to all listeners.
Params:
  • m – the space between the border and the text
/** * Sets margin space between the text component's border * and its text. The text component's default <code>Border</code> * object will use this value to create the proper margin. * However, if a non-default border is set on the text component, * it is that <code>Border</code> object's responsibility to create the * appropriate margin space (else this property will effectively * be ignored). This causes a redraw of the component. * A PropertyChange event ("margin") is sent to all listeners. * * @param m the space between the border and the text */
@BeanProperty(description = "desired space between the border and text area") public void setMargin(Insets m) { Insets old = margin; margin = m; firePropertyChange("margin", old, m); invalidate(); }
Returns the margin between the text component's border and its text.
Returns:the margin
/** * Returns the margin between the text component's border and * its text. * * @return the margin */
public Insets getMargin() { return margin; }
Sets the NavigationFilter. NavigationFilter is used by DefaultCaret and the default cursor movement actions as a way to restrict the cursor movement.
Params:
  • filter – the filter
Since:1.4
/** * Sets the <code>NavigationFilter</code>. <code>NavigationFilter</code> * is used by <code>DefaultCaret</code> and the default cursor movement * actions as a way to restrict the cursor movement. * @param filter the filter * * @since 1.4 */
public void setNavigationFilter(NavigationFilter filter) { navigationFilter = filter; }
Returns the NavigationFilter. NavigationFilter is used by DefaultCaret and the default cursor movement actions as a way to restrict the cursor movement. A null return value implies the cursor movement and selection should not be restricted.
Since:1.4
Returns:the NavigationFilter
/** * Returns the <code>NavigationFilter</code>. <code>NavigationFilter</code> * is used by <code>DefaultCaret</code> and the default cursor movement * actions as a way to restrict the cursor movement. A null return value * implies the cursor movement and selection should not be restricted. * * @since 1.4 * @return the NavigationFilter */
public NavigationFilter getNavigationFilter() { return navigationFilter; }
Fetches the caret that allows text-oriented navigation over the view.
Returns:the caret
/** * Fetches the caret that allows text-oriented navigation over * the view. * * @return the caret */
@Transient public Caret getCaret() { return caret; }
Sets the caret to be used. By default this will be set by the UI that gets installed. This can be changed to a custom caret if desired. Setting the caret results in a PropertyChange event ("caret") being fired.
Params:
  • c – the caret
See Also:
/** * Sets the caret to be used. By default this will be set * by the UI that gets installed. This can be changed to * a custom caret if desired. Setting the caret results in a * PropertyChange event ("caret") being fired. * * @param c the caret * @see #getCaret */
@BeanProperty(expert = true, description = "the caret used to select/navigate") public void setCaret(Caret c) { if (caret != null) { caret.removeChangeListener(caretEvent); caret.deinstall(this); } Caret old = caret; caret = c; if (caret != null) { caret.install(this); caret.addChangeListener(caretEvent); } firePropertyChange("caret", old, caret); }
Fetches the object responsible for making highlights.
Returns:the highlighter
/** * Fetches the object responsible for making highlights. * * @return the highlighter */
public Highlighter getHighlighter() { return highlighter; }
Sets the highlighter to be used. By default this will be set by the UI that gets installed. This can be changed to a custom highlighter if desired. The highlighter can be set to null to disable it. A PropertyChange event ("highlighter") is fired when a new highlighter is installed.
Params:
  • h – the highlighter
See Also:
/** * Sets the highlighter to be used. By default this will be set * by the UI that gets installed. This can be changed to * a custom highlighter if desired. The highlighter can be set to * <code>null</code> to disable it. * A PropertyChange event ("highlighter") is fired * when a new highlighter is installed. * * @param h the highlighter * @see #getHighlighter */
@BeanProperty(expert = true, description = "object responsible for background highlights") public void setHighlighter(Highlighter h) { if (highlighter != null) { highlighter.deinstall(this); } Highlighter old = highlighter; highlighter = h; if (highlighter != null) { highlighter.install(this); } firePropertyChange("highlighter", old, h); }
Sets the keymap to use for binding events to actions. Setting to null effectively disables keyboard input. A PropertyChange event ("keymap") is fired when a new keymap is installed.
Params:
  • map – the keymap
See Also:
/** * Sets the keymap to use for binding events to * actions. Setting to <code>null</code> effectively disables * keyboard input. * A PropertyChange event ("keymap") is fired when a new keymap * is installed. * * @param map the keymap * @see #getKeymap */
@BeanProperty(description = "set of key event to action bindings to use") public void setKeymap(Keymap map) { Keymap old = keymap; keymap = map; firePropertyChange("keymap", old, keymap); updateInputMap(old, map); }
Turns on or off automatic drag handling. In order to enable automatic drag handling, this property should be set to true, and the component's TransferHandler needs to be non-null. The default value of the dragEnabled property is false.

The job of honoring this property, and recognizing a user drag gesture, lies with the look and feel implementation, and in particular, the component's TextUI. When automatic drag handling is enabled, most look and feels (including those that subclass BasicLookAndFeel) begin a drag and drop operation whenever the user presses the mouse button over a selection and then moves the mouse a few pixels. Setting this property to true can therefore have a subtle effect on how selections behave.

If a look and feel is used that ignores this property, you can still begin a drag and drop operation by calling exportAsDrag on the component's TransferHandler.

Params:
  • b – whether or not to enable automatic drag handling
Throws:
See Also:
Since:1.4
/** * Turns on or off automatic drag handling. In order to enable automatic * drag handling, this property should be set to {@code true}, and the * component's {@code TransferHandler} needs to be {@code non-null}. * The default value of the {@code dragEnabled} property is {@code false}. * <p> * The job of honoring this property, and recognizing a user drag gesture, * lies with the look and feel implementation, and in particular, the component's * {@code TextUI}. When automatic drag handling is enabled, most look and * feels (including those that subclass {@code BasicLookAndFeel}) begin a * drag and drop operation whenever the user presses the mouse button over * a selection and then moves the mouse a few pixels. Setting this property to * {@code true} can therefore have a subtle effect on how selections behave. * <p> * If a look and feel is used that ignores this property, you can still * begin a drag and drop operation by calling {@code exportAsDrag} on the * component's {@code TransferHandler}. * * @param b whether or not to enable automatic drag handling * @exception HeadlessException if * <code>b</code> is <code>true</code> and * <code>GraphicsEnvironment.isHeadless()</code> * returns <code>true</code> * @see java.awt.GraphicsEnvironment#isHeadless * @see #getDragEnabled * @see #setTransferHandler * @see TransferHandler * @since 1.4 */
@BeanProperty(bound = false, description = "determines whether automatic drag handling is enabled") public void setDragEnabled(boolean b) { checkDragEnabled(b); dragEnabled = b; } private static void checkDragEnabled(boolean b) { if (b && GraphicsEnvironment.isHeadless()) { throw new HeadlessException(); } }
Returns whether or not automatic drag handling is enabled.
See Also:
Returns:the value of the dragEnabled property
Since:1.4
/** * Returns whether or not automatic drag handling is enabled. * * @return the value of the {@code dragEnabled} property * @see #setDragEnabled * @since 1.4 */
public boolean getDragEnabled() { return dragEnabled; }
Sets the drop mode for this component. For backward compatibility, the default for this property is DropMode.USE_SELECTION. Usage of DropMode.INSERT is recommended, however, for an improved user experience. It offers similar behavior of dropping between text locations, but does so without affecting the actual text selection and caret location.

JTextComponents support the following drop modes:

  • DropMode.USE_SELECTION
  • DropMode.INSERT

The drop mode is only meaningful if this component has a TransferHandler that accepts drops.

Params:
  • dropMode – the drop mode to use
Throws:
See Also:
Since:1.6
/** * Sets the drop mode for this component. For backward compatibility, * the default for this property is <code>DropMode.USE_SELECTION</code>. * Usage of <code>DropMode.INSERT</code> is recommended, however, * for an improved user experience. It offers similar behavior of dropping * between text locations, but does so without affecting the actual text * selection and caret location. * <p> * <code>JTextComponents</code> support the following drop modes: * <ul> * <li><code>DropMode.USE_SELECTION</code></li> * <li><code>DropMode.INSERT</code></li> * </ul> * <p> * The drop mode is only meaningful if this component has a * <code>TransferHandler</code> that accepts drops. * * @param dropMode the drop mode to use * @throws IllegalArgumentException if the drop mode is unsupported * or <code>null</code> * @see #getDropMode * @see #getDropLocation * @see #setTransferHandler * @see javax.swing.TransferHandler * @since 1.6 */
public final void setDropMode(DropMode dropMode) { checkDropMode(dropMode); this.dropMode = dropMode; } private static void checkDropMode(DropMode dropMode) { if (dropMode != null) { switch (dropMode) { case USE_SELECTION: case INSERT: return; } } throw new IllegalArgumentException(dropMode + ": Unsupported drop mode for text"); }
Returns the drop mode for this component.
See Also:
Returns:the drop mode for this component
Since:1.6
/** * Returns the drop mode for this component. * * @return the drop mode for this component * @see #setDropMode * @since 1.6 */
public final DropMode getDropMode() { return dropMode; } static { SwingAccessor.setJTextComponentAccessor( new SwingAccessor.JTextComponentAccessor() { public TransferHandler.DropLocation dropLocationForPoint(JTextComponent textComp, Point p) { return textComp.dropLocationForPoint(p); } public Object setDropLocation(JTextComponent textComp, TransferHandler.DropLocation location, Object state, boolean forDrop) { return textComp.setDropLocation(location, state, forDrop); } }); }
Calculates a drop location in this component, representing where a drop at the given point should insert data.

Note: This method is meant to override JComponent.dropLocationForPoint(), which is package-private in javax.swing. TransferHandler will detect text components and call this method instead via reflection. It's name should therefore not be changed.

Params:
  • p – the point to calculate a drop location for
Returns:the drop location, or null
/** * Calculates a drop location in this component, representing where a * drop at the given point should insert data. * <p> * Note: This method is meant to override * <code>JComponent.dropLocationForPoint()</code>, which is package-private * in javax.swing. <code>TransferHandler</code> will detect text components * and call this method instead via reflection. It's name should therefore * not be changed. * * @param p the point to calculate a drop location for * @return the drop location, or <code>null</code> */
@SuppressWarnings("deprecation") DropLocation dropLocationForPoint(Point p) { Position.Bias[] bias = new Position.Bias[1]; int index = getUI().viewToModel(this, p, bias); // viewToModel currently returns null for some HTML content // when the point is within the component's top inset if (bias[0] == null) { bias[0] = Position.Bias.Forward; } return new DropLocation(p, index, bias[0]); }
Called to set or clear the drop location during a DnD operation. In some cases, the component may need to use it's internal selection temporarily to indicate the drop location. To help facilitate this, this method returns and accepts as a parameter a state object. This state object can be used to store, and later restore, the selection state. Whatever this method returns will be passed back to it in future calls, as the state parameter. If it wants the DnD system to continue storing the same state, it must pass it back every time. Here's how this is used:

Let's say that on the first call to this method the component decides to save some state (because it is about to use the selection to show a drop index). It can return a state object to the caller encapsulating any saved selection state. On a second call, let's say the drop location is being changed to something else. The component doesn't need to restore anything yet, so it simply passes back the same state object to have the DnD system continue storing it. Finally, let's say this method is messaged with null. This means DnD is finished with this component for now, meaning it should restore state. At this point, it can use the state parameter to restore said state, and of course return null since there's no longer anything to store.

Note: This method is meant to override JComponent.setDropLocation(), which is package-private in javax.swing. TransferHandler will detect text components and call this method instead via reflection. It's name should therefore not be changed.

Params:
  • location – the drop location (as calculated by dropLocationForPoint) or null if there's no longer a valid drop location
  • state – the state object saved earlier for this component, or null
  • forDrop – whether or not the method is being called because an actual drop occurred
Returns:any saved state for this component, or null if none
/** * Called to set or clear the drop location during a DnD operation. * In some cases, the component may need to use it's internal selection * temporarily to indicate the drop location. To help facilitate this, * this method returns and accepts as a parameter a state object. * This state object can be used to store, and later restore, the selection * state. Whatever this method returns will be passed back to it in * future calls, as the state parameter. If it wants the DnD system to * continue storing the same state, it must pass it back every time. * Here's how this is used: * <p> * Let's say that on the first call to this method the component decides * to save some state (because it is about to use the selection to show * a drop index). It can return a state object to the caller encapsulating * any saved selection state. On a second call, let's say the drop location * is being changed to something else. The component doesn't need to * restore anything yet, so it simply passes back the same state object * to have the DnD system continue storing it. Finally, let's say this * method is messaged with <code>null</code>. This means DnD * is finished with this component for now, meaning it should restore * state. At this point, it can use the state parameter to restore * said state, and of course return <code>null</code> since there's * no longer anything to store. * <p> * Note: This method is meant to override * <code>JComponent.setDropLocation()</code>, which is package-private * in javax.swing. <code>TransferHandler</code> will detect text components * and call this method instead via reflection. It's name should therefore * not be changed. * * @param location the drop location (as calculated by * <code>dropLocationForPoint</code>) or <code>null</code> * if there's no longer a valid drop location * @param state the state object saved earlier for this component, * or <code>null</code> * @param forDrop whether or not the method is being called because an * actual drop occurred * @return any saved state for this component, or <code>null</code> if none */
Object setDropLocation(TransferHandler.DropLocation location, Object state, boolean forDrop) { Object retVal = null; DropLocation textLocation = (DropLocation)location; if (dropMode == DropMode.USE_SELECTION) { if (textLocation == null) { if (state != null) { /* * This object represents the state saved earlier. * If the caret is a DefaultCaret it will be * an Object array containing, in order: * - the saved caret mark (Integer) * - the saved caret dot (Integer) * - the saved caret visibility (Boolean) * - the saved mark bias (Position.Bias) * - the saved dot bias (Position.Bias) * If the caret is not a DefaultCaret it will * be similar, but will not contain the dot * or mark bias. */ Object[] vals = (Object[])state; if (!forDrop) { if (caret instanceof DefaultCaret) { ((DefaultCaret)caret).setDot(((Integer)vals[0]).intValue(), (Position.Bias)vals[3]); ((DefaultCaret)caret).moveDot(((Integer)vals[1]).intValue(), (Position.Bias)vals[4]); } else { caret.setDot(((Integer)vals[0]).intValue()); caret.moveDot(((Integer)vals[1]).intValue()); } } caret.setVisible(((Boolean)vals[2]).booleanValue()); } } else { if (dropLocation == null) { boolean visible; if (caret instanceof DefaultCaret) { DefaultCaret dc = (DefaultCaret)caret; visible = dc.isActive(); retVal = new Object[] {Integer.valueOf(dc.getMark()), Integer.valueOf(dc.getDot()), Boolean.valueOf(visible), dc.getMarkBias(), dc.getDotBias()}; } else { visible = caret.isVisible(); retVal = new Object[] {Integer.valueOf(caret.getMark()), Integer.valueOf(caret.getDot()), Boolean.valueOf(visible)}; } caret.setVisible(true); } else { retVal = state; } if (caret instanceof DefaultCaret) { ((DefaultCaret)caret).setDot(textLocation.getIndex(), textLocation.getBias()); } else { caret.setDot(textLocation.getIndex()); } } } else { if (textLocation == null) { if (state != null) { caret.setVisible(((Boolean)state).booleanValue()); } } else { if (dropLocation == null) { boolean visible = caret instanceof DefaultCaret ? ((DefaultCaret)caret).isActive() : caret.isVisible(); retVal = Boolean.valueOf(visible); caret.setVisible(false); } else { retVal = state; } } } DropLocation old = dropLocation; dropLocation = textLocation; firePropertyChange("dropLocation", old, dropLocation); return retVal; }
Returns the location that this component should visually indicate as the drop location during a DnD operation over the component, or null if no location is to currently be shown.

This method is not meant for querying the drop location from a TransferHandler, as the drop location is only set after the TransferHandler's canImport has returned and has allowed for the location to be shown.

When this property changes, a property change event with name "dropLocation" is fired by the component.

See Also:
Returns:the drop location
Since:1.6
/** * Returns the location that this component should visually indicate * as the drop location during a DnD operation over the component, * or {@code null} if no location is to currently be shown. * <p> * This method is not meant for querying the drop location * from a {@code TransferHandler}, as the drop location is only * set after the {@code TransferHandler}'s <code>canImport</code> * has returned and has allowed for the location to be shown. * <p> * When this property changes, a property change event with * name "dropLocation" is fired by the component. * * @return the drop location * @see #setDropMode * @see TransferHandler#canImport(TransferHandler.TransferSupport) * @since 1.6 */
@BeanProperty(bound = false) public final DropLocation getDropLocation() { return dropLocation; }
Updates the InputMaps in response to a Keymap change.
Params:
  • oldKm – the old Keymap
  • newKm – the new Keymap
/** * Updates the <code>InputMap</code>s in response to a * <code>Keymap</code> change. * @param oldKm the old <code>Keymap</code> * @param newKm the new <code>Keymap</code> */
void updateInputMap(Keymap oldKm, Keymap newKm) { // Locate the current KeymapWrapper. InputMap km = getInputMap(JComponent.WHEN_FOCUSED); InputMap last = km; while (km != null && !(km instanceof KeymapWrapper)) { last = km; km = km.getParent(); } if (km != null) { // Found it, tweak the InputMap that points to it, as well // as anything it points to. if (newKm == null) { if (last != km) { last.setParent(km.getParent()); } else { last.setParent(null); } } else { InputMap newKM = new KeymapWrapper(newKm); last.setParent(newKM); if (last != km) { newKM.setParent(km.getParent()); } } } else if (newKm != null) { km = getInputMap(JComponent.WHEN_FOCUSED); if (km != null) { // Couldn't find it. // Set the parent of WHEN_FOCUSED InputMap to be the new one. InputMap newKM = new KeymapWrapper(newKm); newKM.setParent(km.getParent()); km.setParent(newKM); } } // Do the same thing with the ActionMap ActionMap am = getActionMap(); ActionMap lastAM = am; while (am != null && !(am instanceof KeymapActionMap)) { lastAM = am; am = am.getParent(); } if (am != null) { // Found it, tweak the Actionap that points to it, as well // as anything it points to. if (newKm == null) { if (lastAM != am) { lastAM.setParent(am.getParent()); } else { lastAM.setParent(null); } } else { ActionMap newAM = new KeymapActionMap(newKm); lastAM.setParent(newAM); if (lastAM != am) { newAM.setParent(am.getParent()); } } } else if (newKm != null) { am = getActionMap(); if (am != null) { // Couldn't find it. // Set the parent of ActionMap to be the new one. ActionMap newAM = new KeymapActionMap(newKm); newAM.setParent(am.getParent()); am.setParent(newAM); } } }
Fetches the keymap currently active in this text component.
Returns:the keymap
/** * Fetches the keymap currently active in this text * component. * * @return the keymap */
public Keymap getKeymap() { return keymap; }
Adds a new keymap into the keymap hierarchy. Keymap bindings resolve from bottom up so an attribute specified in a child will override an attribute specified in the parent.
Params:
  • nm – the name of the keymap (must be unique within the collection of named keymaps in the document); the name may be null if the keymap is unnamed, but the caller is responsible for managing the reference returned as an unnamed keymap can't be fetched by name
  • parent – the parent keymap; this may be null if unspecified bindings need not be resolved in some other keymap
Returns:the keymap
/** * Adds a new keymap into the keymap hierarchy. Keymap bindings * resolve from bottom up so an attribute specified in a child * will override an attribute specified in the parent. * * @param nm the name of the keymap (must be unique within the * collection of named keymaps in the document); the name may * be <code>null</code> if the keymap is unnamed, * but the caller is responsible for managing the reference * returned as an unnamed keymap can't * be fetched by name * @param parent the parent keymap; this may be <code>null</code> if * unspecified bindings need not be resolved in some other keymap * @return the keymap */
public static Keymap addKeymap(String nm, Keymap parent) { Keymap map = new DefaultKeymap(nm, parent); if (nm != null) { // add a named keymap, a class of bindings getKeymapTable().put(nm, map); } return map; }
Removes a named keymap previously added to the document. Keymaps with null names may not be removed in this way.
Params:
  • nm – the name of the keymap to remove
Returns:the keymap that was removed
/** * Removes a named keymap previously added to the document. Keymaps * with <code>null</code> names may not be removed in this way. * * @param nm the name of the keymap to remove * @return the keymap that was removed */
public static Keymap removeKeymap(String nm) { return getKeymapTable().remove(nm); }
Fetches a named keymap previously added to the document. This does not work with null-named keymaps.
Params:
  • nm – the name of the keymap
Returns:the keymap
/** * Fetches a named keymap previously added to the document. * This does not work with <code>null</code>-named keymaps. * * @param nm the name of the keymap * @return the keymap */
public static Keymap getKeymap(String nm) { return getKeymapTable().get(nm); } private static HashMap<String,Keymap> getKeymapTable() { synchronized (KEYMAP_TABLE) { AppContext appContext = AppContext.getAppContext(); @SuppressWarnings("unchecked") HashMap<String,Keymap> keymapTable = (HashMap<String,Keymap>)appContext.get(KEYMAP_TABLE); if (keymapTable == null) { keymapTable = new HashMap<String,Keymap>(17); appContext.put(KEYMAP_TABLE, keymapTable); //initialize default keymap Keymap binding = addKeymap(DEFAULT_KEYMAP, null); binding.setDefaultAction(new DefaultEditorKit.DefaultKeyTypedAction()); } return keymapTable; } }
Binding record for creating key bindings.

Warning: Serialized objects of this class will not be compatible with future Swing releases. The current serialization support is appropriate for short term storage or RMI between applications running the same version of Swing. As of 1.4, support for long term storage of all JavaBeans has been added to the java.beans package. Please see XMLEncoder.

/** * Binding record for creating key bindings. * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeans * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. */
@SuppressWarnings("serial") // Same-version serialization only public static class KeyBinding {
The key.
/** * The key. */
public KeyStroke key;
The name of the action for the key.
/** * The name of the action for the key. */
public String actionName;
Creates a new key binding.
Params:
  • key – the key
  • actionName – the name of the action for the key
/** * Creates a new key binding. * * @param key the key * @param actionName the name of the action for the key */
public KeyBinding(KeyStroke key, String actionName) { this.key = key; this.actionName = actionName; } }

Loads a keymap with a bunch of bindings. This can be used to take a static table of definitions and load them into some keymap. The following example illustrates an example of binding some keys to the cut, copy, and paste actions associated with a JTextComponent. A code fragment to accomplish this might look as follows:


  static final JTextComponent.KeyBinding[] defaultBindings = {
    new JTextComponent.KeyBinding(
      KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK),
      DefaultEditorKit.copyAction),
    new JTextComponent.KeyBinding(
      KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK),
      DefaultEditorKit.pasteAction),
    new JTextComponent.KeyBinding(
      KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK),
      DefaultEditorKit.cutAction),
  };
  JTextComponent c = new JTextPane();
  Keymap k = c.getKeymap();
  JTextComponent.loadKeymap(k, defaultBindings, c.getActions());
The sets of bindings and actions may be empty but must be non-null.
Params:
  • map – the keymap
  • bindings – the bindings
  • actions – the set of actions
/** * <p> * Loads a keymap with a bunch of * bindings. This can be used to take a static table of * definitions and load them into some keymap. The following * example illustrates an example of binding some keys to * the cut, copy, and paste actions associated with a * JTextComponent. A code fragment to accomplish * this might look as follows: * <pre><code> * * static final JTextComponent.KeyBinding[] defaultBindings = { * new JTextComponent.KeyBinding( * KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK), * DefaultEditorKit.copyAction), * new JTextComponent.KeyBinding( * KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK), * DefaultEditorKit.pasteAction), * new JTextComponent.KeyBinding( * KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK), * DefaultEditorKit.cutAction), * }; * * JTextComponent c = new JTextPane(); * Keymap k = c.getKeymap(); * JTextComponent.loadKeymap(k, defaultBindings, c.getActions()); * * </code></pre> * The sets of bindings and actions may be empty but must be * non-<code>null</code>. * * @param map the keymap * @param bindings the bindings * @param actions the set of actions */
public static void loadKeymap(Keymap map, KeyBinding[] bindings, Action[] actions) { Hashtable<String, Action> h = new Hashtable<String, Action>(); for (Action a : actions) { String value = (String)a.getValue(Action.NAME); h.put((value!=null ? value:""), a); } for (KeyBinding binding : bindings) { Action a = h.get(binding.actionName); if (a != null) { map.addActionForKeyStroke(binding.key, a); } } }
Fetches the current color used to render the caret.
Returns:the color
/** * Fetches the current color used to render the * caret. * * @return the color */
public Color getCaretColor() { return caretColor; }
Sets the current color used to render the caret. Setting to null effectively restores the default color. Setting the color results in a PropertyChange event ("caretColor") being fired.
Params:
  • c – the color
See Also:
/** * Sets the current color used to render the caret. * Setting to <code>null</code> effectively restores the default color. * Setting the color results in a PropertyChange event ("caretColor") * being fired. * * @param c the color * @see #getCaretColor */
@BeanProperty(preferred = true, description = "the color used to render the caret") public void setCaretColor(Color c) { Color old = caretColor; caretColor = c; firePropertyChange("caretColor", old, caretColor); }
Fetches the current color used to render the selection.
Returns:the color
/** * Fetches the current color used to render the * selection. * * @return the color */
public Color getSelectionColor() { return selectionColor; }
Sets the current color used to render the selection. Setting the color to null is the same as setting Color.white. Setting the color results in a PropertyChange event ("selectionColor").
Params:
  • c – the color
See Also:
/** * Sets the current color used to render the selection. * Setting the color to <code>null</code> is the same as setting * <code>Color.white</code>. Setting the color results in a * PropertyChange event ("selectionColor"). * * @param c the color * @see #getSelectionColor */
@BeanProperty(preferred = true, description = "color used to render selection background") public void setSelectionColor(Color c) { Color old = selectionColor; selectionColor = c; firePropertyChange("selectionColor", old, selectionColor); }
Fetches the current color used to render the selected text.
Returns:the color
/** * Fetches the current color used to render the * selected text. * * @return the color */
public Color getSelectedTextColor() { return selectedTextColor; }
Sets the current color used to render the selected text. Setting the color to null is the same as Color.black. Setting the color results in a PropertyChange event ("selectedTextColor") being fired.
Params:
  • c – the color
See Also:
/** * Sets the current color used to render the selected text. * Setting the color to <code>null</code> is the same as * <code>Color.black</code>. Setting the color results in a * PropertyChange event ("selectedTextColor") being fired. * * @param c the color * @see #getSelectedTextColor */
@BeanProperty(preferred = true, description = "color used to render selected text") public void setSelectedTextColor(Color c) { Color old = selectedTextColor; selectedTextColor = c; firePropertyChange("selectedTextColor", old, selectedTextColor); }
Fetches the current color used to render the disabled text.
Returns:the color
/** * Fetches the current color used to render the * disabled text. * * @return the color */
public Color getDisabledTextColor() { return disabledTextColor; }
Sets the current color used to render the disabled text. Setting the color fires off a PropertyChange event ("disabledTextColor").
Params:
  • c – the color
See Also:
/** * Sets the current color used to render the * disabled text. Setting the color fires off a * PropertyChange event ("disabledTextColor"). * * @param c the color * @see #getDisabledTextColor */
@BeanProperty(preferred = true, description = "color used to render disabled text") public void setDisabledTextColor(Color c) { Color old = disabledTextColor; disabledTextColor = c; firePropertyChange("disabledTextColor", old, disabledTextColor); }
Replaces the currently selected content with new content represented by the given string. If there is no selection this amounts to an insert of the given text. If there is no replacement text this amounts to a removal of the current selection.

This is the method that is used by the default implementation of the action for inserting content that gets bound to the keymap actions.

Params:
  • content – the content to replace the selection with
/** * Replaces the currently selected content with new content * represented by the given string. If there is no selection * this amounts to an insert of the given text. If there * is no replacement text this amounts to a removal of the * current selection. * <p> * This is the method that is used by the default implementation * of the action for inserting content that gets bound to the * keymap actions. * * @param content the content to replace the selection with */
public void replaceSelection(String content) { Document doc = getDocument(); if (doc != null) { try { boolean composedTextSaved = saveComposedText(caret.getDot()); int p0 = Math.min(caret.getDot(), caret.getMark()); int p1 = Math.max(caret.getDot(), caret.getMark()); if (doc instanceof AbstractDocument) { ((AbstractDocument)doc).replace(p0, p1 - p0, content,null); } else { if (p0 != p1) { doc.remove(p0, p1 - p0); } if (content != null && content.length() > 0) { doc.insertString(p0, content, null); } } if (composedTextSaved) { restoreComposedText(); } } catch (BadLocationException e) { UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this); } } }
Fetches a portion of the text represented by the component. Returns an empty string if length is 0.
Params:
  • offs – the offset ≥ 0
  • len – the length ≥ 0
Throws:
Returns:the text
/** * Fetches a portion of the text represented by the * component. Returns an empty string if length is 0. * * @param offs the offset &ge; 0 * @param len the length &ge; 0 * @return the text * @exception BadLocationException if the offset or length are invalid */
public String getText(int offs, int len) throws BadLocationException { return getDocument().getText(offs, len); }
Converts the given location in the model to a place in the view coordinate system. The component must have a positive size for this translation to be computed (i.e. layout cannot be computed until the component has been sized). The component does not have to be visible or painted.
Params:
  • pos – the position ≥ 0
Throws:
  • BadLocationException – if the given position does not represent a valid location in the associated document
See Also:
Returns:the coordinates as a rectangle, with (r.x, r.y) as the location in the coordinate system, or null if the component does not yet have a positive size.
Deprecated:replaced by modelToView2D(int)
/** * Converts the given location in the model to a place in * the view coordinate system. * The component must have a positive size for * this translation to be computed (i.e. layout cannot * be computed until the component has been sized). The * component does not have to be visible or painted. * * @param pos the position &ge; 0 * @return the coordinates as a rectangle, with (r.x, r.y) as the location * in the coordinate system, or null if the component does * not yet have a positive size. * @exception BadLocationException if the given position does not * represent a valid location in the associated document * @see TextUI#modelToView * * @deprecated replaced by * {@link #modelToView2D(int)} */
@Deprecated(since = "9") public Rectangle modelToView(int pos) throws BadLocationException { return getUI().modelToView(this, pos); }
Converts the given location in the model to a place in the view coordinate system. The component must have a positive size for this translation to be computed (i.e. layout cannot be computed until the component has been sized). The component does not have to be visible or painted.
Params:
  • pos – the position >= 0
Throws:
  • BadLocationException – if the given position does not represent a valid location in the associated document
See Also:
Returns:the coordinates as a rectangle, with (r.x, r.y) as the location in the coordinate system, or null if the component does not yet have a positive size.
Since:9
/** * Converts the given location in the model to a place in * the view coordinate system. * The component must have a positive size for * this translation to be computed (i.e. layout cannot * be computed until the component has been sized). The * component does not have to be visible or painted. * * @param pos the position {@code >= 0} * @return the coordinates as a rectangle, with (r.x, r.y) as the location * in the coordinate system, or null if the component does * not yet have a positive size. * @exception BadLocationException if the given position does not * represent a valid location in the associated document * @see TextUI#modelToView2D * * @since 9 */
public Rectangle2D modelToView2D(int pos) throws BadLocationException { return getUI().modelToView2D(this, pos, Position.Bias.Forward); }
Converts the given place in the view coordinate system to the nearest representative location in the model. The component must have a positive size for this translation to be computed (i.e. layout cannot be computed until the component has been sized). The component does not have to be visible or painted.
Params:
  • pt – the location in the view to translate
See Also:
Returns:the offset ≥ 0 from the start of the document, or -1 if the component does not yet have a positive size.
Deprecated:replaced by viewToModel2D(Point2D)
/** * Converts the given place in the view coordinate system * to the nearest representative location in the model. * The component must have a positive size for * this translation to be computed (i.e. layout cannot * be computed until the component has been sized). The * component does not have to be visible or painted. * * @param pt the location in the view to translate * @return the offset &ge; 0 from the start of the document, * or -1 if the component does not yet have a positive * size. * @see TextUI#viewToModel * * @deprecated replaced by * {@link #viewToModel2D(Point2D)} */
@Deprecated(since = "9") public int viewToModel(Point pt) { return getUI().viewToModel(this, pt); }
Converts the given place in the view coordinate system to the nearest representative location in the model. The component must have a positive size for this translation to be computed (i.e. layout cannot be computed until the component has been sized). The component does not have to be visible or painted.
Params:
  • pt – the location in the view to translate
See Also:
Returns:the offset >= 0 from the start of the document, or -1 if the component does not yet have a positive size.
Since:9
/** * Converts the given place in the view coordinate system * to the nearest representative location in the model. * The component must have a positive size for * this translation to be computed (i.e. layout cannot * be computed until the component has been sized). The * component does not have to be visible or painted. * * @param pt the location in the view to translate * @return the offset {@code >= 0} from the start of the document, * or {@code -1} if the component does not yet have a positive * size. * @see TextUI#viewToModel2D * * @since 9 */
public int viewToModel2D(Point2D pt) { return getUI().viewToModel2D(this, pt, new Position.Bias[1]); }
Transfers the currently selected range in the associated text model to the system clipboard, removing the contents from the model. The current selection is reset. Does nothing for null selections.
See Also:
  • getSystemClipboard.getSystemClipboard
  • Clipboard
/** * Transfers the currently selected range in the associated * text model to the system clipboard, removing the contents * from the model. The current selection is reset. Does nothing * for <code>null</code> selections. * * @see java.awt.Toolkit#getSystemClipboard * @see java.awt.datatransfer.Clipboard */
public void cut() { if (isEditable() && isEnabled()) { invokeAction("cut", TransferHandler.getCutAction()); } }
Transfers the currently selected range in the associated text model to the system clipboard, leaving the contents in the text model. The current selection remains intact. Does nothing for null selections.
See Also:
  • getSystemClipboard.getSystemClipboard
  • Clipboard
/** * Transfers the currently selected range in the associated * text model to the system clipboard, leaving the contents * in the text model. The current selection remains intact. * Does nothing for <code>null</code> selections. * * @see java.awt.Toolkit#getSystemClipboard * @see java.awt.datatransfer.Clipboard */
public void copy() { invokeAction("copy", TransferHandler.getCopyAction()); }
Transfers the contents of the system clipboard into the associated text model. If there is a selection in the associated view, it is replaced with the contents of the clipboard. If there is no selection, the clipboard contents are inserted in front of the current insert position in the associated view. If the clipboard is empty, does nothing.
See Also:
/** * Transfers the contents of the system clipboard into the * associated text model. If there is a selection in the * associated view, it is replaced with the contents of the * clipboard. If there is no selection, the clipboard contents * are inserted in front of the current insert position in * the associated view. If the clipboard is empty, does nothing. * * @see #replaceSelection * @see java.awt.Toolkit#getSystemClipboard * @see java.awt.datatransfer.Clipboard */
public void paste() { if (isEditable() && isEnabled()) { invokeAction("paste", TransferHandler.getPasteAction()); } }
This is a convenience method that is only useful for cut, copy and paste. If an Action with the name name does not exist in the ActionMap, this will attempt to install a TransferHandler and then use altAction.
/** * This is a convenience method that is only useful for * <code>cut</code>, <code>copy</code> and <code>paste</code>. If * an <code>Action</code> with the name <code>name</code> does not * exist in the <code>ActionMap</code>, this will attempt to install a * <code>TransferHandler</code> and then use <code>altAction</code>. */
private void invokeAction(String name, Action altAction) { ActionMap map = getActionMap(); Action action = null; if (map != null) { action = map.get(name); } if (action == null) { installDefaultTransferHandlerIfNecessary(); action = altAction; } action.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, (String)action. getValue(Action.NAME), EventQueue.getMostRecentEventTime(), getCurrentEventModifiers())); }
If the current TransferHandler is null, this will install a new one.
/** * If the current <code>TransferHandler</code> is null, this will * install a new one. */
private void installDefaultTransferHandlerIfNecessary() { if (getTransferHandler() == null) { if (defaultTransferHandler == null) { defaultTransferHandler = new DefaultTransferHandler(); } setTransferHandler(defaultTransferHandler); } }
Moves the caret to a new position, leaving behind a mark defined by the last time setCaretPosition was called. This forms a selection. If the document is null, does nothing. The position must be between 0 and the length of the component's text or else an exception is thrown.
Params:
  • pos – the position
Throws:
  • IllegalArgumentException – if the value supplied for position is less than zero or greater than the component's text length
See Also:
/** * Moves the caret to a new position, leaving behind a mark * defined by the last time <code>setCaretPosition</code> was * called. This forms a selection. * If the document is <code>null</code>, does nothing. The position * must be between 0 and the length of the component's text or else * an exception is thrown. * * @param pos the position * @exception IllegalArgumentException if the value supplied * for <code>position</code> is less than zero or greater * than the component's text length * @see #setCaretPosition */
public void moveCaretPosition(int pos) { Document doc = getDocument(); if (doc != null) { if (pos > doc.getLength() || pos < 0) { throw new IllegalArgumentException("bad position: " + pos); } caret.moveDot(pos); } }
The bound property name for the focus accelerator.
/** * The bound property name for the focus accelerator. */
public static final String FOCUS_ACCELERATOR_KEY = "focusAcceleratorKey";
Sets the key accelerator that will cause the receiving text component to get the focus. The accelerator will be the key combination of the platform-specific modifier key and the character given (converted to upper case). For example, the ALT key is used as a modifier on Windows and the CTRL+ALT combination is used on Mac. By default, there is no focus accelerator key. Any previous key accelerator setting will be superseded. A '\0' key setting will be registered, and has the effect of turning off the focus accelerator. When the new key is set, a PropertyChange event (FOCUS_ACCELERATOR_KEY) will be fired.
Params:
  • aKey – the key
See Also:
/** * Sets the key accelerator that will cause the receiving text * component to get the focus. The accelerator will be the * key combination of the platform-specific modifier key and * the character given (converted to upper case). For example, * the ALT key is used as a modifier on Windows and the CTRL+ALT * combination is used on Mac. By default, there is no focus * accelerator key. Any previous key accelerator setting will be * superseded. A '\0' key setting will be registered, and has the * effect of turning off the focus accelerator. When the new key * is set, a PropertyChange event (FOCUS_ACCELERATOR_KEY) will be fired. * * @param aKey the key * @see #getFocusAccelerator */
@BeanProperty(description = "accelerator character used to grab focus") public void setFocusAccelerator(char aKey) { aKey = Character.toUpperCase(aKey); char old = focusAccelerator; focusAccelerator = aKey; // Fix for 4341002: value of FOCUS_ACCELERATOR_KEY is wrong. // So we fire both FOCUS_ACCELERATOR_KEY, for compatibility, // and the correct event here. firePropertyChange(FOCUS_ACCELERATOR_KEY, old, focusAccelerator); firePropertyChange("focusAccelerator", old, focusAccelerator); }
Returns the key accelerator that will cause the receiving text component to get the focus. Return '\0' if no focus accelerator has been set.
Returns:the key
/** * Returns the key accelerator that will cause the receiving * text component to get the focus. Return '\0' if no focus * accelerator has been set. * * @return the key */
public char getFocusAccelerator() { return focusAccelerator; }
Initializes from a stream. This creates a model of the type appropriate for the component and initializes the model from the stream. By default this will load the model as plain text. Previous contents of the model are discarded.
Params:
  • in – the stream to read from
  • desc – an object describing the stream; this might be a string, a File, a URL, etc. Some kinds of documents (such as html for example) might be able to make use of this information; if non-null, it is added as a property of the document
Throws:
  • IOException – as thrown by the stream being used to initialize
See Also:
/** * Initializes from a stream. This creates a * model of the type appropriate for the component * and initializes the model from the stream. * By default this will load the model as plain * text. Previous contents of the model are discarded. * * @param in the stream to read from * @param desc an object describing the stream; this * might be a string, a File, a URL, etc. Some kinds * of documents (such as html for example) might be * able to make use of this information; if non-<code>null</code>, * it is added as a property of the document * @exception IOException as thrown by the stream being * used to initialize * @see EditorKit#createDefaultDocument * @see #setDocument * @see PlainDocument */
public void read(Reader in, Object desc) throws IOException { EditorKit kit = getUI().getEditorKit(this); Document doc = kit.createDefaultDocument(); if (desc != null) { doc.putProperty(Document.StreamDescriptionProperty, desc); } try { kit.read(in, doc, 0); setDocument(doc); } catch (BadLocationException e) { throw new IOException(e.getMessage()); } }
Stores the contents of the model into the given stream. By default this will store the model as plain text.
Params:
  • out – the output stream
Throws:
/** * Stores the contents of the model into the given * stream. By default this will store the model as plain * text. * * @param out the output stream * @exception IOException on any I/O error */
public void write(Writer out) throws IOException { Document doc = getDocument(); try { getUI().getEditorKit(this).write(out, doc, 0, doc.getLength()); } catch (BadLocationException e) { throw new IOException(e.getMessage()); } } public void removeNotify() { super.removeNotify(); if (getFocusedComponent() == this) { AppContext.getAppContext().remove(FOCUSED_COMPONENT); } } // --- java.awt.TextComponent methods ------------------------
Sets the position of the text insertion caret for the TextComponent. Note that the caret tracks change, so this may move if the underlying text of the component is changed. If the document is null, does nothing. The position must be between 0 and the length of the component's text or else an exception is thrown.
Params:
  • position – the position
Throws:
  • IllegalArgumentException – if the value supplied for position is less than zero or greater than the component's text length
/** * Sets the position of the text insertion caret for the * <code>TextComponent</code>. Note that the caret tracks change, * so this may move if the underlying text of the component is changed. * If the document is <code>null</code>, does nothing. The position * must be between 0 and the length of the component's text or else * an exception is thrown. * * @param position the position * @exception IllegalArgumentException if the value supplied * for <code>position</code> is less than zero or greater * than the component's text length */
@BeanProperty(bound = false, description = "the caret position") public void setCaretPosition(int position) { Document doc = getDocument(); if (doc != null) { if (position > doc.getLength() || position < 0) { throw new IllegalArgumentException("bad position: " + position); } caret.setDot(position); } }
Returns the position of the text insertion caret for the text component.
Returns:the position of the text insertion caret for the text component ≥ 0
/** * Returns the position of the text insertion caret for the * text component. * * @return the position of the text insertion caret for the * text component &ge; 0 */
@Transient public int getCaretPosition() { return caret.getDot(); }
Sets the text of this TextComponent to the specified text. If the text is null or empty, has the effect of simply deleting the old text. When text has been inserted, the resulting caret location is determined by the implementation of the caret class.

Note that text is not a bound property, so no PropertyChangeEvent is fired when it changes. To listen for changes to the text, use DocumentListener.

Params:
  • t – the new text to be set
See Also:
/** * Sets the text of this <code>TextComponent</code> * to the specified text. If the text is <code>null</code> * or empty, has the effect of simply deleting the old text. * When text has been inserted, the resulting caret location * is determined by the implementation of the caret class. * * <p> * Note that text is not a bound property, so no <code>PropertyChangeEvent * </code> is fired when it changes. To listen for changes to the text, * use <code>DocumentListener</code>. * * @param t the new text to be set * @see #getText * @see DefaultCaret */
@BeanProperty(bound = false, description = "the text of this component") public void setText(String t) { try { Document doc = getDocument(); if (doc instanceof AbstractDocument) { ((AbstractDocument)doc).replace(0, doc.getLength(), t,null); } else { doc.remove(0, doc.getLength()); doc.insertString(0, t, null); } } catch (BadLocationException e) { UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this); } }
Returns the text contained in this TextComponent. If the underlying document is null, will give a NullPointerException. Note that text is not a bound property, so no PropertyChangeEvent is fired when it changes. To listen for changes to the text, use DocumentListener.
Throws:
See Also:
Returns:the text
/** * Returns the text contained in this <code>TextComponent</code>. * If the underlying document is <code>null</code>, * will give a <code>NullPointerException</code>. * * Note that text is not a bound property, so no <code>PropertyChangeEvent * </code> is fired when it changes. To listen for changes to the text, * use <code>DocumentListener</code>. * * @return the text * @exception NullPointerException if the document is <code>null</code> * @see #setText */
public String getText() { Document doc = getDocument(); String txt; try { txt = doc.getText(0, doc.getLength()); } catch (BadLocationException e) { txt = null; } return txt; }
Returns the selected text contained in this TextComponent. If the selection is null or the document empty, returns null.
Throws:
See Also:
Returns:the text
/** * Returns the selected text contained in this * <code>TextComponent</code>. If the selection is * <code>null</code> or the document empty, returns <code>null</code>. * * @return the text * @exception IllegalArgumentException if the selection doesn't * have a valid mapping into the document for some reason * @see #setText */
@BeanProperty(bound = false) public String getSelectedText() { String txt = null; int p0 = Math.min(caret.getDot(), caret.getMark()); int p1 = Math.max(caret.getDot(), caret.getMark()); if (p0 != p1) { try { Document doc = getDocument(); txt = doc.getText(p0, p1 - p0); } catch (BadLocationException e) { throw new IllegalArgumentException(e.getMessage()); } } return txt; }
Returns the boolean indicating whether this TextComponent is editable or not.
See Also:
Returns:the boolean value
/** * Returns the boolean indicating whether this * <code>TextComponent</code> is editable or not. * * @return the boolean value * @see #setEditable */
public boolean isEditable() { return editable; }
Sets the specified boolean to indicate whether or not this TextComponent should be editable. A PropertyChange event ("editable") is fired when the state is changed.
Params:
  • b – the boolean to be set
See Also:
/** * Sets the specified boolean to indicate whether or not this * <code>TextComponent</code> should be editable. * A PropertyChange event ("editable") is fired when the * state is changed. * * @param b the boolean to be set * @see #isEditable */
@BeanProperty(description = "specifies if the text can be edited") public void setEditable(boolean b) { if (b != editable) { boolean oldVal = editable; editable = b; enableInputMethods(editable); firePropertyChange("editable", Boolean.valueOf(oldVal), Boolean.valueOf(editable)); repaint(); } }
Returns the selected text's start position. Return 0 for an empty document, or the value of dot if no selection.
Returns:the start position ≥ 0
/** * Returns the selected text's start position. Return 0 for an * empty document, or the value of dot if no selection. * * @return the start position &ge; 0 */
@Transient public int getSelectionStart() { int start = Math.min(caret.getDot(), caret.getMark()); return start; }
Sets the selection start to the specified position. The new starting point is constrained to be before or at the current selection end.

This is available for backward compatibility to code that called this method on java.awt.TextComponent. This is implemented to forward to the Caret implementation which is where the actual selection is maintained.

Params:
  • selectionStart – the start position of the text ≥ 0
/** * Sets the selection start to the specified position. The new * starting point is constrained to be before or at the current * selection end. * <p> * This is available for backward compatibility to code * that called this method on <code>java.awt.TextComponent</code>. * This is implemented to forward to the <code>Caret</code> * implementation which is where the actual selection is maintained. * * @param selectionStart the start position of the text &ge; 0 */
@BeanProperty(bound = false, description = "starting location of the selection.") public void setSelectionStart(int selectionStart) { /* Route through select method to enforce consistent policy * between selectionStart and selectionEnd. */ select(selectionStart, getSelectionEnd()); }
Returns the selected text's end position. Return 0 if the document is empty, or the value of dot if there is no selection.
Returns:the end position ≥ 0
/** * Returns the selected text's end position. Return 0 if the document * is empty, or the value of dot if there is no selection. * * @return the end position &ge; 0 */
@Transient public int getSelectionEnd() { int end = Math.max(caret.getDot(), caret.getMark()); return end; }
Sets the selection end to the specified position. The new end point is constrained to be at or after the current selection start.

This is available for backward compatibility to code that called this method on java.awt.TextComponent. This is implemented to forward to the Caret implementation which is where the actual selection is maintained.

Params:
  • selectionEnd – the end position of the text ≥ 0
/** * Sets the selection end to the specified position. The new * end point is constrained to be at or after the current * selection start. * <p> * This is available for backward compatibility to code * that called this method on <code>java.awt.TextComponent</code>. * This is implemented to forward to the <code>Caret</code> * implementation which is where the actual selection is maintained. * * @param selectionEnd the end position of the text &ge; 0 */
@BeanProperty(bound = false, description = "ending location of the selection.") public void setSelectionEnd(int selectionEnd) { /* Route through select method to enforce consistent policy * between selectionStart and selectionEnd. */ select(getSelectionStart(), selectionEnd); }
Selects the text between the specified start and end positions.

This method sets the start and end positions of the selected text, enforcing the restriction that the start position must be greater than or equal to zero. The end position must be greater than or equal to the start position, and less than or equal to the length of the text component's text.

If the caller supplies values that are inconsistent or out of bounds, the method enforces these constraints silently, and without failure. Specifically, if the start position or end position is greater than the length of the text, it is reset to equal the text length. If the start position is less than zero, it is reset to zero, and if the end position is less than the start position, it is reset to the start position.

This call is provided for backward compatibility. It is routed to a call to setCaretPosition followed by a call to moveCaretPosition. The preferred way to manage selection is by calling those methods directly.

Params:
  • selectionStart – the start position of the text
  • selectionEnd – the end position of the text
See Also:
/** * Selects the text between the specified start and end positions. * <p> * This method sets the start and end positions of the * selected text, enforcing the restriction that the start position * must be greater than or equal to zero. The end position must be * greater than or equal to the start position, and less than or * equal to the length of the text component's text. * <p> * If the caller supplies values that are inconsistent or out of * bounds, the method enforces these constraints silently, and * without failure. Specifically, if the start position or end * position is greater than the length of the text, it is reset to * equal the text length. If the start position is less than zero, * it is reset to zero, and if the end position is less than the * start position, it is reset to the start position. * <p> * This call is provided for backward compatibility. * It is routed to a call to <code>setCaretPosition</code> * followed by a call to <code>moveCaretPosition</code>. * The preferred way to manage selection is by calling * those methods directly. * * @param selectionStart the start position of the text * @param selectionEnd the end position of the text * @see #setCaretPosition * @see #moveCaretPosition */
public void select(int selectionStart, int selectionEnd) { // argument adjustment done by java.awt.TextComponent int docLength = getDocument().getLength(); if (selectionStart < 0) { selectionStart = 0; } if (selectionStart > docLength) { selectionStart = docLength; } if (selectionEnd > docLength) { selectionEnd = docLength; } if (selectionEnd < selectionStart) { selectionEnd = selectionStart; } setCaretPosition(selectionStart); moveCaretPosition(selectionEnd); }
Selects all the text in the TextComponent. Does nothing on a null or empty document.
/** * Selects all the text in the <code>TextComponent</code>. * Does nothing on a <code>null</code> or empty document. */
public void selectAll() { Document doc = getDocument(); if (doc != null) { setCaretPosition(0); moveCaretPosition(doc.getLength()); } } // --- Tooltip Methods ---------------------------------------------
Returns the string to be used as the tooltip for event. This will return one of:
  1. If setToolTipText has been invoked with a non-null value, it will be returned, otherwise
  2. The value from invoking getToolTipText on the UI will be returned.
By default JTextComponent does not register itself with the ToolTipManager. This means that tooltips will NOT be shown from the TextUI unless registerComponent has been invoked on the ToolTipManager.
Params:
  • event – the event in question
See Also:
Returns:the string to be used as the tooltip for event
/** * Returns the string to be used as the tooltip for <code>event</code>. * This will return one of: * <ol> * <li>If <code>setToolTipText</code> has been invoked with a * non-<code>null</code> * value, it will be returned, otherwise * <li>The value from invoking <code>getToolTipText</code> on * the UI will be returned. * </ol> * By default <code>JTextComponent</code> does not register * itself with the <code>ToolTipManager</code>. * This means that tooltips will NOT be shown from the * <code>TextUI</code> unless <code>registerComponent</code> has * been invoked on the <code>ToolTipManager</code>. * * @param event the event in question * @return the string to be used as the tooltip for <code>event</code> * @see javax.swing.JComponent#setToolTipText * @see javax.swing.plaf.TextUI#getToolTipText * @see javax.swing.ToolTipManager#registerComponent */
@SuppressWarnings("deprecation") public String getToolTipText(MouseEvent event) { String retValue = super.getToolTipText(event); if (retValue == null) { TextUI ui = getUI(); if (ui != null) { retValue = ui.getToolTipText(this, new Point(event.getX(), event.getY())); } } return retValue; } // --- Scrollable methods ---------------------------------------------
Returns the preferred size of the viewport for a view component. This is implemented to do the default behavior of returning the preferred size of the component.
Returns:the preferredSize of a JViewport whose view is this Scrollable
/** * Returns the preferred size of the viewport for a view component. * This is implemented to do the default behavior of returning * the preferred size of the component. * * @return the <code>preferredSize</code> of a <code>JViewport</code> * whose view is this <code>Scrollable</code> */
@BeanProperty(bound = false) public Dimension getPreferredScrollableViewportSize() { return getPreferredSize(); }
Components that display logical rows or columns should compute the scroll increment that will completely expose one new row or column, depending on the value of orientation. Ideally, components should handle a partially exposed row or column by returning the distance required to completely expose the item.

The default implementation of this is to simply return 10% of the visible area. Subclasses are likely to be able to provide a much more reasonable value.

Params:
  • visibleRect – the view area visible within the viewport
  • orientation – either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL
  • direction – less than zero to scroll up/left, greater than zero for down/right
Throws:
See Also:
Returns:the "unit" increment for scrolling in the specified direction
/** * Components that display logical rows or columns should compute * the scroll increment that will completely expose one new row * or column, depending on the value of orientation. Ideally, * components should handle a partially exposed row or column by * returning the distance required to completely expose the item. * <p> * The default implementation of this is to simply return 10% of * the visible area. Subclasses are likely to be able to provide * a much more reasonable value. * * @param visibleRect the view area visible within the viewport * @param orientation either <code>SwingConstants.VERTICAL</code> or * <code>SwingConstants.HORIZONTAL</code> * @param direction less than zero to scroll up/left, greater than * zero for down/right * @return the "unit" increment for scrolling in the specified direction * @exception IllegalArgumentException for an invalid orientation * @see JScrollBar#setUnitIncrement */
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { switch(orientation) { case SwingConstants.VERTICAL: return visibleRect.height / 10; case SwingConstants.HORIZONTAL: return visibleRect.width / 10; default: throw new IllegalArgumentException("Invalid orientation: " + orientation); } }
Components that display logical rows or columns should compute the scroll increment that will completely expose one block of rows or columns, depending on the value of orientation.

The default implementation of this is to simply return the visible area. Subclasses will likely be able to provide a much more reasonable value.

Params:
  • visibleRect – the view area visible within the viewport
  • orientation – either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL
  • direction – less than zero to scroll up/left, greater than zero for down/right
Throws:
See Also:
Returns:the "block" increment for scrolling in the specified direction
/** * Components that display logical rows or columns should compute * the scroll increment that will completely expose one block * of rows or columns, depending on the value of orientation. * <p> * The default implementation of this is to simply return the visible * area. Subclasses will likely be able to provide a much more * reasonable value. * * @param visibleRect the view area visible within the viewport * @param orientation either <code>SwingConstants.VERTICAL</code> or * <code>SwingConstants.HORIZONTAL</code> * @param direction less than zero to scroll up/left, greater than zero * for down/right * @return the "block" increment for scrolling in the specified direction * @exception IllegalArgumentException for an invalid orientation * @see JScrollBar#setBlockIncrement */
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { switch(orientation) { case SwingConstants.VERTICAL: return visibleRect.height; case SwingConstants.HORIZONTAL: return visibleRect.width; default: throw new IllegalArgumentException("Invalid orientation: " + orientation); } }
Returns true if a viewport should always force the width of this Scrollable to match the width of the viewport. For example a normal text view that supported line wrapping would return true here, since it would be undesirable for wrapped lines to disappear beyond the right edge of the viewport. Note that returning true for a Scrollable whose ancestor is a JScrollPane effectively disables horizontal scrolling.

Scrolling containers, like JViewport, will use this method each time they are validated.

Returns:true if a viewport should force the Scrollables width to match its own
/** * Returns true if a viewport should always force the width of this * <code>Scrollable</code> to match the width of the viewport. * For example a normal text view that supported line wrapping * would return true here, since it would be undesirable for * wrapped lines to disappear beyond the right * edge of the viewport. Note that returning true for a * <code>Scrollable</code> whose ancestor is a <code>JScrollPane</code> * effectively disables horizontal scrolling. * <p> * Scrolling containers, like <code>JViewport</code>, * will use this method each time they are validated. * * @return true if a viewport should force the <code>Scrollable</code>s * width to match its own */
@BeanProperty(bound = false) public boolean getScrollableTracksViewportWidth() { Container parent = SwingUtilities.getUnwrappedParent(this); if (parent instanceof JViewport) { return parent.getWidth() > getPreferredSize().width; } return false; }
Returns true if a viewport should always force the height of this Scrollable to match the height of the viewport. For example a columnar text view that flowed text in left to right columns could effectively disable vertical scrolling by returning true here.

Scrolling containers, like JViewport, will use this method each time they are validated.

Returns:true if a viewport should force the Scrollables height to match its own
/** * Returns true if a viewport should always force the height of this * <code>Scrollable</code> to match the height of the viewport. * For example a columnar text view that flowed text in left to * right columns could effectively disable vertical scrolling by * returning true here. * <p> * Scrolling containers, like <code>JViewport</code>, * will use this method each time they are validated. * * @return true if a viewport should force the Scrollables height * to match its own */
@BeanProperty(bound = false) public boolean getScrollableTracksViewportHeight() { Container parent = SwingUtilities.getUnwrappedParent(this); if (parent instanceof JViewport) { return parent.getHeight() > getPreferredSize().height; } return false; } ////////////////// // Printing Support //////////////////
A convenience print method that displays a print dialog, and then prints this JTextComponent in interactive mode with no header or footer text. Note: this method blocks until printing is done.

Note: In headless mode, no dialogs will be shown.

This method calls the full featured print method to perform printing.

Throws:
See Also:
Returns:true, unless printing is canceled by the user
Since:1.6
/** * A convenience print method that displays a print dialog, and then * prints this {@code JTextComponent} in <i>interactive</i> mode with no * header or footer text. Note: this method * blocks until printing is done. * <p> * Note: In <i>headless</i> mode, no dialogs will be shown. * * <p> This method calls the full featured * {@link #print(MessageFormat, MessageFormat, boolean, PrintService, PrintRequestAttributeSet, boolean) * print} method to perform printing. * @return {@code true}, unless printing is canceled by the user * @throws PrinterException if an error in the print system causes the job * to be aborted * @throws SecurityException if this thread is not allowed to * initiate a print job request * * @see #print(MessageFormat, MessageFormat, boolean, PrintService, PrintRequestAttributeSet, boolean) * * @since 1.6 */
public boolean print() throws PrinterException { return print(null, null, true, null, null, true); }
A convenience print method that displays a print dialog, and then prints this JTextComponent in interactive mode with the specified header and footer text. Note: this method blocks until printing is done.

Note: In headless mode, no dialogs will be shown.

This method calls the full featured print method to perform printing.

Params:
  • headerFormat – the text, in MessageFormat, to be used as the header, or null for no header
  • footerFormat – the text, in MessageFormat, to be used as the footer, or null for no footer
Throws:
See Also:
Returns:true, unless printing is canceled by the user
Since:1.6
/** * A convenience print method that displays a print dialog, and then * prints this {@code JTextComponent} in <i>interactive</i> mode with * the specified header and footer text. Note: this method * blocks until printing is done. * <p> * Note: In <i>headless</i> mode, no dialogs will be shown. * * <p> This method calls the full featured * {@link #print(MessageFormat, MessageFormat, boolean, PrintService, PrintRequestAttributeSet, boolean) * print} method to perform printing. * @param headerFormat the text, in {@code MessageFormat}, to be * used as the header, or {@code null} for no header * @param footerFormat the text, in {@code MessageFormat}, to be * used as the footer, or {@code null} for no footer * @return {@code true}, unless printing is canceled by the user * @throws PrinterException if an error in the print system causes the job * to be aborted * @throws SecurityException if this thread is not allowed to * initiate a print job request * * @see #print(MessageFormat, MessageFormat, boolean, PrintService, PrintRequestAttributeSet, boolean) * @see java.text.MessageFormat * @since 1.6 */
public boolean print(final MessageFormat headerFormat, final MessageFormat footerFormat) throws PrinterException { return print(headerFormat, footerFormat, true, null, null, true); }
Prints the content of this JTextComponent. Note: this method blocks until printing is done.

Page header and footer text can be added to the output by providing MessageFormat arguments. The printing code requests Strings from the formats, providing a single item which may be included in the formatted string: an Integer representing the current page number.

showPrintDialog boolean parameter allows you to specify whether a print dialog is displayed to the user. When it is, the user may use the dialog to change printing attributes or even cancel the print.

service allows you to provide the initial PrintService for the print dialog, or to specify PrintService to print to when the dialog is not shown.

attributes can be used to provide the initial values for the print dialog, or to supply any needed attributes when the dialog is not shown. attributes can be used to control how the job will print, for example duplex or single-sided.

interactive boolean parameter allows you to specify whether to perform printing in interactive mode. If true, a progress dialog, with an abort option, is displayed for the duration of printing. This dialog is modal when print is invoked on the Event Dispatch Thread and non-modal otherwise. Warning: calling this method on the Event Dispatch Thread with interactive false blocks all events, including repaints, from being processed until printing is complete. It is only recommended when printing from an application with no visible GUI.

Note: In headless mode, showPrintDialog and interactive parameters are ignored and no dialogs are shown.

This method ensures the document is not mutated during printing. To indicate it visually, setEnabled(false) is set for the duration of printing.

This method uses getPrintable to render document content.

This method is thread-safe, although most Swing methods are not. Please see Concurrency in Swing for more information.

Sample Usage. This code snippet shows a cross-platform print dialog and then prints the JTextComponent in interactive mode unless the user cancels the dialog:

textComponent.print(new MessageFormat("My text component header"),
    new MessageFormat("Footer. Page - {0}"), true, null, null, true);

Executing this code off the Event Dispatch Thread performs printing on the background. The following pattern might be used for background printing:

    FutureTask<Boolean> future =
        new FutureTask<Boolean>(
            new Callable<Boolean>() {
                public Boolean call() {
                    return textComponent.print(.....);
                }
            });
    executor.execute(future);
Params:
  • headerFormat – the text, in MessageFormat, to be used as the header, or null for no header
  • footerFormat – the text, in MessageFormat, to be used as the footer, or null for no footer
  • showPrintDialog – true to display a print dialog, false otherwise
  • service – initial PrintService, or null for the default
  • attributes – the job attributes to be applied to the print job, or null for none
  • interactive – whether to print in an interactive mode
Throws:
See Also:
Returns:true, unless printing is canceled by the user
Since:1.6
/** * Prints the content of this {@code JTextComponent}. Note: this method * blocks until printing is done. * * <p> * Page header and footer text can be added to the output by providing * {@code MessageFormat} arguments. The printing code requests * {@code Strings} from the formats, providing a single item which may be * included in the formatted string: an {@code Integer} representing the * current page number. * * <p> * {@code showPrintDialog boolean} parameter allows you to specify whether * a print dialog is displayed to the user. When it is, the user * may use the dialog to change printing attributes or even cancel the * print. * * <p> * {@code service} allows you to provide the initial * {@code PrintService} for the print dialog, or to specify * {@code PrintService} to print to when the dialog is not shown. * * <p> * {@code attributes} can be used to provide the * initial values for the print dialog, or to supply any needed * attributes when the dialog is not shown. {@code attributes} can * be used to control how the job will print, for example * <i>duplex</i> or <i>single-sided</i>. * * <p> * {@code interactive boolean} parameter allows you to specify * whether to perform printing in <i>interactive</i> * mode. If {@code true}, a progress dialog, with an abort option, * is displayed for the duration of printing. This dialog is * <i>modal</i> when {@code print} is invoked on the <i>Event Dispatch * Thread</i> and <i>non-modal</i> otherwise. <b>Warning</b>: * calling this method on the <i>Event Dispatch Thread</i> with {@code * interactive false} blocks <i>all</i> events, including repaints, from * being processed until printing is complete. It is only * recommended when printing from an application with no * visible GUI. * * <p> * Note: In <i>headless</i> mode, {@code showPrintDialog} and * {@code interactive} parameters are ignored and no dialogs are * shown. * * <p> * This method ensures the {@code document} is not mutated during printing. * To indicate it visually, {@code setEnabled(false)} is set for the * duration of printing. * * <p> * This method uses {@link #getPrintable} to render document content. * * <p> * This method is thread-safe, although most Swing methods are not. Please * see <A * HREF="https://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html"> * Concurrency in Swing</A> for more information. * * <p> * <b>Sample Usage</b>. This code snippet shows a cross-platform print * dialog and then prints the {@code JTextComponent} in <i>interactive</i> mode * unless the user cancels the dialog: * * <pre> * textComponent.print(new MessageFormat(&quot;My text component header&quot;), * new MessageFormat(&quot;Footer. Page - {0}&quot;), true, null, null, true); * </pre> * <p> * Executing this code off the <i>Event Dispatch Thread</i> * performs printing on the <i>background</i>. * The following pattern might be used for <i>background</i> * printing: * <pre> * FutureTask&lt;Boolean&gt; future = * new FutureTask&lt;Boolean&gt;( * new Callable&lt;Boolean&gt;() { * public Boolean call() { * return textComponent.print(.....); * } * }); * executor.execute(future); * </pre> * * @param headerFormat the text, in {@code MessageFormat}, to be * used as the header, or {@code null} for no header * @param footerFormat the text, in {@code MessageFormat}, to be * used as the footer, or {@code null} for no footer * @param showPrintDialog {@code true} to display a print dialog, * {@code false} otherwise * @param service initial {@code PrintService}, or {@code null} for the * default * @param attributes the job attributes to be applied to the print job, or * {@code null} for none * @param interactive whether to print in an interactive mode * @return {@code true}, unless printing is canceled by the user * @throws PrinterException if an error in the print system causes the job * to be aborted * @throws SecurityException if this thread is not allowed to * initiate a print job request * * @see #getPrintable * @see java.text.MessageFormat * @see java.awt.GraphicsEnvironment#isHeadless * @see java.util.concurrent.FutureTask * * @since 1.6 */
public boolean print(final MessageFormat headerFormat, final MessageFormat footerFormat, final boolean showPrintDialog, final PrintService service, final PrintRequestAttributeSet attributes, final boolean interactive) throws PrinterException { final PrinterJob job = PrinterJob.getPrinterJob(); final Printable printable; final PrintingStatus printingStatus; final boolean isHeadless = GraphicsEnvironment.isHeadless(); final boolean isEventDispatchThread = SwingUtilities.isEventDispatchThread(); final Printable textPrintable = getPrintable(headerFormat, footerFormat); if (interactive && ! isHeadless) { printingStatus = PrintingStatus.createPrintingStatus(this, job); printable = printingStatus.createNotificationPrintable(textPrintable); } else { printingStatus = null; printable = textPrintable; } if (service != null) { job.setPrintService(service); } job.setPrintable(printable); final PrintRequestAttributeSet attr = (attributes == null) ? new HashPrintRequestAttributeSet() : attributes; if (showPrintDialog && ! isHeadless && ! job.printDialog(attr)) { return false; } /* * there are three cases for printing: * 1. print non interactively (! interactive || isHeadless) * 2. print interactively off EDT * 3. print interactively on EDT * * 1 and 2 prints on the current thread (3 prints on another thread) * 2 and 3 deal with PrintingStatusDialog */ final Callable<Object> doPrint = new Callable<Object>() { public Object call() throws Exception { try { job.print(attr); } finally { if (printingStatus != null) { printingStatus.dispose(); } } return null; } }; final FutureTask<Object> futurePrinting = new FutureTask<Object>(doPrint); final Runnable runnablePrinting = new Runnable() { public void run() { //disable component boolean wasEnabled = false; if (isEventDispatchThread) { if (isEnabled()) { wasEnabled = true; setEnabled(false); } } else { try { wasEnabled = SwingUtilities2.submit( new Callable<Boolean>() { public Boolean call() throws Exception { boolean rv = isEnabled(); if (rv) { setEnabled(false); } return rv; } }).get(); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (ExecutionException e) { Throwable cause = e.getCause(); if (cause instanceof Error) { throw (Error) cause; } if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } throw new AssertionError(cause); } } getDocument().render(futurePrinting); //enable component if (wasEnabled) { if (isEventDispatchThread) { setEnabled(true); } else { try { SwingUtilities2.submit( new Runnable() { public void run() { setEnabled(true); } }, null).get(); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (ExecutionException e) { Throwable cause = e.getCause(); if (cause instanceof Error) { throw (Error) cause; } if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } throw new AssertionError(cause); } } } } }; if (! interactive || isHeadless) { runnablePrinting.run(); } else { if (isEventDispatchThread) { new Thread(null, runnablePrinting, "JTextComponentPrint", 0, false ).start(); printingStatus.showModal(true); } else { printingStatus.showModal(false); runnablePrinting.run(); } } //the printing is done successfully or otherwise. //dialog is hidden if needed. try { futurePrinting.get(); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (ExecutionException e) { Throwable cause = e.getCause(); if (cause instanceof PrinterAbortException) { if (printingStatus != null && printingStatus.isAborted()) { return false; } else { throw (PrinterAbortException) cause; } } else if (cause instanceof PrinterException) { throw (PrinterException) cause; } else if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } else { throw new AssertionError(cause); } } return true; }
Returns a Printable to use for printing the content of this JTextComponent. The returned Printable prints the document as it looks on the screen except being reformatted to fit the paper. The returned Printable can be wrapped inside another Printable in order to create complex reports and documents.

The returned Printable shares the document with this JTextComponent. It is the responsibility of the developer to ensure that the document is not mutated while this Printable is used. Printing behavior is undefined when the document is mutated during printing.

Page header and footer text can be added to the output by providing MessageFormat arguments. The printing code requests Strings from the formats, providing a single item which may be included in the formatted string: an Integer representing the current page number.

The returned Printable when printed, formats the document content appropriately for the page size. For correct line wrapping the imageable width of all pages must be the same. See PageFormat.getImageableWidth.

This method is thread-safe, although most Swing methods are not. Please see Concurrency in Swing for more information.

The returned Printable can be printed on any thread.

This implementation returned Printable performs all painting on the Event Dispatch Thread, regardless of what thread it is used on.

Params:
  • headerFormat – the text, in MessageFormat, to be used as the header, or null for no header
  • footerFormat – the text, in MessageFormat, to be used as the footer, or null for no footer
See Also:
Returns:a Printable for use in printing content of this JTextComponent
Since:1.6
/** * Returns a {@code Printable} to use for printing the content of this * {@code JTextComponent}. The returned {@code Printable} prints * the document as it looks on the screen except being reformatted * to fit the paper. * The returned {@code Printable} can be wrapped inside another * {@code Printable} in order to create complex reports and * documents. * * * <p> * The returned {@code Printable} shares the {@code document} with this * {@code JTextComponent}. It is the responsibility of the developer to * ensure that the {@code document} is not mutated while this {@code Printable} * is used. Printing behavior is undefined when the {@code document} is * mutated during printing. * * <p> * Page header and footer text can be added to the output by providing * {@code MessageFormat} arguments. The printing code requests * {@code Strings} from the formats, providing a single item which may be * included in the formatted string: an {@code Integer} representing the * current page number. * * <p> * The returned {@code Printable} when printed, formats the * document content appropriately for the page size. For correct * line wrapping the {@code imageable width} of all pages must be the * same. See {@link java.awt.print.PageFormat#getImageableWidth}. * * <p> * This method is thread-safe, although most Swing methods are not. Please * see <A * HREF="https://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html"> * Concurrency in Swing</A> for more information. * * <p> * The returned {@code Printable} can be printed on any thread. * * <p> * This implementation returned {@code Printable} performs all painting on * the <i>Event Dispatch Thread</i>, regardless of what thread it is * used on. * * @param headerFormat the text, in {@code MessageFormat}, to be * used as the header, or {@code null} for no header * @param footerFormat the text, in {@code MessageFormat}, to be * used as the footer, or {@code null} for no footer * @return a {@code Printable} for use in printing content of this * {@code JTextComponent} * * * @see java.awt.print.Printable * @see java.awt.print.PageFormat * @see javax.swing.text.Document#render(java.lang.Runnable) * * @since 1.6 */
public Printable getPrintable(final MessageFormat headerFormat, final MessageFormat footerFormat) { return TextComponentPrintable.getPrintable( this, headerFormat, footerFormat); } ///////////////// // Accessibility support ////////////////
Gets the AccessibleContext associated with this JTextComponent. For text components, the AccessibleContext takes the form of an AccessibleJTextComponent. A new AccessibleJTextComponent instance is created if necessary.
Returns:an AccessibleJTextComponent that serves as the AccessibleContext of this JTextComponent
/** * Gets the <code>AccessibleContext</code> associated with this * <code>JTextComponent</code>. For text components, * the <code>AccessibleContext</code> takes the form of an * <code>AccessibleJTextComponent</code>. * A new <code>AccessibleJTextComponent</code> instance * is created if necessary. * * @return an <code>AccessibleJTextComponent</code> that serves as the * <code>AccessibleContext</code> of this * <code>JTextComponent</code> */
@BeanProperty(bound = false) public AccessibleContext getAccessibleContext() { if (accessibleContext == null) { accessibleContext = new AccessibleJTextComponent(); } return accessibleContext; }
This class implements accessibility support for the JTextComponent class. It provides an implementation of the Java Accessibility API appropriate to menu user-interface elements.

Warning: Serialized objects of this class will not be compatible with future Swing releases. The current serialization support is appropriate for short term storage or RMI between applications running the same version of Swing. As of 1.4, support for long term storage of all JavaBeans has been added to the java.beans package. Please see XMLEncoder.

/** * This class implements accessibility support for the * <code>JTextComponent</code> class. It provides an implementation of * the Java Accessibility API appropriate to menu user-interface elements. * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeans * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. */
@SuppressWarnings("serial") // Same-version serialization only public class AccessibleJTextComponent extends AccessibleJComponent implements AccessibleText, CaretListener, DocumentListener, AccessibleAction, AccessibleEditableText, AccessibleExtendedText { int caretPos; Point oldLocationOnScreen;
Constructs an AccessibleJTextComponent. Adds a listener to track caret change.
/** * Constructs an AccessibleJTextComponent. Adds a listener to track * caret change. */
public AccessibleJTextComponent() { Document doc = JTextComponent.this.getDocument(); if (doc != null) { doc.addDocumentListener(this); } JTextComponent.this.addCaretListener(this); caretPos = getCaretPosition(); try { oldLocationOnScreen = getLocationOnScreen(); } catch (IllegalComponentStateException iae) { } // Fire a ACCESSIBLE_VISIBLE_DATA_PROPERTY PropertyChangeEvent // when the text component moves (e.g., when scrolling). // Using an anonymous class since making AccessibleJTextComponent // implement ComponentListener would be an API change. JTextComponent.this.addComponentListener(new ComponentAdapter() { public void componentMoved(ComponentEvent e) { try { Point newLocationOnScreen = getLocationOnScreen(); firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, oldLocationOnScreen, newLocationOnScreen); oldLocationOnScreen = newLocationOnScreen; } catch (IllegalComponentStateException iae) { } } }); }
Handles caret updates (fire appropriate property change event, which are AccessibleContext.ACCESSIBLE_CARET_PROPERTY and AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY). This keeps track of the dot position internally. When the caret moves, the internal position is updated after firing the event.
Params:
  • e – the CaretEvent
/** * Handles caret updates (fire appropriate property change event, * which are AccessibleContext.ACCESSIBLE_CARET_PROPERTY and * AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY). * This keeps track of the dot position internally. When the caret * moves, the internal position is updated after firing the event. * * @param e the CaretEvent */
public void caretUpdate(CaretEvent e) { int dot = e.getDot(); int mark = e.getMark(); if (caretPos != dot) { // the caret moved firePropertyChange(ACCESSIBLE_CARET_PROPERTY, caretPos, dot); caretPos = dot; try { oldLocationOnScreen = getLocationOnScreen(); } catch (IllegalComponentStateException iae) { } } if (mark != dot) { // there is a selection firePropertyChange(ACCESSIBLE_SELECTION_PROPERTY, null, getSelectedText()); } } // DocumentListener methods
Handles document insert (fire appropriate property change event which is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY). This tracks the changed offset via the event.
Params:
  • e – the DocumentEvent
/** * Handles document insert (fire appropriate property change event * which is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY). * This tracks the changed offset via the event. * * @param e the DocumentEvent */
public void insertUpdate(DocumentEvent e) { final Integer pos = e.getOffset(); if (SwingUtilities.isEventDispatchThread()) { firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, pos); } else { Runnable doFire = new Runnable() { public void run() { firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, pos); } }; SwingUtilities.invokeLater(doFire); } }
Handles document remove (fire appropriate property change event, which is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY). This tracks the changed offset via the event.
Params:
  • e – the DocumentEvent
/** * Handles document remove (fire appropriate property change event, * which is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY). * This tracks the changed offset via the event. * * @param e the DocumentEvent */
public void removeUpdate(DocumentEvent e) { final Integer pos = e.getOffset(); if (SwingUtilities.isEventDispatchThread()) { firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, pos); } else { Runnable doFire = new Runnable() { public void run() { firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, pos); } }; SwingUtilities.invokeLater(doFire); } }
Handles document remove (fire appropriate property change event, which is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY). This tracks the changed offset via the event.
Params:
  • e – the DocumentEvent
/** * Handles document remove (fire appropriate property change event, * which is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY). * This tracks the changed offset via the event. * * @param e the DocumentEvent */
public void changedUpdate(DocumentEvent e) { final Integer pos = e.getOffset(); if (SwingUtilities.isEventDispatchThread()) { firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, pos); } else { Runnable doFire = new Runnable() { public void run() { firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, pos); } }; SwingUtilities.invokeLater(doFire); } }
Gets the state set of the JTextComponent. The AccessibleStateSet of an object is composed of a set of unique AccessibleState's. A change in the AccessibleStateSet of an object will cause a PropertyChangeEvent to be fired for the AccessibleContext.ACCESSIBLE_STATE_PROPERTY property.
See Also:
Returns:an instance of AccessibleStateSet containing the current state set of the object
/** * Gets the state set of the JTextComponent. * The AccessibleStateSet of an object is composed of a set of * unique AccessibleState's. A change in the AccessibleStateSet * of an object will cause a PropertyChangeEvent to be fired * for the AccessibleContext.ACCESSIBLE_STATE_PROPERTY property. * * @return an instance of AccessibleStateSet containing the * current state set of the object * @see AccessibleStateSet * @see AccessibleState * @see #addPropertyChangeListener */
public AccessibleStateSet getAccessibleStateSet() { AccessibleStateSet states = super.getAccessibleStateSet(); if (JTextComponent.this.isEditable()) { states.add(AccessibleState.EDITABLE); } return states; }
Gets the role of this object.
See Also:
Returns:an instance of AccessibleRole describing the role of the object (AccessibleRole.TEXT)
/** * Gets the role of this object. * * @return an instance of AccessibleRole describing the role of the * object (AccessibleRole.TEXT) * @see AccessibleRole */
public AccessibleRole getAccessibleRole() { return AccessibleRole.TEXT; }
Get the AccessibleText associated with this object. In the implementation of the Java Accessibility API for this class, return this object, which is responsible for implementing the AccessibleText interface on behalf of itself.
Returns:this object
/** * Get the AccessibleText associated with this object. In the * implementation of the Java Accessibility API for this class, * return this object, which is responsible for implementing the * AccessibleText interface on behalf of itself. * * @return this object */
public AccessibleText getAccessibleText() { return this; } // --- interface AccessibleText methods ------------------------ /** * Many of these methods are just convenience methods; they * just call the equivalent on the parent */
Given a point in local coordinates, return the zero-based index of the character under that Point. If the point is invalid, this method returns -1.
Params:
  • p – the Point in local coordinates
Returns:the zero-based index of the character under Point p.
/** * Given a point in local coordinates, return the zero-based index * of the character under that Point. If the point is invalid, * this method returns -1. * * @param p the Point in local coordinates * @return the zero-based index of the character under Point p. */
public int getIndexAtPoint(Point p) { if (p == null) { return -1; } return JTextComponent.this.viewToModel(p); }
Gets the editor's drawing rectangle. Stolen from the unfortunately named BasicTextUI.getVisibleEditorRect()
Returns:the bounding box for the root view
/** * Gets the editor's drawing rectangle. Stolen * from the unfortunately named * BasicTextUI.getVisibleEditorRect() * * @return the bounding box for the root view */
Rectangle getRootEditorRect() { Rectangle alloc = JTextComponent.this.getBounds(); if ((alloc.width > 0) && (alloc.height > 0)) { alloc.x = alloc.y = 0; Insets insets = JTextComponent.this.getInsets(); alloc.x += insets.left; alloc.y += insets.top; alloc.width -= insets.left + insets.right; alloc.height -= insets.top + insets.bottom; return alloc; } return null; }
Determines the bounding box of the character at the given index into the string. The bounds are returned in local coordinates. If the index is invalid a null rectangle is returned. The screen coordinates returned are "unscrolled coordinates" if the JTextComponent is contained in a JScrollPane in which case the resulting rectangle should be composed with the parent coordinates. A good algorithm to use is:
Accessible a:
AccessibleText at = a.getAccessibleText();
AccessibleComponent ac = a.getAccessibleComponent();
Rectangle r = at.getCharacterBounds();
Point p = ac.getLocation();
r.x += p.x;
r.y += p.y;
Note: the JTextComponent must have a valid size (e.g. have been added to a parent container whose ancestor container is a valid top-level window) for this method to be able to return a meaningful (non-null) value.
Params:
  • i – the index into the String ≥ 0
Returns:the screen coordinates of the character's bounding box
/** * Determines the bounding box of the character at the given * index into the string. The bounds are returned in local * coordinates. If the index is invalid a null rectangle * is returned. * * The screen coordinates returned are "unscrolled coordinates" * if the JTextComponent is contained in a JScrollPane in which * case the resulting rectangle should be composed with the parent * coordinates. A good algorithm to use is: * <pre> * Accessible a: * AccessibleText at = a.getAccessibleText(); * AccessibleComponent ac = a.getAccessibleComponent(); * Rectangle r = at.getCharacterBounds(); * Point p = ac.getLocation(); * r.x += p.x; * r.y += p.y; * </pre> * * Note: the JTextComponent must have a valid size (e.g. have * been added to a parent container whose ancestor container * is a valid top-level window) for this method to be able * to return a meaningful (non-null) value. * * @param i the index into the String &ge; 0 * @return the screen coordinates of the character's bounding box */
public Rectangle getCharacterBounds(int i) { if (i < 0 || i > model.getLength()-1) { return null; } TextUI ui = getUI(); if (ui == null) { return null; } Rectangle rect = null; Rectangle alloc = getRootEditorRect(); if (alloc == null) { return null; } if (model instanceof AbstractDocument) { ((AbstractDocument)model).readLock(); } try { View rootView = ui.getRootView(JTextComponent.this); if (rootView != null) { rootView.setSize(alloc.width, alloc.height); Shape bounds = rootView.modelToView(i, Position.Bias.Forward, i+1, Position.Bias.Backward, alloc); rect = (bounds instanceof Rectangle) ? (Rectangle)bounds : bounds.getBounds(); } } catch (BadLocationException e) { } finally { if (model instanceof AbstractDocument) { ((AbstractDocument)model).readUnlock(); } } return rect; }
Returns the number of characters (valid indices)
Returns:the number of characters ≥ 0
/** * Returns the number of characters (valid indices) * * @return the number of characters &ge; 0 */
public int getCharCount() { return model.getLength(); }
Returns the zero-based offset of the caret. Note: The character to the right of the caret will have the same index value as the offset (the caret is between two characters).
Returns:the zero-based offset of the caret.
/** * Returns the zero-based offset of the caret. * * Note: The character to the right of the caret will have the * same index value as the offset (the caret is between * two characters). * * @return the zero-based offset of the caret. */
public int getCaretPosition() { return JTextComponent.this.getCaretPosition(); }
Returns the AttributeSet for a given character (at a given index).
Params:
  • i – the zero-based index into the text
Returns:the AttributeSet of the character
/** * Returns the AttributeSet for a given character (at a given index). * * @param i the zero-based index into the text * @return the AttributeSet of the character */
public AttributeSet getCharacterAttribute(int i) { Element e = null; if (model instanceof AbstractDocument) { ((AbstractDocument)model).readLock(); } try { for (e = model.getDefaultRootElement(); ! e.isLeaf(); ) { int index = e.getElementIndex(i); e = e.getElement(index); } } finally { if (model instanceof AbstractDocument) { ((AbstractDocument)model).readUnlock(); } } return e.getAttributes(); }
Returns the start offset within the selected text. If there is no selection, but there is a caret, the start and end offsets will be the same. Return 0 if the text is empty, or the caret position if no selection.
Returns:the index into the text of the start of the selection ≥ 0
/** * Returns the start offset within the selected text. * If there is no selection, but there is * a caret, the start and end offsets will be the same. * Return 0 if the text is empty, or the caret position * if no selection. * * @return the index into the text of the start of the selection &ge; 0 */
public int getSelectionStart() { return JTextComponent.this.getSelectionStart(); }
Returns the end offset within the selected text. If there is no selection, but there is a caret, the start and end offsets will be the same. Return 0 if the text is empty, or the caret position if no selection.
Returns:the index into the text of the end of the selection ≥ 0
/** * Returns the end offset within the selected text. * If there is no selection, but there is * a caret, the start and end offsets will be the same. * Return 0 if the text is empty, or the caret position * if no selection. * * @return the index into the text of the end of the selection &ge; 0 */
public int getSelectionEnd() { return JTextComponent.this.getSelectionEnd(); }
Returns the portion of the text that is selected.
Returns:the text, null if no selection
/** * Returns the portion of the text that is selected. * * @return the text, null if no selection */
public String getSelectedText() { return JTextComponent.this.getSelectedText(); }
IndexedSegment extends Segment adding the offset into the the model the Segment was asked for.
/** * IndexedSegment extends Segment adding the offset into the * the model the <code>Segment</code> was asked for. */
private class IndexedSegment extends Segment {
Offset into the model that the position represents.
/** * Offset into the model that the position represents. */
public int modelOffset; } // TIGER - 4170173
Returns the String at a given index. Whitespace between words is treated as a word.
Params:
  • part – the CHARACTER, WORD, or SENTENCE to retrieve
  • index – an index within the text
Returns:the letter, word, or sentence.
/** * Returns the String at a given index. Whitespace * between words is treated as a word. * * @param part the CHARACTER, WORD, or SENTENCE to retrieve * @param index an index within the text * @return the letter, word, or sentence. * */
public String getAtIndex(int part, int index) { return getAtIndex(part, index, 0); }
Returns the String after a given index. Whitespace between words is treated as a word.
Params:
  • part – the CHARACTER, WORD, or SENTENCE to retrieve
  • index – an index within the text
Returns:the letter, word, or sentence.
/** * Returns the String after a given index. Whitespace * between words is treated as a word. * * @param part the CHARACTER, WORD, or SENTENCE to retrieve * @param index an index within the text * @return the letter, word, or sentence. */
public String getAfterIndex(int part, int index) { return getAtIndex(part, index, 1); }
Returns the String before a given index. Whitespace between words is treated a word.
Params:
  • part – the CHARACTER, WORD, or SENTENCE to retrieve
  • index – an index within the text
Returns:the letter, word, or sentence.
/** * Returns the String before a given index. Whitespace * between words is treated a word. * * @param part the CHARACTER, WORD, or SENTENCE to retrieve * @param index an index within the text * @return the letter, word, or sentence. */
public String getBeforeIndex(int part, int index) { return getAtIndex(part, index, -1); }
Gets the word, sentence, or character at index. If direction is non-null this will find the next/previous word/sentence/character.
/** * Gets the word, sentence, or character at <code>index</code>. * If <code>direction</code> is non-null this will find the * next/previous word/sentence/character. */
private String getAtIndex(int part, int index, int direction) { if (model instanceof AbstractDocument) { ((AbstractDocument)model).readLock(); } try { if (index < 0 || index >= model.getLength()) { return null; } switch (part) { case AccessibleText.CHARACTER: if (index + direction < model.getLength() && index + direction >= 0) { return model.getText(index + direction, 1); } break; case AccessibleText.WORD: case AccessibleText.SENTENCE: IndexedSegment seg = getSegmentAt(part, index); if (seg != null) { if (direction != 0) { int next; if (direction < 0) { next = seg.modelOffset - 1; } else { next = seg.modelOffset + direction * seg.count; } if (next >= 0 && next <= model.getLength()) { seg = getSegmentAt(part, next); } else { seg = null; } } if (seg != null) { return new String(seg.array, seg.offset, seg.count); } } break; default: break; } } catch (BadLocationException e) { } finally { if (model instanceof AbstractDocument) { ((AbstractDocument)model).readUnlock(); } } return null; } /* * Returns the paragraph element for the specified index. */ private Element getParagraphElement(int index) { if (model instanceof PlainDocument ) { PlainDocument sdoc = (PlainDocument)model; return sdoc.getParagraphElement(index); } else if (model instanceof StyledDocument) { StyledDocument sdoc = (StyledDocument)model; return sdoc.getParagraphElement(index); } else { Element para; for (para = model.getDefaultRootElement(); ! para.isLeaf(); ) { int pos = para.getElementIndex(index); para = para.getElement(pos); } if (para == null) { return null; } return para.getParentElement(); } } /* * Returns a <code>Segment</code> containing the paragraph text * at <code>index</code>, or null if <code>index</code> isn't * valid. */ private IndexedSegment getParagraphElementText(int index) throws BadLocationException { Element para = getParagraphElement(index); if (para != null) { IndexedSegment segment = new IndexedSegment(); try { int length = para.getEndOffset() - para.getStartOffset(); model.getText(para.getStartOffset(), length, segment); } catch (BadLocationException e) { return null; } segment.modelOffset = para.getStartOffset(); return segment; } return null; }
Returns the Segment at index representing either the paragraph or sentence as identified by part, or null if a valid paragraph/sentence can't be found. The offset will point to the start of the word/sentence in the array, and the modelOffset will point to the location of the word/sentence in the model.
/** * Returns the Segment at <code>index</code> representing either * the paragraph or sentence as identified by <code>part</code>, or * null if a valid paragraph/sentence can't be found. The offset * will point to the start of the word/sentence in the array, and * the modelOffset will point to the location of the word/sentence * in the model. */
private IndexedSegment getSegmentAt(int part, int index) throws BadLocationException { IndexedSegment seg = getParagraphElementText(index); if (seg == null) { return null; } BreakIterator iterator; switch (part) { case AccessibleText.WORD: iterator = BreakIterator.getWordInstance(getLocale()); break; case AccessibleText.SENTENCE: iterator = BreakIterator.getSentenceInstance(getLocale()); break; default: return null; } seg.first(); iterator.setText(seg); int end = iterator.following(index - seg.modelOffset + seg.offset); if (end == BreakIterator.DONE) { return null; } if (end > seg.offset + seg.count) { return null; } int begin = iterator.previous(); if (begin == BreakIterator.DONE || begin >= seg.offset + seg.count) { return null; } seg.modelOffset = seg.modelOffset + begin - seg.offset; seg.offset = begin; seg.count = end - begin; return seg; } // begin AccessibleEditableText methods -----
Returns the AccessibleEditableText interface for this text component.
Returns:the AccessibleEditableText interface
Since:1.4
/** * Returns the AccessibleEditableText interface for * this text component. * * @return the AccessibleEditableText interface * @since 1.4 */
public AccessibleEditableText getAccessibleEditableText() { return this; }
Sets the text contents to the specified string.
Params:
  • s – the string to set the text contents
Since:1.4
/** * Sets the text contents to the specified string. * * @param s the string to set the text contents * @since 1.4 */
public void setTextContents(String s) { JTextComponent.this.setText(s); }
Inserts the specified string at the given index
Params:
  • index – the index in the text where the string will be inserted
  • s – the string to insert in the text
Since:1.4
/** * Inserts the specified string at the given index * * @param index the index in the text where the string will * be inserted * @param s the string to insert in the text * @since 1.4 */
public void insertTextAtIndex(int index, String s) { Document doc = JTextComponent.this.getDocument(); if (doc != null) { try { if (s != null && s.length() > 0) { boolean composedTextSaved = saveComposedText(index); doc.insertString(index, s, null); if (composedTextSaved) { restoreComposedText(); } } } catch (BadLocationException e) { UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this); } } }
Returns the text string between two indices.
Params:
  • startIndex – the starting index in the text
  • endIndex – the ending index in the text
Returns:the text string between the indices
Since:1.4
/** * Returns the text string between two indices. * * @param startIndex the starting index in the text * @param endIndex the ending index in the text * @return the text string between the indices * @since 1.4 */
public String getTextRange(int startIndex, int endIndex) { String txt = null; int p0 = Math.min(startIndex, endIndex); int p1 = Math.max(startIndex, endIndex); if (p0 != p1) { try { Document doc = JTextComponent.this.getDocument(); txt = doc.getText(p0, p1 - p0); } catch (BadLocationException e) { throw new IllegalArgumentException(e.getMessage()); } } return txt; }
Deletes the text between two indices
Params:
  • startIndex – the starting index in the text
  • endIndex – the ending index in the text
Since:1.4
/** * Deletes the text between two indices * * @param startIndex the starting index in the text * @param endIndex the ending index in the text * @since 1.4 */
public void delete(int startIndex, int endIndex) { if (isEditable() && isEnabled()) { try { int p0 = Math.min(startIndex, endIndex); int p1 = Math.max(startIndex, endIndex); if (p0 != p1) { Document doc = getDocument(); doc.remove(p0, p1 - p0); } } catch (BadLocationException e) { } } else { UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this); } }
Cuts the text between two indices into the system clipboard.
Params:
  • startIndex – the starting index in the text
  • endIndex – the ending index in the text
Since:1.4
/** * Cuts the text between two indices into the system clipboard. * * @param startIndex the starting index in the text * @param endIndex the ending index in the text * @since 1.4 */
public void cut(int startIndex, int endIndex) { selectText(startIndex, endIndex); JTextComponent.this.cut(); }
Pastes the text from the system clipboard into the text starting at the specified index.
Params:
  • startIndex – the starting index in the text
Since:1.4
/** * Pastes the text from the system clipboard into the text * starting at the specified index. * * @param startIndex the starting index in the text * @since 1.4 */
public void paste(int startIndex) { setCaretPosition(startIndex); JTextComponent.this.paste(); }
Replaces the text between two indices with the specified string.
Params:
  • startIndex – the starting index in the text
  • endIndex – the ending index in the text
  • s – the string to replace the text between two indices
Since:1.4
/** * Replaces the text between two indices with the specified * string. * * @param startIndex the starting index in the text * @param endIndex the ending index in the text * @param s the string to replace the text between two indices * @since 1.4 */
public void replaceText(int startIndex, int endIndex, String s) { selectText(startIndex, endIndex); JTextComponent.this.replaceSelection(s); }
Selects the text between two indices.
Params:
  • startIndex – the starting index in the text
  • endIndex – the ending index in the text
Since:1.4
/** * Selects the text between two indices. * * @param startIndex the starting index in the text * @param endIndex the ending index in the text * @since 1.4 */
public void selectText(int startIndex, int endIndex) { JTextComponent.this.select(startIndex, endIndex); }
Sets attributes for the text between two indices.
Params:
  • startIndex – the starting index in the text
  • endIndex – the ending index in the text
  • as – the attribute set
See Also:
Since:1.4
/** * Sets attributes for the text between two indices. * * @param startIndex the starting index in the text * @param endIndex the ending index in the text * @param as the attribute set * @see AttributeSet * @since 1.4 */
public void setAttributes(int startIndex, int endIndex, AttributeSet as) { // Fixes bug 4487492 Document doc = JTextComponent.this.getDocument(); if (doc != null && doc instanceof StyledDocument) { StyledDocument sDoc = (StyledDocument)doc; int offset = startIndex; int length = endIndex - startIndex; sDoc.setCharacterAttributes(offset, length, as, true); } } // ----- end AccessibleEditableText methods // ----- begin AccessibleExtendedText methods // Probably should replace the helper method getAtIndex() to return // instead an AccessibleTextSequence also for LINE & ATTRIBUTE_RUN // and then make the AccessibleText methods get[At|After|Before]Point // call this new method instead and return only the string portion
Returns the AccessibleTextSequence at a given index. If direction is non-null this will find the next/previous word/sentence/character.
Params:
  • part – the CHARACTER, WORD, SENTENCE, LINE or ATTRIBUTE_RUN to retrieve
  • index – an index within the text
  • direction – is either -1, 0, or 1
See Also:
Returns:an AccessibleTextSequence specifying the text if part and index are valid. Otherwise, null is returned.
Since:1.6
/** * Returns the AccessibleTextSequence at a given <code>index</code>. * If <code>direction</code> is non-null this will find the * next/previous word/sentence/character. * * @param part the <code>CHARACTER</code>, <code>WORD</code>, * <code>SENTENCE</code>, <code>LINE</code> or * <code>ATTRIBUTE_RUN</code> to retrieve * @param index an index within the text * @param direction is either -1, 0, or 1 * @return an <code>AccessibleTextSequence</code> specifying the text * if <code>part</code> and <code>index</code> are valid. Otherwise, * <code>null</code> is returned. * * @see javax.accessibility.AccessibleText#CHARACTER * @see javax.accessibility.AccessibleText#WORD * @see javax.accessibility.AccessibleText#SENTENCE * @see javax.accessibility.AccessibleExtendedText#LINE * @see javax.accessibility.AccessibleExtendedText#ATTRIBUTE_RUN * * @since 1.6 */
private AccessibleTextSequence getSequenceAtIndex(int part, int index, int direction) { if (index < 0 || index >= model.getLength()) { return null; } if (direction < -1 || direction > 1) { return null; // direction must be 1, 0, or -1 } switch (part) { case AccessibleText.CHARACTER: if (model instanceof AbstractDocument) { ((AbstractDocument)model).readLock(); } AccessibleTextSequence charSequence = null; try { if (index + direction < model.getLength() && index + direction >= 0) { charSequence = new AccessibleTextSequence(index + direction, index + direction + 1, model.getText(index + direction, 1)); } } catch (BadLocationException e) { // we are intentionally silent; our contract says we return // null if there is any failure in this method } finally { if (model instanceof AbstractDocument) { ((AbstractDocument)model).readUnlock(); } } return charSequence; case AccessibleText.WORD: case AccessibleText.SENTENCE: if (model instanceof AbstractDocument) { ((AbstractDocument)model).readLock(); } AccessibleTextSequence rangeSequence = null; try { IndexedSegment seg = getSegmentAt(part, index); if (seg != null) { if (direction != 0) { int next; if (direction < 0) { next = seg.modelOffset - 1; } else { next = seg.modelOffset + seg.count; } if (next >= 0 && next <= model.getLength()) { seg = getSegmentAt(part, next); } else { seg = null; } } if (seg != null && (seg.offset + seg.count) <= model.getLength()) { rangeSequence = new AccessibleTextSequence (seg.offset, seg.offset + seg.count, new String(seg.array, seg.offset, seg.count)); } // else we leave rangeSequence set to null } } catch(BadLocationException e) { // we are intentionally silent; our contract says we return // null if there is any failure in this method } finally { if (model instanceof AbstractDocument) { ((AbstractDocument)model).readUnlock(); } } return rangeSequence; case AccessibleExtendedText.LINE: AccessibleTextSequence lineSequence = null; if (model instanceof AbstractDocument) { ((AbstractDocument)model).readLock(); } try { int startIndex = Utilities.getRowStart(JTextComponent.this, index); int endIndex = Utilities.getRowEnd(JTextComponent.this, index); if (startIndex >= 0 && endIndex >= startIndex) { if (direction == 0) { lineSequence = new AccessibleTextSequence(startIndex, endIndex, model.getText(startIndex, endIndex - startIndex + 1)); } else if (direction == -1 && startIndex > 0) { endIndex = Utilities.getRowEnd(JTextComponent.this, startIndex - 1); startIndex = Utilities.getRowStart(JTextComponent.this, startIndex - 1); if (startIndex >= 0 && endIndex >= startIndex) { lineSequence = new AccessibleTextSequence(startIndex, endIndex, model.getText(startIndex, endIndex - startIndex + 1)); } } else if (direction == 1 && endIndex < model.getLength()) { startIndex = Utilities.getRowStart(JTextComponent.this, endIndex + 1); endIndex = Utilities.getRowEnd(JTextComponent.this, endIndex + 1); if (startIndex >= 0 && endIndex >= startIndex) { lineSequence = new AccessibleTextSequence(startIndex, endIndex, model.getText(startIndex, endIndex - startIndex + 1)); } } // already validated 'direction' above... } } catch(BadLocationException e) { // we are intentionally silent; our contract says we return // null if there is any failure in this method } finally { if (model instanceof AbstractDocument) { ((AbstractDocument)model).readUnlock(); } } return lineSequence; case AccessibleExtendedText.ATTRIBUTE_RUN: // assumptions: (1) that all characters in a single element // share the same attribute set; (2) that adjacent elements // *may* share the same attribute set int attributeRunStartIndex, attributeRunEndIndex; String runText = null; if (model instanceof AbstractDocument) { ((AbstractDocument)model).readLock(); } try { attributeRunStartIndex = attributeRunEndIndex = Integer.MIN_VALUE; int tempIndex = index; switch (direction) { case -1: // going backwards, so find left edge of this run - // that'll be the end of the previous run // (off-by-one counting) attributeRunEndIndex = getRunEdge(index, direction); // now set ourselves up to find the left edge of the // prev. run tempIndex = attributeRunEndIndex - 1; break; case 1: // going forward, so find right edge of this run - // that'll be the start of the next run // (off-by-one counting) attributeRunStartIndex = getRunEdge(index, direction); // now set ourselves up to find the right edge of the // next run tempIndex = attributeRunStartIndex; break; case 0: // interested in the current run, so nothing special to // set up in advance... break; default: // only those three values of direction allowed... throw new AssertionError(direction); } // set the unset edge; if neither set then we're getting // both edges of the current run around our 'index' attributeRunStartIndex = (attributeRunStartIndex != Integer.MIN_VALUE) ? attributeRunStartIndex : getRunEdge(tempIndex, -1); attributeRunEndIndex = (attributeRunEndIndex != Integer.MIN_VALUE) ? attributeRunEndIndex : getRunEdge(tempIndex, 1); runText = model.getText(attributeRunStartIndex, attributeRunEndIndex - attributeRunStartIndex); } catch (BadLocationException e) { // we are intentionally silent; our contract says we return // null if there is any failure in this method return null; } finally { if (model instanceof AbstractDocument) { ((AbstractDocument)model).readUnlock(); } } return new AccessibleTextSequence(attributeRunStartIndex, attributeRunEndIndex, runText); default: break; } return null; }
Starting at text position index, and going in direction, return the edge of run that shares the same AttributeSet and parent element as those at index. Note: we assume the document is already locked...
/** * Starting at text position <code>index</code>, and going in * <code>direction</code>, return the edge of run that shares the * same <code>AttributeSet</code> and parent element as those at * <code>index</code>. * * Note: we assume the document is already locked... */
private int getRunEdge(int index, int direction) throws BadLocationException { if (index < 0 || index >= model.getLength()) { throw new BadLocationException("Location out of bounds", index); } // locate the Element at index Element indexElement; // locate the Element at our index/offset int elementIndex = -1; // test for initialization for (indexElement = model.getDefaultRootElement(); ! indexElement.isLeaf(); ) { elementIndex = indexElement.getElementIndex(index); indexElement = indexElement.getElement(elementIndex); } if (elementIndex == -1) { throw new AssertionError(index); } // cache the AttributeSet and parentElement atindex AttributeSet indexAS = indexElement.getAttributes(); Element parent = indexElement.getParentElement(); // find the first Element before/after ours w/the same AttributeSet // if we are already at edge of the first element in our parent // then return that edge Element edgeElement; switch (direction) { case -1: case 1: int edgeElementIndex = elementIndex; int elementCount = parent.getElementCount(); while ((edgeElementIndex + direction) > 0 && ((edgeElementIndex + direction) < elementCount) && parent.getElement(edgeElementIndex + direction).getAttributes().isEqual(indexAS)) { edgeElementIndex += direction; } edgeElement = parent.getElement(edgeElementIndex); break; default: throw new AssertionError(direction); } switch (direction) { case -1: return edgeElement.getStartOffset(); case 1: return edgeElement.getEndOffset(); default: // we already caught this case earlier; this is to satisfy // the compiler... return Integer.MIN_VALUE; } } // getTextRange() not needed; defined in AccessibleEditableText
Returns the AccessibleTextSequence at a given index.
Params:
  • part – the CHARACTER, WORD, SENTENCE, LINE or ATTRIBUTE_RUN to retrieve
  • index – an index within the text
See Also:
Returns:an AccessibleTextSequence specifying the text if part and index are valid. Otherwise, null is returned
Since:1.6
/** * Returns the <code>AccessibleTextSequence</code> at a given * <code>index</code>. * * @param part the <code>CHARACTER</code>, <code>WORD</code>, * <code>SENTENCE</code>, <code>LINE</code> or * <code>ATTRIBUTE_RUN</code> to retrieve * @param index an index within the text * @return an <code>AccessibleTextSequence</code> specifying the text if * <code>part</code> and <code>index</code> are valid. Otherwise, * <code>null</code> is returned * * @see javax.accessibility.AccessibleText#CHARACTER * @see javax.accessibility.AccessibleText#WORD * @see javax.accessibility.AccessibleText#SENTENCE * @see javax.accessibility.AccessibleExtendedText#LINE * @see javax.accessibility.AccessibleExtendedText#ATTRIBUTE_RUN * * @since 1.6 */
public AccessibleTextSequence getTextSequenceAt(int part, int index) { return getSequenceAtIndex(part, index, 0); }
Returns the AccessibleTextSequence after a given index.
Params:
  • part – the CHARACTER, WORD, SENTENCE, LINE or ATTRIBUTE_RUN to retrieve
  • index – an index within the text
See Also:
Returns:an AccessibleTextSequence specifying the text if part and index are valid. Otherwise, null is returned
Since:1.6
/** * Returns the <code>AccessibleTextSequence</code> after a given * <code>index</code>. * * @param part the <code>CHARACTER</code>, <code>WORD</code>, * <code>SENTENCE</code>, <code>LINE</code> or * <code>ATTRIBUTE_RUN</code> to retrieve * @param index an index within the text * @return an <code>AccessibleTextSequence</code> specifying the text * if <code>part</code> and <code>index</code> are valid. Otherwise, * <code>null</code> is returned * * @see javax.accessibility.AccessibleText#CHARACTER * @see javax.accessibility.AccessibleText#WORD * @see javax.accessibility.AccessibleText#SENTENCE * @see javax.accessibility.AccessibleExtendedText#LINE * @see javax.accessibility.AccessibleExtendedText#ATTRIBUTE_RUN * * @since 1.6 */
public AccessibleTextSequence getTextSequenceAfter(int part, int index) { return getSequenceAtIndex(part, index, 1); }
Returns the AccessibleTextSequence before a given index.
Params:
  • part – the CHARACTER, WORD, SENTENCE, LINE or ATTRIBUTE_RUN to retrieve
  • index – an index within the text
See Also:
Returns:an AccessibleTextSequence specifying the text if part and index are valid. Otherwise, null is returned
Since:1.6
/** * Returns the <code>AccessibleTextSequence</code> before a given * <code>index</code>. * * @param part the <code>CHARACTER</code>, <code>WORD</code>, * <code>SENTENCE</code>, <code>LINE</code> or * <code>ATTRIBUTE_RUN</code> to retrieve * @param index an index within the text * @return an <code>AccessibleTextSequence</code> specifying the text * if <code>part</code> and <code>index</code> are valid. Otherwise, * <code>null</code> is returned * * @see javax.accessibility.AccessibleText#CHARACTER * @see javax.accessibility.AccessibleText#WORD * @see javax.accessibility.AccessibleText#SENTENCE * @see javax.accessibility.AccessibleExtendedText#LINE * @see javax.accessibility.AccessibleExtendedText#ATTRIBUTE_RUN * * @since 1.6 */
public AccessibleTextSequence getTextSequenceBefore(int part, int index) { return getSequenceAtIndex(part, index, -1); }
Returns the Rectangle enclosing the text between two indicies.
Params:
  • startIndex – the start index in the text
  • endIndex – the end index in the text
Returns:the bounding rectangle of the text if the indices are valid. Otherwise, null is returned
Since:1.6
/** * Returns the <code>Rectangle</code> enclosing the text between * two indicies. * * @param startIndex the start index in the text * @param endIndex the end index in the text * @return the bounding rectangle of the text if the indices are valid. * Otherwise, <code>null</code> is returned * * @since 1.6 */
public Rectangle getTextBounds(int startIndex, int endIndex) { if (startIndex < 0 || startIndex > model.getLength()-1 || endIndex < 0 || endIndex > model.getLength()-1 || startIndex > endIndex) { return null; } TextUI ui = getUI(); if (ui == null) { return null; } Rectangle rect = null; Rectangle alloc = getRootEditorRect(); if (alloc == null) { return null; } if (model instanceof AbstractDocument) { ((AbstractDocument)model).readLock(); } try { View rootView = ui.getRootView(JTextComponent.this); if (rootView != null) { Shape bounds = rootView.modelToView(startIndex, Position.Bias.Forward, endIndex, Position.Bias.Backward, alloc); rect = (bounds instanceof Rectangle) ? (Rectangle)bounds : bounds.getBounds(); } } catch (BadLocationException e) { } finally { if (model instanceof AbstractDocument) { ((AbstractDocument)model).readUnlock(); } } return rect; } // ----- end AccessibleExtendedText methods // --- interface AccessibleAction methods ------------------------ public AccessibleAction getAccessibleAction() { return this; }
Returns the number of accessible actions available in this object If there are more than one, the first one is considered the "default" action of the object.
Returns:the zero-based number of Actions in this object
Since:1.4
/** * Returns the number of accessible actions available in this object * If there are more than one, the first one is considered the * "default" action of the object. * * @return the zero-based number of Actions in this object * @since 1.4 */
public int getAccessibleActionCount() { Action [] actions = JTextComponent.this.getActions(); return actions.length; }
Returns a description of the specified action of the object.
Params:
  • i – zero-based index of the actions
See Also:
Returns:a String description of the action
Since:1.4
/** * Returns a description of the specified action of the object. * * @param i zero-based index of the actions * @return a String description of the action * @see #getAccessibleActionCount * @since 1.4 */
public String getAccessibleActionDescription(int i) { Action [] actions = JTextComponent.this.getActions(); if (i < 0 || i >= actions.length) { return null; } return (String)actions[i].getValue(Action.NAME); }
Performs the specified Action on the object
Params:
  • i – zero-based index of actions
See Also:
Returns:true if the action was performed; otherwise false.
Since:1.4
/** * Performs the specified Action on the object * * @param i zero-based index of actions * @return true if the action was performed; otherwise false. * @see #getAccessibleActionCount * @since 1.4 */
public boolean doAccessibleAction(int i) { Action [] actions = JTextComponent.this.getActions(); if (i < 0 || i >= actions.length) { return false; } ActionEvent ae = new ActionEvent(JTextComponent.this, ActionEvent.ACTION_PERFORMED, null, EventQueue.getMostRecentEventTime(), getCurrentEventModifiers()); actions[i].actionPerformed(ae); return true; } // ----- end AccessibleAction methods } // --- serialization --------------------------------------------- private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { ObjectInputStream.GetField f = s.readFields(); model = (Document) f.get("model", null); navigationFilter = (NavigationFilter) f.get("navigationFilter", null); caretColor = (Color) f.get("caretColor", null); selectionColor = (Color) f.get("selectionColor", null); selectedTextColor = (Color) f.get("selectedTextColor", null); disabledTextColor = (Color) f.get("disabledTextColor", null); editable = f.get("editable", false); margin = (Insets) f.get("margin", null); focusAccelerator = f.get("focusAccelerator", '\0'); boolean newDragEnabled = f.get("dragEnabled", false); checkDragEnabled(newDragEnabled); dragEnabled = newDragEnabled; DropMode newDropMode = (DropMode) f.get("dropMode", DropMode.USE_SELECTION); checkDropMode(newDropMode); dropMode = newDropMode; composedTextAttribute = (SimpleAttributeSet) f.get("composedTextAttribute", null); composedTextContent = (String) f.get("composedTextContent", null); composedTextStart = (Position) f.get("composedTextStart", null); composedTextEnd = (Position) f.get("composedTextEnd", null); latestCommittedTextStart = (Position) f.get("latestCommittedTextStart", null); latestCommittedTextEnd = (Position) f.get("latestCommittedTextEnd", null); composedTextCaret = (ComposedTextCaret) f.get("composedTextCaret", null); checkedInputOverride = f.get("checkedInputOverride", false); needToSendKeyTypedEvent = f.get("needToSendKeyTypedEvent", false); caretEvent = new MutableCaretEvent(this); addMouseListener(caretEvent); addFocusListener(caretEvent); } // --- member variables ----------------------------------
The document model.
/** * The document model. */
private Document model;
The caret used to display the insert position and navigate throughout the document. PENDING(prinz) This should be serializable, default installed by UI.
/** * The caret used to display the insert position * and navigate throughout the document. * * PENDING(prinz) * This should be serializable, default installed * by UI. */
private transient Caret caret;
Object responsible for restricting the cursor navigation.
/** * Object responsible for restricting the cursor navigation. */
private NavigationFilter navigationFilter;
The object responsible for managing highlights. PENDING(prinz) This should be serializable, default installed by UI.
/** * The object responsible for managing highlights. * * PENDING(prinz) * This should be serializable, default installed * by UI. */
private transient Highlighter highlighter;
The current key bindings in effect. PENDING(prinz) This should be serializable, default installed by UI.
/** * The current key bindings in effect. * * PENDING(prinz) * This should be serializable, default installed * by UI. */
private transient Keymap keymap; private transient MutableCaretEvent caretEvent; private Color caretColor; private Color selectionColor; private Color selectedTextColor; private Color disabledTextColor; private boolean editable; private Insets margin; private char focusAccelerator; private boolean dragEnabled;
The drop mode for this component.
/** * The drop mode for this component. */
private DropMode dropMode = DropMode.USE_SELECTION;
The drop location.
/** * The drop location. */
private transient DropLocation dropLocation;
Represents a drop location for JTextComponents.
See Also:
  • getDropLocation
Since:1.6
/** * Represents a drop location for <code>JTextComponent</code>s. * * @see #getDropLocation * @since 1.6 */
public static final class DropLocation extends TransferHandler.DropLocation { private final int index; private final Position.Bias bias; private DropLocation(Point p, int index, Position.Bias bias) { super(p); this.index = index; this.bias = bias; }
Returns the index where dropped data should be inserted into the associated component. This index represents a position between characters, as would be interpreted by a caret.
Returns:the drop index
/** * Returns the index where dropped data should be inserted into the * associated component. This index represents a position between * characters, as would be interpreted by a caret. * * @return the drop index */
public int getIndex() { return index; }
Returns the bias for the drop index.
Returns:the drop bias
/** * Returns the bias for the drop index. * * @return the drop bias */
public Position.Bias getBias() { return bias; }
Returns a string representation of this drop location. This method is intended to be used for debugging purposes, and the content and format of the returned string may vary between implementations.
Returns:a string representation of this drop location
/** * Returns a string representation of this drop location. * This method is intended to be used for debugging purposes, * and the content and format of the returned string may vary * between implementations. * * @return a string representation of this drop location */
public String toString() { return getClass().getName() + "[dropPoint=" + getDropPoint() + "," + "index=" + index + "," + "bias=" + bias + "]"; } }
TransferHandler used if one hasn't been supplied by the UI.
/** * TransferHandler used if one hasn't been supplied by the UI. */
private static DefaultTransferHandler defaultTransferHandler;
Maps from class name to Boolean indicating if processInputMethodEvent has been overriden.
/** * Maps from class name to Boolean indicating if * <code>processInputMethodEvent</code> has been overriden. */
private static Cache<Class<?>,Boolean> METHOD_OVERRIDDEN = new Cache<Class<?>,Boolean>(Cache.Kind.WEAK, Cache.Kind.STRONG) {
Returns true if the specified type extends JTextComponent and the JTextComponent.processInputMethodEvent method is overridden.
/** * Returns {@code true} if the specified {@code type} extends {@link JTextComponent} * and the {@link JTextComponent#processInputMethodEvent} method is overridden. */
@Override public Boolean create(final Class<?> type) { if (JTextComponent.class == type) { return Boolean.FALSE; } if (get(type.getSuperclass())) { return Boolean.TRUE; } return AccessController.doPrivileged( new PrivilegedAction<Boolean>() { public Boolean run() { try { type.getDeclaredMethod("processInputMethodEvent", InputMethodEvent.class); return Boolean.TRUE; } catch (NoSuchMethodException exception) { return Boolean.FALSE; } } }); } };
Returns a string representation of this JTextComponent. This method is intended to be used only for debugging purposes, and the content and format of the returned string may vary between implementations. The returned string may be empty but may not be null.

Overriding paramString to provide information about the specific new aspects of the JFC components.

Returns: a string representation of this JTextComponent
/** * Returns a string representation of this <code>JTextComponent</code>. * This method is intended to be used only for debugging purposes, and the * content and format of the returned string may vary between * implementations. The returned string may be empty but may not * be <code>null</code>. * <P> * Overriding <code>paramString</code> to provide information about the * specific new aspects of the JFC components. * * @return a string representation of this <code>JTextComponent</code> */
protected String paramString() { String editableString = (editable ? "true" : "false"); String caretColorString = (caretColor != null ? caretColor.toString() : ""); String selectionColorString = (selectionColor != null ? selectionColor.toString() : ""); String selectedTextColorString = (selectedTextColor != null ? selectedTextColor.toString() : ""); String disabledTextColorString = (disabledTextColor != null ? disabledTextColor.toString() : ""); String marginString = (margin != null ? margin.toString() : ""); return super.paramString() + ",caretColor=" + caretColorString + ",disabledTextColor=" + disabledTextColorString + ",editable=" + editableString + ",margin=" + marginString + ",selectedTextColor=" + selectedTextColorString + ",selectionColor=" + selectionColorString; }
A Simple TransferHandler that exports the data as a String, and imports the data from the String clipboard. This is only used if the UI hasn't supplied one, which would only happen if someone hasn't subclassed Basic.
/** * A Simple TransferHandler that exports the data as a String, and * imports the data from the String clipboard. This is only used * if the UI hasn't supplied one, which would only happen if someone * hasn't subclassed Basic. */
static class DefaultTransferHandler extends TransferHandler implements UIResource { public void exportToClipboard(JComponent comp, Clipboard clipboard, int action) throws IllegalStateException { if (comp instanceof JTextComponent) { JTextComponent text = (JTextComponent)comp; int p0 = text.getSelectionStart(); int p1 = text.getSelectionEnd(); if (p0 != p1) { try { Document doc = text.getDocument(); String srcData = doc.getText(p0, p1 - p0); StringSelection contents =new StringSelection(srcData); // this may throw an IllegalStateException, // but it will be caught and handled in the // action that invoked this method clipboard.setContents(contents, null); if (action == TransferHandler.MOVE) { doc.remove(p0, p1 - p0); } } catch (BadLocationException ble) {} } } } public boolean importData(JComponent comp, Transferable t) { if (comp instanceof JTextComponent) { DataFlavor flavor = getFlavor(t.getTransferDataFlavors()); if (flavor != null) { InputContext ic = comp.getInputContext(); if (ic != null) { ic.endComposition(); } try { String data = (String)t.getTransferData(flavor); ((JTextComponent)comp).replaceSelection(data); return true; } catch (UnsupportedFlavorException ufe) { } catch (IOException ioe) { } } } return false; } public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) { JTextComponent c = (JTextComponent)comp; if (!(c.isEditable() && c.isEnabled())) { return false; } return (getFlavor(transferFlavors) != null); } public int getSourceActions(JComponent c) { return NONE; } private DataFlavor getFlavor(DataFlavor[] flavors) { if (flavors != null) { for (DataFlavor flavor : flavors) { if (flavor.equals(DataFlavor.stringFlavor)) { return flavor; } } } return null; } }
Returns the JTextComponent that most recently had focus. The returned value may currently have focus.
/** * Returns the JTextComponent that most recently had focus. The returned * value may currently have focus. */
static final JTextComponent getFocusedComponent() { return (JTextComponent)AppContext.getAppContext(). get(FOCUSED_COMPONENT); } @SuppressWarnings("deprecation") private int getCurrentEventModifiers() { int modifiers = 0; AWTEvent currentEvent = EventQueue.getCurrentEvent(); if (currentEvent instanceof InputEvent) { modifiers = ((InputEvent)currentEvent).getModifiers(); } else if (currentEvent instanceof ActionEvent) { modifiers = ((ActionEvent)currentEvent).getModifiers(); } return modifiers; } private static final Object KEYMAP_TABLE = new StringBuilder("JTextComponent_KeymapTable"); // // member variables used for on-the-spot input method // editing style support // private transient InputMethodRequests inputMethodRequestsHandler; private SimpleAttributeSet composedTextAttribute; private String composedTextContent; private Position composedTextStart; private Position composedTextEnd; private Position latestCommittedTextStart; private Position latestCommittedTextEnd; private ComposedTextCaret composedTextCaret; private transient Caret originalCaret;
Set to true after the check for the override of processInputMethodEvent has been checked.
/** * Set to true after the check for the override of processInputMethodEvent * has been checked. */
private boolean checkedInputOverride; private boolean needToSendKeyTypedEvent; static class DefaultKeymap implements Keymap { DefaultKeymap(String nm, Keymap parent) { this.nm = nm; this.parent = parent; bindings = new Hashtable<KeyStroke, Action>(); }
Fetch the default action to fire if a key is typed (ie a KEY_TYPED KeyEvent is received) and there is no binding for it. Typically this would be some action that inserts text so that the keymap doesn't require an action for each possible key.
/** * Fetch the default action to fire if a * key is typed (ie a KEY_TYPED KeyEvent is received) * and there is no binding for it. Typically this * would be some action that inserts text so that * the keymap doesn't require an action for each * possible key. */
public Action getDefaultAction() { if (defaultAction != null) { return defaultAction; } return (parent != null) ? parent.getDefaultAction() : null; }
Set the default action to fire if a key is typed.
/** * Set the default action to fire if a key is typed. */
public void setDefaultAction(Action a) { defaultAction = a; } public String getName() { return nm; } public Action getAction(KeyStroke key) { Action a = bindings.get(key); if ((a == null) && (parent != null)) { a = parent.getAction(key); } return a; } public KeyStroke[] getBoundKeyStrokes() { KeyStroke[] keys = new KeyStroke[bindings.size()]; int i = 0; for (Enumeration<KeyStroke> e = bindings.keys() ; e.hasMoreElements() ;) { keys[i++] = e.nextElement(); } return keys; } public Action[] getBoundActions() { Action[] actions = new Action[bindings.size()]; int i = 0; for (Enumeration<Action> e = bindings.elements() ; e.hasMoreElements() ;) { actions[i++] = e.nextElement(); } return actions; } public KeyStroke[] getKeyStrokesForAction(Action a) { if (a == null) { return null; } KeyStroke[] retValue = null; // Determine local bindings first. Vector<KeyStroke> keyStrokes = null; for (Enumeration<KeyStroke> keys = bindings.keys(); keys.hasMoreElements();) { KeyStroke key = keys.nextElement(); if (bindings.get(key) == a) { if (keyStrokes == null) { keyStrokes = new Vector<KeyStroke>(); } keyStrokes.addElement(key); } } // See if the parent has any. if (parent != null) { KeyStroke[] pStrokes = parent.getKeyStrokesForAction(a); if (pStrokes != null) { // Remove any bindings defined in the parent that // are locally defined. int rCount = 0; for (int counter = pStrokes.length - 1; counter >= 0; counter--) { if (isLocallyDefined(pStrokes[counter])) { pStrokes[counter] = null; rCount++; } } if (rCount > 0 && rCount < pStrokes.length) { if (keyStrokes == null) { keyStrokes = new Vector<KeyStroke>(); } for (int counter = pStrokes.length - 1; counter >= 0; counter--) { if (pStrokes[counter] != null) { keyStrokes.addElement(pStrokes[counter]); } } } else if (rCount == 0) { if (keyStrokes == null) { retValue = pStrokes; } else { retValue = new KeyStroke[keyStrokes.size() + pStrokes.length]; keyStrokes.copyInto(retValue); System.arraycopy(pStrokes, 0, retValue, keyStrokes.size(), pStrokes.length); keyStrokes = null; } } } } if (keyStrokes != null) { retValue = new KeyStroke[keyStrokes.size()]; keyStrokes.copyInto(retValue); } return retValue; } public boolean isLocallyDefined(KeyStroke key) { return bindings.containsKey(key); } public void addActionForKeyStroke(KeyStroke key, Action a) { bindings.put(key, a); } public void removeKeyStrokeBinding(KeyStroke key) { bindings.remove(key); } public void removeBindings() { bindings.clear(); } public Keymap getResolveParent() { return parent; } public void setResolveParent(Keymap parent) { this.parent = parent; }
String representation of the keymap... potentially a very long string.
/** * String representation of the keymap... potentially * a very long string. */
public String toString() { return "Keymap[" + nm + "]" + bindings; } String nm; Keymap parent; Hashtable<KeyStroke, Action> bindings; Action defaultAction; }
KeymapWrapper wraps a Keymap inside an InputMap. For KeymapWrapper to be useful it must be used with a KeymapActionMap. KeymapWrapper for the most part, is an InputMap with two parents. The first parent visited is ALWAYS the Keymap, with the second parent being the parent inherited from InputMap. If keymap.getAction returns null, implying the Keymap does not have a binding for the KeyStroke, the parent is then visited. If the Keymap has a binding, the Action is returned, if not and the KeyStroke represents a KeyTyped event and the Keymap has a defaultAction, DefaultActionKey is returned.

KeymapActionMap is then able to transate the object passed in to either message the Keymap, or message its default implementation.

/** * KeymapWrapper wraps a Keymap inside an InputMap. For KeymapWrapper * to be useful it must be used with a KeymapActionMap. * KeymapWrapper for the most part, is an InputMap with two parents. * The first parent visited is ALWAYS the Keymap, with the second * parent being the parent inherited from InputMap. If * <code>keymap.getAction</code> returns null, implying the Keymap * does not have a binding for the KeyStroke, * the parent is then visited. If the Keymap has a binding, the * Action is returned, if not and the KeyStroke represents a * KeyTyped event and the Keymap has a defaultAction, * <code>DefaultActionKey</code> is returned. * <p>KeymapActionMap is then able to transate the object passed in * to either message the Keymap, or message its default implementation. */
static class KeymapWrapper extends InputMap { static final Object DefaultActionKey = new Object(); private Keymap keymap; KeymapWrapper(Keymap keymap) { this.keymap = keymap; } public KeyStroke[] keys() { KeyStroke[] sKeys = super.keys(); KeyStroke[] keymapKeys = keymap.getBoundKeyStrokes(); int sCount = (sKeys == null) ? 0 : sKeys.length; int keymapCount = (keymapKeys == null) ? 0 : keymapKeys.length; if (sCount == 0) { return keymapKeys; } if (keymapCount == 0) { return sKeys; } KeyStroke[] retValue = new KeyStroke[sCount + keymapCount]; // There may be some duplication here... System.arraycopy(sKeys, 0, retValue, 0, sCount); System.arraycopy(keymapKeys, 0, retValue, sCount, keymapCount); return retValue; } public int size() { // There may be some duplication here... KeyStroke[] keymapStrokes = keymap.getBoundKeyStrokes(); int keymapCount = (keymapStrokes == null) ? 0: keymapStrokes.length; return super.size() + keymapCount; } public Object get(KeyStroke keyStroke) { Object retValue = keymap.getAction(keyStroke); if (retValue == null) { retValue = super.get(keyStroke); if (retValue == null && keyStroke.getKeyChar() != KeyEvent.CHAR_UNDEFINED && keymap.getDefaultAction() != null) { // Implies this is a KeyTyped event, use the default // action. retValue = DefaultActionKey; } } return retValue; } }
Wraps a Keymap inside an ActionMap. This is used with a KeymapWrapper. If get is passed in KeymapWrapper.DefaultActionKey, the default action is returned, otherwise if the key is an Action, it is returned.
/** * Wraps a Keymap inside an ActionMap. This is used with * a KeymapWrapper. If <code>get</code> is passed in * <code>KeymapWrapper.DefaultActionKey</code>, the default action is * returned, otherwise if the key is an Action, it is returned. */
static class KeymapActionMap extends ActionMap { private Keymap keymap; KeymapActionMap(Keymap keymap) { this.keymap = keymap; } public Object[] keys() { Object[] sKeys = super.keys(); Object[] keymapKeys = keymap.getBoundActions(); int sCount = (sKeys == null) ? 0 : sKeys.length; int keymapCount = (keymapKeys == null) ? 0 : keymapKeys.length; boolean hasDefault = (keymap.getDefaultAction() != null); if (hasDefault) { keymapCount++; } if (sCount == 0) { if (hasDefault) { Object[] retValue = new Object[keymapCount]; if (keymapCount > 1) { System.arraycopy(keymapKeys, 0, retValue, 0, keymapCount - 1); } retValue[keymapCount - 1] = KeymapWrapper.DefaultActionKey; return retValue; } return keymapKeys; } if (keymapCount == 0) { return sKeys; } Object[] retValue = new Object[sCount + keymapCount]; // There may be some duplication here... System.arraycopy(sKeys, 0, retValue, 0, sCount); if (hasDefault) { if (keymapCount > 1) { System.arraycopy(keymapKeys, 0, retValue, sCount, keymapCount - 1); } retValue[sCount + keymapCount - 1] = KeymapWrapper. DefaultActionKey; } else { System.arraycopy(keymapKeys, 0, retValue, sCount, keymapCount); } return retValue; } public int size() { // There may be some duplication here... Object[] actions = keymap.getBoundActions(); int keymapCount = (actions == null) ? 0 : actions.length; if (keymap.getDefaultAction() != null) { keymapCount++; } return super.size() + keymapCount; } public Action get(Object key) { Action retValue = super.get(key); if (retValue == null) { // Try the Keymap. if (key == KeymapWrapper.DefaultActionKey) { retValue = keymap.getDefaultAction(); } else if (key instanceof Action) { // This is a little iffy, technically an Action is // a valid Key. We're assuming the Action came from // the InputMap though. retValue = (Action)key; } } return retValue; } } private static final Object FOCUSED_COMPONENT = new StringBuilder("JTextComponent_FocusedComponent");
The default keymap that will be shared by all JTextComponent instances unless they have had a different keymap set.
/** * The default keymap that will be shared by all * <code>JTextComponent</code> instances unless they * have had a different keymap set. */
public static final String DEFAULT_KEYMAP = "default";
Event to use when firing a notification of change to caret position. This is mutable so that the event can be reused since caret events can be fairly high in bandwidth.
/** * Event to use when firing a notification of change to caret * position. This is mutable so that the event can be reused * since caret events can be fairly high in bandwidth. */
static class MutableCaretEvent extends CaretEvent implements ChangeListener, FocusListener, MouseListener { MutableCaretEvent(JTextComponent c) { super(c); } final void fire() { JTextComponent c = (JTextComponent) getSource(); if (c != null) { Caret caret = c.getCaret(); dot = caret.getDot(); mark = caret.getMark(); c.fireCaretUpdate(this); } } public final String toString() { return "dot=" + dot + "," + "mark=" + mark; } // --- CaretEvent methods ----------------------- public final int getDot() { return dot; } public final int getMark() { return mark; } // --- ChangeListener methods ------------------- public final void stateChanged(ChangeEvent e) { if (! dragActive) { fire(); } } // --- FocusListener methods ----------------------------------- public void focusGained(FocusEvent fe) { AppContext.getAppContext().put(FOCUSED_COMPONENT, fe.getSource()); } public void focusLost(FocusEvent fe) { } // --- MouseListener methods -----------------------------------
Requests focus on the associated text component, and try to set the cursor position.
Params:
  • e – the mouse event
See Also:
/** * Requests focus on the associated * text component, and try to set the cursor position. * * @param e the mouse event * @see MouseListener#mousePressed */
public final void mousePressed(MouseEvent e) { dragActive = true; }
Called when the mouse is released.
Params:
  • e – the mouse event
See Also:
/** * Called when the mouse is released. * * @param e the mouse event * @see MouseListener#mouseReleased */
public final void mouseReleased(MouseEvent e) { dragActive = false; fire(); } public final void mouseClicked(MouseEvent e) { } public final void mouseEntered(MouseEvent e) { } public final void mouseExited(MouseEvent e) { } private boolean dragActive; private int dot; private int mark; } // // Process any input method events that the component itself // recognizes. The default on-the-spot handling for input method // composed(uncommitted) text is done here after all input // method listeners get called for stealing the events. // @SuppressWarnings("fallthrough") protected void processInputMethodEvent(InputMethodEvent e) { // let listeners handle the events super.processInputMethodEvent(e); if (!e.isConsumed()) { if (! isEditable()) { return; } else { switch (e.getID()) { case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED: replaceInputMethodText(e); // fall through case InputMethodEvent.CARET_POSITION_CHANGED: setInputMethodCaretPosition(e); break; } } e.consume(); } } // // Overrides this method to become an active input method client. // @BeanProperty(bound = false) public InputMethodRequests getInputMethodRequests() { if (inputMethodRequestsHandler == null) { inputMethodRequestsHandler = new InputMethodRequestsHandler(); Document doc = getDocument(); if (doc != null) { doc.addDocumentListener((DocumentListener)inputMethodRequestsHandler); } } return inputMethodRequestsHandler; } // // Overrides this method to watch the listener installed. // public void addInputMethodListener(InputMethodListener l) { super.addInputMethodListener(l); if (l != null) { needToSendKeyTypedEvent = false; checkedInputOverride = true; } } // // Default implementation of the InputMethodRequests interface. // class InputMethodRequestsHandler implements InputMethodRequests, DocumentListener { // --- InputMethodRequests methods --- public AttributedCharacterIterator cancelLatestCommittedText( Attribute[] attributes) { Document doc = getDocument(); if ((doc != null) && (latestCommittedTextStart != null) && (!latestCommittedTextStart.equals(latestCommittedTextEnd))) { try { int startIndex = latestCommittedTextStart.getOffset(); int endIndex = latestCommittedTextEnd.getOffset(); String latestCommittedText = doc.getText(startIndex, endIndex - startIndex); doc.remove(startIndex, endIndex - startIndex); return new AttributedString(latestCommittedText).getIterator(); } catch (BadLocationException ble) {} } return null; } public AttributedCharacterIterator getCommittedText(int beginIndex, int endIndex, Attribute[] attributes) { int composedStartIndex = 0; int composedEndIndex = 0; if (composedTextExists()) { composedStartIndex = composedTextStart.getOffset(); composedEndIndex = composedTextEnd.getOffset(); } String committed; try { if (beginIndex < composedStartIndex) { if (endIndex <= composedStartIndex) { committed = getText(beginIndex, endIndex - beginIndex); } else { int firstPartLength = composedStartIndex - beginIndex; committed = getText(beginIndex, firstPartLength) + getText(composedEndIndex, endIndex - beginIndex - firstPartLength); } } else { committed = getText(beginIndex + (composedEndIndex - composedStartIndex), endIndex - beginIndex); } } catch (BadLocationException ble) { throw new IllegalArgumentException("Invalid range"); } return new AttributedString(committed).getIterator(); } public int getCommittedTextLength() { Document doc = getDocument(); int length = 0; if (doc != null) { length = doc.getLength(); if (composedTextContent != null) { if (composedTextEnd == null || composedTextStart == null) { /* * fix for : 6355666 * this is the case when this method is invoked * from DocumentListener. At this point * composedTextEnd and composedTextStart are * not defined yet. */ length -= composedTextContent.length(); } else { length -= composedTextEnd.getOffset() - composedTextStart.getOffset(); } } } return length; } public int getInsertPositionOffset() { int composedStartIndex = 0; int composedEndIndex = 0; if (composedTextExists()) { composedStartIndex = composedTextStart.getOffset(); composedEndIndex = composedTextEnd.getOffset(); } int caretIndex = getCaretPosition(); if (caretIndex < composedStartIndex) { return caretIndex; } else if (caretIndex < composedEndIndex) { return composedStartIndex; } else { return caretIndex - (composedEndIndex - composedStartIndex); } } public TextHitInfo getLocationOffset(int x, int y) { if (composedTextAttribute == null) { return null; } else { Point p = getLocationOnScreen(); p.x = x - p.x; p.y = y - p.y; int pos = viewToModel(p); if ((pos >= composedTextStart.getOffset()) && (pos <= composedTextEnd.getOffset())) { return TextHitInfo.leading(pos - composedTextStart.getOffset()); } else { return null; } } } public Rectangle getTextLocation(TextHitInfo offset) { Rectangle r; try { r = modelToView(getCaretPosition()); if (r != null) { Point p = getLocationOnScreen(); r.translate(p.x, p.y); } } catch (BadLocationException ble) { r = null; } if (r == null) r = new Rectangle(); return r; } public AttributedCharacterIterator getSelectedText( Attribute[] attributes) { String selection = JTextComponent.this.getSelectedText(); if (selection != null) { return new AttributedString(selection).getIterator(); } else { return null; } } // --- DocumentListener methods --- public void changedUpdate(DocumentEvent e) { latestCommittedTextStart = latestCommittedTextEnd = null; } public void insertUpdate(DocumentEvent e) { latestCommittedTextStart = latestCommittedTextEnd = null; } public void removeUpdate(DocumentEvent e) { latestCommittedTextStart = latestCommittedTextEnd = null; } } // // Replaces the current input method (composed) text according to // the passed input method event. This method also inserts the // committed text into the document. // private void replaceInputMethodText(InputMethodEvent e) { int commitCount = e.getCommittedCharacterCount(); AttributedCharacterIterator text = e.getText(); int composedTextIndex; // old composed text deletion Document doc = getDocument(); if (composedTextExists()) { try { doc.remove(composedTextStart.getOffset(), composedTextEnd.getOffset() - composedTextStart.getOffset()); } catch (BadLocationException ble) {} composedTextStart = composedTextEnd = null; composedTextAttribute = null; composedTextContent = null; } if (text != null) { text.first(); int committedTextStartIndex = 0; int committedTextEndIndex = 0; // committed text insertion if (commitCount > 0) { // Remember latest committed text start index committedTextStartIndex = caret.getDot(); // Need to generate KeyTyped events for the committed text for components // that are not aware they are active input method clients. if (shouldSynthensizeKeyEvents()) { for (char c = text.current(); commitCount > 0; c = text.next(), commitCount--) { KeyEvent ke = new KeyEvent(this, KeyEvent.KEY_TYPED, EventQueue.getMostRecentEventTime(), 0, KeyEvent.VK_UNDEFINED, c); processKeyEvent(ke); } } else { StringBuilder strBuf = new StringBuilder(); for (char c = text.current(); commitCount > 0; c = text.next(), commitCount--) { strBuf.append(c); } // map it to an ActionEvent mapCommittedTextToAction(strBuf.toString()); } // Remember latest committed text end index committedTextEndIndex = caret.getDot(); } // new composed text insertion composedTextIndex = text.getIndex(); if (composedTextIndex < text.getEndIndex()) { createComposedTextAttribute(composedTextIndex, text); try { replaceSelection(null); doc.insertString(caret.getDot(), composedTextContent, composedTextAttribute); composedTextStart = doc.createPosition(caret.getDot() - composedTextContent.length()); composedTextEnd = doc.createPosition(caret.getDot()); } catch (BadLocationException ble) { composedTextStart = composedTextEnd = null; composedTextAttribute = null; composedTextContent = null; } } // Save the latest committed text information if (committedTextStartIndex != committedTextEndIndex) { try { latestCommittedTextStart = doc. createPosition(committedTextStartIndex); latestCommittedTextEnd = doc. createPosition(committedTextEndIndex); } catch (BadLocationException ble) { latestCommittedTextStart = latestCommittedTextEnd = null; } } else { latestCommittedTextStart = latestCommittedTextEnd = null; } } } private void createComposedTextAttribute(int composedIndex, AttributedCharacterIterator text) { Document doc = getDocument(); StringBuilder strBuf = new StringBuilder(); // create attributed string with no attributes for (char c = text.setIndex(composedIndex); c != CharacterIterator.DONE; c = text.next()) { strBuf.append(c); } composedTextContent = strBuf.toString(); composedTextAttribute = new SimpleAttributeSet(); composedTextAttribute.addAttribute(StyleConstants.ComposedTextAttribute, new AttributedString(text, composedIndex, text.getEndIndex())); }
Saves composed text around the specified position. The composed text (if any) around the specified position is saved in a backing store and removed from the document.
Params:
  • pos – document position to identify the composed text location
See Also:
Returns: true if the composed text exists and is saved, false otherwise
Since:1.7
/** * Saves composed text around the specified position. * * The composed text (if any) around the specified position is saved * in a backing store and removed from the document. * * @param pos document position to identify the composed text location * @return {@code true} if the composed text exists and is saved, * {@code false} otherwise * @see #restoreComposedText * @since 1.7 */
protected boolean saveComposedText(int pos) { if (composedTextExists()) { int start = composedTextStart.getOffset(); int len = composedTextEnd.getOffset() - composedTextStart.getOffset(); if (pos >= start && pos <= start + len) { try { getDocument().remove(start, len); return true; } catch (BadLocationException ble) {} } } return false; }
Restores composed text previously saved by saveComposedText. The saved composed text is inserted back into the document. This method should be invoked only if saveComposedText returns true.
See Also:
Since:1.7
/** * Restores composed text previously saved by {@code saveComposedText}. * * The saved composed text is inserted back into the document. This method * should be invoked only if {@code saveComposedText} returns {@code true}. * * @see #saveComposedText * @since 1.7 */
protected void restoreComposedText() { Document doc = getDocument(); try { doc.insertString(caret.getDot(), composedTextContent, composedTextAttribute); composedTextStart = doc.createPosition(caret.getDot() - composedTextContent.length()); composedTextEnd = doc.createPosition(caret.getDot()); } catch (BadLocationException ble) {} } // // Map committed text to an ActionEvent. If the committed text length is 1, // treat it as a KeyStroke, otherwise or there is no KeyStroke defined, // treat it just as a default action. // private void mapCommittedTextToAction(String committedText) { Keymap binding = getKeymap(); if (binding != null) { Action a = null; if (committedText.length() == 1) { KeyStroke k = KeyStroke.getKeyStroke(committedText.charAt(0)); a = binding.getAction(k); } if (a == null) { a = binding.getDefaultAction(); } if (a != null) { ActionEvent ae = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, committedText, EventQueue.getMostRecentEventTime(), getCurrentEventModifiers()); a.actionPerformed(ae); } } } // // Sets the caret position according to the passed input method // event. Also, sets/resets composed text caret appropriately. // private void setInputMethodCaretPosition(InputMethodEvent e) { int dot; if (composedTextExists()) { dot = composedTextStart.getOffset(); if (!(caret instanceof ComposedTextCaret)) { if (composedTextCaret == null) { composedTextCaret = new ComposedTextCaret(); } originalCaret = caret; // Sets composed text caret exchangeCaret(originalCaret, composedTextCaret); } TextHitInfo caretPos = e.getCaret(); if (caretPos != null) { int index = caretPos.getInsertionIndex(); dot += index; if (index == 0) { // Scroll the component if needed so that the composed text // becomes visible. try { Rectangle d = modelToView(dot); Rectangle end = modelToView(composedTextEnd.getOffset()); Rectangle b = getBounds(); d.x += Math.min(end.x - d.x, b.width); scrollRectToVisible(d); } catch (BadLocationException ble) {} } } caret.setDot(dot); } else if (caret instanceof ComposedTextCaret) { dot = caret.getDot(); // Restores original caret exchangeCaret(caret, originalCaret); caret.setDot(dot); } } private void exchangeCaret(Caret oldCaret, Caret newCaret) { int blinkRate = oldCaret.getBlinkRate(); setCaret(newCaret); caret.setBlinkRate(blinkRate); caret.setVisible(hasFocus()); }
Returns true if KeyEvents should be synthesized from an InputEvent.
/** * Returns true if KeyEvents should be synthesized from an InputEvent. */
private boolean shouldSynthensizeKeyEvents() { if (!checkedInputOverride) { // Checks whether the client code overrides processInputMethodEvent. // If it is overridden, need not to generate KeyTyped events for committed text. // If it's not, behave as an passive input method client. needToSendKeyTypedEvent = !METHOD_OVERRIDDEN.get(getClass()); checkedInputOverride = true; } return needToSendKeyTypedEvent; } // // Checks whether a composed text in this text component // boolean composedTextExists() { return (composedTextStart != null); } // // Caret implementation for editing the composed text. // class ComposedTextCaret extends DefaultCaret implements Serializable { Color bg; // // Get the background color of the component // public void install(JTextComponent c) { super.install(c); Document doc = c.getDocument(); if (doc instanceof StyledDocument) { StyledDocument sDoc = (StyledDocument)doc; Element elem = sDoc.getCharacterElement(c.composedTextStart.getOffset()); AttributeSet attr = elem.getAttributes(); bg = sDoc.getBackground(attr); } if (bg == null) { bg = c.getBackground(); } } // // Draw caret in XOR mode. // public void paint(Graphics g) { if(isVisible()) { try { Rectangle r = component.modelToView(getDot()); g.setXORMode(bg); g.drawLine(r.x, r.y, r.x, r.y + r.height - 1); g.setPaintMode(); } catch (BadLocationException e) { // can't render I guess //System.err.println("Can't render cursor"); } } } // // If some area other than the composed text is clicked by mouse, // issue endComposition() to force commit the composed text. // protected void positionCaret(MouseEvent me) { JTextComponent host = component; Point pt = new Point(me.getX(), me.getY()); int offset = host.viewToModel(pt); int composedStartIndex = host.composedTextStart.getOffset(); if ((offset < composedStartIndex) || (offset > composedTextEnd.getOffset())) { try { // Issue endComposition Position newPos = host.getDocument().createPosition(offset); host.getInputContext().endComposition(); // Post a caret positioning runnable to assure that the positioning // occurs *after* committing the composed text. EventQueue.invokeLater(new DoSetCaretPosition(host, newPos)); } catch (BadLocationException ble) { System.err.println(ble); } } else { // Normal processing super.positionCaret(me); } } } // // Runnable class for invokeLater() to set caret position later. // private class DoSetCaretPosition implements Runnable { JTextComponent host; Position newPos; DoSetCaretPosition(JTextComponent host, Position newPos) { this.host = host; this.newPos = newPos; } public void run() { host.setCaretPosition(newPos.getOffset()); } } }