/*
* Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.awt;
import java.awt.peer.
TextComponentPeer;
import java.awt.event.*;
import java.util.
EventListener;
import java.io.
ObjectOutputStream;
import java.io.
ObjectInputStream;
import java.io.
IOException;
import sun.awt.
InputMethodSupport;
import java.text.
BreakIterator;
import javax.swing.text.
AttributeSet;
import javax.accessibility.*;
import java.awt.im.
InputMethodRequests;
import sun.security.util.
SecurityConstants;
/**
* The <code>TextComponent</code> class is the superclass of
* any component that allows the editing of some text.
* <p>
* A text component embodies a string of text. The
* <code>TextComponent</code> class defines a set of methods
* that determine whether or not this text is editable. If the
* component is editable, it defines another set of methods
* that supports a text insertion caret.
* <p>
* In addition, the class defines methods that are used
* to maintain a current <em>selection</em> from the text.
* The text selection, a substring of the component's text,
* is the target of editing operations. It is also referred
* to as the <em>selected text</em>.
*
* @author Sami Shaio
* @author Arthur van Hoff
* @since JDK1.0
*/
public class
TextComponent extends
Component implements
Accessible {
/**
* The value of the text.
* A <code>null</code> value is the same as "".
*
* @serial
* @see #setText(String)
* @see #getText()
*/
String text;
/**
* A boolean indicating whether or not this
* <code>TextComponent</code> is editable.
* It will be <code>true</code> if the text component
* is editable and <code>false</code> if not.
*
* @serial
* @see #isEditable()
*/
boolean
editable = true;
/**
* The selection refers to the selected text, and the
* <code>selectionStart</code> is the start position
* of the selected text.
*
* @serial
* @see #getSelectionStart()
* @see #setSelectionStart(int)
*/
int
selectionStart;
/**
* The selection refers to the selected text, and the
* <code>selectionEnd</code>
* is the end position of the selected text.
*
* @serial
* @see #getSelectionEnd()
* @see #setSelectionEnd(int)
*/
int
selectionEnd;
// A flag used to tell whether the background has been set by
// developer code (as opposed to AWT code). Used to determine
// the background color of non-editable TextComponents.
boolean
backgroundSetByClientCode = false;
transient protected
TextListener textListener;
/*
* JDK 1.1 serialVersionUID
*/
private static final long
serialVersionUID = -2214773872412987419L;
/**
* Constructs a new text component initialized with the
* specified text. Sets the value of the cursor to
* <code>Cursor.TEXT_CURSOR</code>.
* @param text the text to be displayed; if
* <code>text</code> is <code>null</code>, the empty
* string <code>""</code> will be displayed
* @exception HeadlessException if
* <code>GraphicsEnvironment.isHeadless</code>
* returns true
* @see java.awt.GraphicsEnvironment#isHeadless
* @see java.awt.Cursor
*/
TextComponent(
String text) throws
HeadlessException {
GraphicsEnvironment.
checkHeadless();
this.
text = (
text != null) ?
text : "";
setCursor(
Cursor.
getPredefinedCursor(
Cursor.
TEXT_CURSOR));
}
private void
enableInputMethodsIfNecessary() {
if (
checkForEnableIM) {
checkForEnableIM = false;
try {
Toolkit toolkit =
Toolkit.
getDefaultToolkit();
boolean
shouldEnable = false;
if (
toolkit instanceof
InputMethodSupport) {
shouldEnable = ((
InputMethodSupport)
toolkit)
.
enableInputMethodsForTextComponent();
}
enableInputMethods(
shouldEnable);
} catch (
Exception e) {
// if something bad happens, just don't enable input methods
}
}
}
/**
* Enables or disables input method support for this text component. If input
* method support is enabled and the text component also processes key events,
* incoming events are offered to the current input method and will only be
* processed by the component or dispatched to its listeners if the input method
* does not consume them. Whether and how input method support for this text
* component is enabled or disabled by default is implementation dependent.
*
* @param enable true to enable, false to disable
* @see #processKeyEvent
* @since 1.2
*/
public void
enableInputMethods(boolean
enable) {
checkForEnableIM = false;
super.enableInputMethods(
enable);
}
boolean
areInputMethodsEnabled() {
// moved from the constructor above to here and addNotify below,
// this call will initialize the toolkit if not already initialized.
if (
checkForEnableIM) {
enableInputMethodsIfNecessary();
}
// TextComponent handles key events without touching the eventMask or
// having a key listener, so just check whether the flag is set
return (
eventMask &
AWTEvent.
INPUT_METHODS_ENABLED_MASK) != 0;
}
public
InputMethodRequests getInputMethodRequests() {
TextComponentPeer peer = (
TextComponentPeer)this.
peer;
if (
peer != null) return
peer.
getInputMethodRequests();
else return null;
}
/**
* Makes this Component displayable by connecting it to a
* native screen resource.
* This method is called internally by the toolkit and should
* not be called directly by programs.
* @see java.awt.TextComponent#removeNotify
*/
public void
addNotify() {
super.addNotify();
enableInputMethodsIfNecessary();
}
/**
* Removes the <code>TextComponent</code>'s peer.
* The peer allows us to modify the appearance of the
* <code>TextComponent</code> without changing its
* functionality.
*/
public void
removeNotify() {
synchronized (
getTreeLock()) {
TextComponentPeer peer = (
TextComponentPeer)this.
peer;
if (
peer != null) {
text =
peer.
getText();
selectionStart =
peer.
getSelectionStart();
selectionEnd =
peer.
getSelectionEnd();
}
super.removeNotify();
}
}
/**
* Sets the text that is presented by this
* text component to be the specified text.
* @param t the new text;
* if this parameter is <code>null</code> then
* the text is set to the empty string ""
* @see java.awt.TextComponent#getText
*/
public synchronized void
setText(
String t) {
boolean
skipTextEvent = (
text == null ||
text.
isEmpty())
&& (
t == null ||
t.
isEmpty());
text = (
t != null) ?
t : "";
TextComponentPeer peer = (
TextComponentPeer)this.
peer;
// Please note that we do not want to post an event
// if TextArea.setText() or TextField.setText() replaces an empty text
// by an empty text, that is, if component's text remains unchanged.
if (
peer != null && !
skipTextEvent) {
peer.
setText(
text);
}
}
/**
* Returns the text that is presented by this text component.
* By default, this is an empty string.
*
* @return the value of this <code>TextComponent</code>
* @see java.awt.TextComponent#setText
*/
public synchronized
String getText() {
TextComponentPeer peer = (
TextComponentPeer)this.
peer;
if (
peer != null) {
text =
peer.
getText();
}
return
text;
}
/**
* Returns the selected text from the text that is
* presented by this text component.
* @return the selected text of this text component
* @see java.awt.TextComponent#select
*/
public synchronized
String getSelectedText() {
return
getText().
substring(
getSelectionStart(),
getSelectionEnd());
}
/**
* Indicates whether or not this text component is editable.
* @return <code>true</code> if this text component is
* editable; <code>false</code> otherwise.
* @see java.awt.TextComponent#setEditable
* @since JDK1.0
*/
public boolean
isEditable() {
return
editable;
}
/**
* Sets the flag that determines whether or not this
* text component is editable.
* <p>
* If the flag is set to <code>true</code>, this text component
* becomes user editable. If the flag is set to <code>false</code>,
* the user cannot change the text of this text component.
* By default, non-editable text components have a background color
* of SystemColor.control. This default can be overridden by
* calling setBackground.
*
* @param b a flag indicating whether this text component
* is user editable.
* @see java.awt.TextComponent#isEditable
* @since JDK1.0
*/
public synchronized void
setEditable(boolean
b) {
if (
editable ==
b) {
return;
}
editable =
b;
TextComponentPeer peer = (
TextComponentPeer)this.
peer;
if (
peer != null) {
peer.
setEditable(
b);
}
}
/**
* Gets the background color of this text component.
*
* By default, non-editable text components have a background color
* of SystemColor.control. This default can be overridden by
* calling setBackground.
*
* @return This text component's background color.
* If this text component does not have a background color,
* the background color of its parent is returned.
* @see #setBackground(Color)
* @since JDK1.0
*/
public
Color getBackground() {
if (!
editable && !
backgroundSetByClientCode) {
return
SystemColor.
control;
}
return super.getBackground();
}
/**
* Sets the background color of this text component.
*
* @param c The color to become this text component's color.
* If this parameter is null then this text component
* will inherit the background color of its parent.
* @see #getBackground()
* @since JDK1.0
*/
public void
setBackground(
Color c) {
backgroundSetByClientCode = true;
super.setBackground(
c);
}
/**
* Gets the start position of the selected text in
* this text component.
* @return the start position of the selected text
* @see java.awt.TextComponent#setSelectionStart
* @see java.awt.TextComponent#getSelectionEnd
*/
public synchronized int
getSelectionStart() {
TextComponentPeer peer = (
TextComponentPeer)this.
peer;
if (
peer != null) {
selectionStart =
peer.
getSelectionStart();
}
return
selectionStart;
}
/**
* Sets the selection start for this text component to
* the specified position. The new start point is constrained
* to be at or before the current selection end. It also
* cannot be set to less than zero, the beginning of the
* component's text.
* If the caller supplies a value for <code>selectionStart</code>
* that is out of bounds, the method enforces these constraints
* silently, and without failure.
* @param selectionStart the start position of the
* selected text
* @see java.awt.TextComponent#getSelectionStart
* @see java.awt.TextComponent#setSelectionEnd
* @since JDK1.1
*/
public synchronized void
setSelectionStart(int
selectionStart) {
/* Route through select method to enforce consistent policy
* between selectionStart and selectionEnd.
*/
select(
selectionStart,
getSelectionEnd());
}
/**
* Gets the end position of the selected text in
* this text component.
* @return the end position of the selected text
* @see java.awt.TextComponent#setSelectionEnd
* @see java.awt.TextComponent#getSelectionStart
*/
public synchronized int
getSelectionEnd() {
TextComponentPeer peer = (
TextComponentPeer)this.
peer;
if (
peer != null) {
selectionEnd =
peer.
getSelectionEnd();
}
return
selectionEnd;
}
/**
* Sets the selection end for this text component to
* the specified position. The new end point is constrained
* to be at or after the current selection start. It also
* cannot be set beyond the end of the component's text.
* If the caller supplies a value for <code>selectionEnd</code>
* that is out of bounds, the method enforces these constraints
* silently, and without failure.
* @param selectionEnd the end position of the
* selected text
* @see java.awt.TextComponent#getSelectionEnd
* @see java.awt.TextComponent#setSelectionStart
* @since JDK1.1
*/
public synchronized 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.
* <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. The
* character positions are indexed starting with zero.
* The length of the selection is
* <code>endPosition</code> - <code>startPosition</code>, so the
* character at <code>endPosition</code> is not selected.
* If the start and end positions of the selected text are equal,
* all text is deselected.
* <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.
*
* @param selectionStart the zero-based index of the first
character (<code>char</code> value) to be selected
* @param selectionEnd the zero-based end position of the
text to be selected; the character (<code>char</code> value) at
<code>selectionEnd</code> is not selected
* @see java.awt.TextComponent#setSelectionStart
* @see java.awt.TextComponent#setSelectionEnd
* @see java.awt.TextComponent#selectAll
*/
public synchronized void
select(int
selectionStart, int
selectionEnd) {
String text =
getText();
if (
selectionStart < 0) {
selectionStart = 0;
}
if (
selectionStart >
text.
length()) {
selectionStart =
text.
length();
}
if (
selectionEnd >
text.
length()) {
selectionEnd =
text.
length();
}
if (
selectionEnd <
selectionStart) {
selectionEnd =
selectionStart;
}
this.
selectionStart =
selectionStart;
this.
selectionEnd =
selectionEnd;
TextComponentPeer peer = (
TextComponentPeer)this.
peer;
if (
peer != null) {
peer.
select(
selectionStart,
selectionEnd);
}
}
/**
* Selects all the text in this text component.
* @see java.awt.TextComponent#select
*/
public synchronized void
selectAll() {
this.
selectionStart = 0;
this.
selectionEnd =
getText().
length();
TextComponentPeer peer = (
TextComponentPeer)this.
peer;
if (
peer != null) {
peer.
select(
selectionStart,
selectionEnd);
}
}
/**
* Sets the position of the text insertion caret.
* The caret position is constrained to be between 0
* and the last character of the text, inclusive.
* If the passed-in value is greater than this range,
* the value is set to the last character (or 0 if
* the <code>TextComponent</code> contains no text)
* and no error is returned. If the passed-in value is
* less than 0, an <code>IllegalArgumentException</code>
* is thrown.
*
* @param position the position of the text insertion caret
* @exception IllegalArgumentException if <code>position</code>
* is less than zero
* @since JDK1.1
*/
public synchronized void
setCaretPosition(int
position) {
if (
position < 0) {
throw new
IllegalArgumentException("position less than zero.");
}
int
maxposition =
getText().
length();
if (
position >
maxposition) {
position =
maxposition;
}
TextComponentPeer peer = (
TextComponentPeer)this.
peer;
if (
peer != null) {
peer.
setCaretPosition(
position);
} else {
select(
position,
position);
}
}
/**
* Returns the position of the text insertion caret.
* The caret position is constrained to be between 0
* and the last character of the text, inclusive.
* If the text or caret have not been set, the default
* caret position is 0.
*
* @return the position of the text insertion caret
* @see #setCaretPosition(int)
* @since JDK1.1
*/
public synchronized int
getCaretPosition() {
TextComponentPeer peer = (
TextComponentPeer)this.
peer;
int
position = 0;
if (
peer != null) {
position =
peer.
getCaretPosition();
} else {
position =
selectionStart;
}
int
maxposition =
getText().
length();
if (
position >
maxposition) {
position =
maxposition;
}
return
position;
}
/**
* Adds the specified text event listener to receive text events
* from this text component.
* If <code>l</code> is <code>null</code>, no exception is
* thrown and no action is performed.
* <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
* >AWT Threading Issues</a> for details on AWT's threading model.
*
* @param l the text event listener
* @see #removeTextListener
* @see #getTextListeners
* @see java.awt.event.TextListener
*/
public synchronized void
addTextListener(
TextListener l) {
if (
l == null) {
return;
}
textListener =
AWTEventMulticaster.
add(
textListener,
l);
newEventsOnly = true;
}
/**
* Removes the specified text event listener so that it no longer
* receives text events from this text component
* If <code>l</code> is <code>null</code>, no exception is
* thrown and no action is performed.
* <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
* >AWT Threading Issues</a> for details on AWT's threading model.
*
* @param l the text listener
* @see #addTextListener
* @see #getTextListeners
* @see java.awt.event.TextListener
* @since JDK1.1
*/
public synchronized void
removeTextListener(
TextListener l) {
if (
l == null) {
return;
}
textListener =
AWTEventMulticaster.
remove(
textListener,
l);
}
/**
* Returns an array of all the text listeners
* registered on this text component.
*
* @return all of this text component's <code>TextListener</code>s
* or an empty array if no text
* listeners are currently registered
*
*
* @see #addTextListener
* @see #removeTextListener
* @since 1.4
*/
public synchronized
TextListener[]
getTextListeners() {
return
getListeners(
TextListener.class);
}
/**
* Returns an array of all the objects currently registered
* as <code><em>Foo</em>Listener</code>s
* upon this <code>TextComponent</code>.
* <code><em>Foo</em>Listener</code>s are registered using the
* <code>add<em>Foo</em>Listener</code> method.
*
* <p>
* You can specify the <code>listenerType</code> argument
* with a class literal, such as
* <code><em>Foo</em>Listener.class</code>.
* For example, you can query a
* <code>TextComponent</code> <code>t</code>
* for its text listeners with the following code:
*
* <pre>TextListener[] tls = (TextListener[])(t.getListeners(TextListener.class));</pre>
*
* If no such listeners exist, this method returns an empty array.
*
* @param listenerType the type of listeners requested; this parameter
* should specify an interface that descends from
* <code>java.util.EventListener</code>
* @return an array of all objects registered as
* <code><em>Foo</em>Listener</code>s on this text component,
* or an empty array if no such
* listeners have been added
* @exception ClassCastException if <code>listenerType</code>
* doesn't specify a class or interface that implements
* <code>java.util.EventListener</code>
*
* @see #getTextListeners
* @since 1.3
*/
public <T extends
EventListener> T[]
getListeners(
Class<T>
listenerType) {
EventListener l = null;
if (
listenerType ==
TextListener.class) {
l =
textListener;
} else {
return super.getListeners(
listenerType);
}
return
AWTEventMulticaster.
getListeners(
l,
listenerType);
}
// REMIND: remove when filtering is done at lower level
boolean
eventEnabled(
AWTEvent e) {
if (
e.
id ==
TextEvent.
TEXT_VALUE_CHANGED) {
if ((
eventMask &
AWTEvent.
TEXT_EVENT_MASK) != 0 ||
textListener != null) {
return true;
}
return false;
}
return super.eventEnabled(
e);
}
/**
* Processes events on this text component. If the event is a
* <code>TextEvent</code>, it invokes the <code>processTextEvent</code>
* method else it invokes its superclass's <code>processEvent</code>.
* <p>Note that if the event parameter is <code>null</code>
* the behavior is unspecified and may result in an
* exception.
*
* @param e the event
*/
protected void
processEvent(
AWTEvent e) {
if (
e instanceof
TextEvent) {
processTextEvent((
TextEvent)
e);
return;
}
super.processEvent(
e);
}
/**
* Processes text events occurring on this text component by
* dispatching them to any registered <code>TextListener</code> objects.
* <p>
* NOTE: This method will not be called unless text events
* are enabled for this component. This happens when one of the
* following occurs:
* <ul>
* <li>A <code>TextListener</code> object is registered
* via <code>addTextListener</code>
* <li>Text events are enabled via <code>enableEvents</code>
* </ul>
* <p>Note that if the event parameter is <code>null</code>
* the behavior is unspecified and may result in an
* exception.
*
* @param e the text event
* @see Component#enableEvents
*/
protected void
processTextEvent(
TextEvent e) {
TextListener listener =
textListener;
if (
listener != null) {
int
id =
e.
getID();
switch (
id) {
case
TextEvent.
TEXT_VALUE_CHANGED:
listener.
textValueChanged(
e);
break;
}
}
}
/**
* Returns a string representing the state of this
* <code>TextComponent</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>.
*
* @return the parameter string of this text component
*/
protected
String paramString() {
String str = super.paramString() + ",text=" +
getText();
if (
editable) {
str += ",editable";
}
return
str + ",selection=" +
getSelectionStart() + "-" +
getSelectionEnd();
}
/**
* Assigns a valid value to the canAccessClipboard instance variable.
*/
private boolean
canAccessClipboard() {
SecurityManager sm =
System.
getSecurityManager();
if (
sm == null) return true;
try {
sm.
checkPermission(
SecurityConstants.
AWT.
ACCESS_CLIPBOARD_PERMISSION);
return true;
} catch (
SecurityException e) {}
return false;
}
/*
* Serialization support.
*/
/**
* The textComponent SerializedDataVersion.
*
* @serial
*/
private int
textComponentSerializedDataVersion = 1;
/**
* Writes default serializable fields to stream. Writes
* a list of serializable TextListener(s) as optional data.
* The non-serializable TextListener(s) are detected and
* no attempt is made to serialize them.
*
* @serialData Null terminated sequence of zero or more pairs.
* A pair consists of a String and Object.
* The String indicates the type of object and
* is one of the following :
* textListenerK indicating and TextListener object.
*
* @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)
* @see java.awt.Component#textListenerK
*/
private void
writeObject(java.io.
ObjectOutputStream s)
throws
IOException
{
// Serialization support. Since the value of the fields
// selectionStart, selectionEnd, and text aren't necessarily
// up to date, we sync them up with the peer before serializing.
TextComponentPeer peer = (
TextComponentPeer)this.
peer;
if (
peer != null) {
text =
peer.
getText();
selectionStart =
peer.
getSelectionStart();
selectionEnd =
peer.
getSelectionEnd();
}
s.
defaultWriteObject();
AWTEventMulticaster.
save(
s,
textListenerK,
textListener);
s.
writeObject(null);
}
/**
* Read the ObjectInputStream, and if it isn't null,
* add a listener to receive text events fired by the
* TextComponent. Unrecognized keys or values will be
* ignored.
*
* @exception HeadlessException if
* <code>GraphicsEnvironment.isHeadless()</code> returns
* <code>true</code>
* @see #removeTextListener
* @see #addTextListener
* @see java.awt.GraphicsEnvironment#isHeadless
*/
private void
readObject(
ObjectInputStream s)
throws
ClassNotFoundException,
IOException,
HeadlessException
{
GraphicsEnvironment.
checkHeadless();
s.
defaultReadObject();
// Make sure the state we just read in for text,
// selectionStart and selectionEnd has legal values
this.
text = (
text != null) ?
text : "";
select(
selectionStart,
selectionEnd);
Object keyOrNull;
while(null != (
keyOrNull =
s.
readObject())) {
String key = ((
String)
keyOrNull).
intern();
if (
textListenerK ==
key) {
addTextListener((
TextListener)(
s.
readObject()));
} else {
// skip value for unrecognized key
s.
readObject();
}
}
enableInputMethodsIfNecessary();
}
/////////////////
// Accessibility support
////////////////
/**
* Gets the AccessibleContext associated with this TextComponent.
* For text components, the AccessibleContext takes the form of an
* AccessibleAWTTextComponent.
* A new AccessibleAWTTextComponent instance is created if necessary.
*
* @return an AccessibleAWTTextComponent that serves as the
* AccessibleContext of this TextComponent
* @since 1.3
*/
public
AccessibleContext getAccessibleContext() {
if (
accessibleContext == null) {
accessibleContext = new
AccessibleAWTTextComponent();
}
return
accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>TextComponent</code> class. It provides an implementation of the
* Java Accessibility API appropriate to text component user-interface
* elements.
* @since 1.3
*/
protected class
AccessibleAWTTextComponent extends
AccessibleAWTComponent
implements
AccessibleText,
TextListener
{
/*
* JDK 1.3 serialVersionUID
*/
private static final long
serialVersionUID = 3631432373506317811L;
/**
* Constructs an AccessibleAWTTextComponent. Adds a listener to track
* caret change.
*/
public
AccessibleAWTTextComponent() {
TextComponent.this.
addTextListener(this);
}
/**
* TextListener notification of a text value change.
*/
public void
textValueChanged(
TextEvent textEvent) {
Integer cpos =
Integer.
valueOf(
TextComponent.this.
getCaretPosition());
firePropertyChange(
ACCESSIBLE_TEXT_PROPERTY, null,
cpos);
}
/**
* Gets the state set of the TextComponent.
* The AccessibleStateSet of an object is composed of a set of
* unique AccessibleStates. 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 (
TextComponent.this.
isEditable()) {
states.
add(
AccessibleState.
EDITABLE);
}
return
states;
}
/**
* 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.
*
* @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.
*
* @param p the Point in local coordinates
* @return the zero-based index of the character under Point p.
*/
public int
getIndexAtPoint(
Point p) {
return -1;
}
/**
* 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.
*
* @param i the index into the String >= 0
* @return the screen coordinates of the character's bounding box
*/
public
Rectangle getCharacterBounds(int
i) {
return null;
}
/**
* Returns the number of characters (valid indicies)
*
* @return the number of characters >= 0
*/
public int
getCharCount() {
return
TextComponent.this.
getText().
length();
}
/**
* 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
TextComponent.this.
getCaretPosition();
}
/**
* 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) {
return null; // No attributes in TextComponent
}
/**
* 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 >= 0
*/
public int
getSelectionStart() {
return
TextComponent.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.
*
* @return the index into the text of the end of the selection >= 0
*/
public int
getSelectionEnd() {
return
TextComponent.this.
getSelectionEnd();
}
/**
* Returns the portion of the text that is selected.
*
* @return the text, null if no selection
*/
public
String getSelectedText() {
String selText =
TextComponent.this.
getSelectedText();
// Fix for 4256662
if (
selText == null ||
selText.
equals("")) {
return null;
}
return
selText;
}
/**
* Returns the String at a given index.
*
* @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
* or AccessibleText.SENTENCE to retrieve
* @param index an index within the text >= 0
* @return the letter, word, or sentence,
* null for an invalid index or part
*/
public
String getAtIndex(int
part, int
index) {
if (
index < 0 ||
index >=
TextComponent.this.
getText().
length()) {
return null;
}
switch (
part) {
case
AccessibleText.
CHARACTER:
return
TextComponent.this.
getText().
substring(
index,
index+1);
case
AccessibleText.
WORD: {
String s =
TextComponent.this.
getText();
BreakIterator words =
BreakIterator.
getWordInstance();
words.
setText(
s);
int
end =
words.
following(
index);
return
s.
substring(
words.
previous(),
end);
}
case
AccessibleText.
SENTENCE: {
String s =
TextComponent.this.
getText();
BreakIterator sentence =
BreakIterator.
getSentenceInstance();
sentence.
setText(
s);
int
end =
sentence.
following(
index);
return
s.
substring(
sentence.
previous(),
end);
}
default:
return null;
}
}
private static final boolean
NEXT = true;
private static final boolean
PREVIOUS = false;
/**
* Needed to unify forward and backward searching.
* The method assumes that s is the text assigned to words.
*/
private int
findWordLimit(int
index,
BreakIterator words, boolean
direction,
String s) {
// Fix for 4256660 and 4256661.
// Words iterator is different from character and sentence iterators
// in that end of one word is not necessarily start of another word.
// Please see java.text.BreakIterator JavaDoc. The code below is
// based on nextWordStartAfter example from BreakIterator.java.
int
last = (
direction ==
NEXT) ?
words.
following(
index)
:
words.
preceding(
index);
int
current = (
direction ==
NEXT) ?
words.
next()
:
words.
previous();
while (
current !=
BreakIterator.
DONE) {
for (int
p =
Math.
min(
last,
current);
p <
Math.
max(
last,
current);
p++) {
if (
Character.
isLetter(
s.
charAt(
p))) {
return
last;
}
}
last =
current;
current = (
direction ==
NEXT) ?
words.
next()
:
words.
previous();
}
return
BreakIterator.
DONE;
}
/**
* Returns the String after a given index.
*
* @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
* or AccessibleText.SENTENCE to retrieve
* @param index an index within the text >= 0
* @return the letter, word, or sentence, null for an invalid
* index or part
*/
public
String getAfterIndex(int
part, int
index) {
if (
index < 0 ||
index >=
TextComponent.this.
getText().
length()) {
return null;
}
switch (
part) {
case
AccessibleText.
CHARACTER:
if (
index+1 >=
TextComponent.this.
getText().
length()) {
return null;
}
return
TextComponent.this.
getText().
substring(
index+1,
index+2);
case
AccessibleText.
WORD: {
String s =
TextComponent.this.
getText();
BreakIterator words =
BreakIterator.
getWordInstance();
words.
setText(
s);
int
start =
findWordLimit(
index,
words,
NEXT,
s);
if (
start ==
BreakIterator.
DONE ||
start >=
s.
length()) {
return null;
}
int
end =
words.
following(
start);
if (
end ==
BreakIterator.
DONE ||
end >=
s.
length()) {
return null;
}
return
s.
substring(
start,
end);
}
case
AccessibleText.
SENTENCE: {
String s =
TextComponent.this.
getText();
BreakIterator sentence =
BreakIterator.
getSentenceInstance();
sentence.
setText(
s);
int
start =
sentence.
following(
index);
if (
start ==
BreakIterator.
DONE ||
start >=
s.
length()) {
return null;
}
int
end =
sentence.
following(
start);
if (
end ==
BreakIterator.
DONE ||
end >=
s.
length()) {
return null;
}
return
s.
substring(
start,
end);
}
default:
return null;
}
}
/**
* Returns the String before a given index.
*
* @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
* or AccessibleText.SENTENCE to retrieve
* @param index an index within the text >= 0
* @return the letter, word, or sentence, null for an invalid index
* or part
*/
public
String getBeforeIndex(int
part, int
index) {
if (
index < 0 ||
index >
TextComponent.this.
getText().
length()-1) {
return null;
}
switch (
part) {
case
AccessibleText.
CHARACTER:
if (
index == 0) {
return null;
}
return
TextComponent.this.
getText().
substring(
index-1,
index);
case
AccessibleText.
WORD: {
String s =
TextComponent.this.
getText();
BreakIterator words =
BreakIterator.
getWordInstance();
words.
setText(
s);
int
end =
findWordLimit(
index,
words,
PREVIOUS,
s);
if (
end ==
BreakIterator.
DONE) {
return null;
}
int
start =
words.
preceding(
end);
if (
start ==
BreakIterator.
DONE) {
return null;
}
return
s.
substring(
start,
end);
}
case
AccessibleText.
SENTENCE: {
String s =
TextComponent.this.
getText();
BreakIterator sentence =
BreakIterator.
getSentenceInstance();
sentence.
setText(
s);
int
end =
sentence.
following(
index);
end =
sentence.
previous();
int
start =
sentence.
previous();
if (
start ==
BreakIterator.
DONE) {
return null;
}
return
s.
substring(
start,
end);
}
default:
return null;
}
}
} // end of AccessibleAWTTextComponent
private boolean
checkForEnableIM = true;
}