0001 /*
0002 * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025 package java.awt;
0026
0027 import java.awt.peer.TextComponentPeer;
0028 import java.awt.event.*;
0029 import java.util.EventListener;
0030 import java.io.ObjectOutputStream;
0031 import java.io.ObjectInputStream;
0032 import java.io.IOException;
0033 import sun.awt.InputMethodSupport;
0034 import java.text.BreakIterator;
0035 import javax.swing.text.AttributeSet;
0036 import javax.accessibility.*;
0037 import java.awt.im.InputMethodRequests;
0038
0039 /**
0040 * The <code>TextComponent</code> class is the superclass of
0041 * any component that allows the editing of some text.
0042 * <p>
0043 * A text component embodies a string of text. The
0044 * <code>TextComponent</code> class defines a set of methods
0045 * that determine whether or not this text is editable. If the
0046 * component is editable, it defines another set of methods
0047 * that supports a text insertion caret.
0048 * <p>
0049 * In addition, the class defines methods that are used
0050 * to maintain a current <em>selection</em> from the text.
0051 * The text selection, a substring of the component's text,
0052 * is the target of editing operations. It is also referred
0053 * to as the <em>selected text</em>.
0054 *
0055 * @version 1.97, 05/05/07
0056 * @author Sami Shaio
0057 * @author Arthur van Hoff
0058 * @since JDK1.0
0059 */
0060 public class TextComponent extends Component implements Accessible {
0061
0062 /**
0063 * The value of the text.
0064 * A <code>null</code> value is the same as "".
0065 *
0066 * @serial
0067 * @see #setText(String)
0068 * @see #getText()
0069 */
0070 String text;
0071
0072 /**
0073 * A boolean indicating whether or not this
0074 * <code>TextComponent</code> is editable.
0075 * It will be <code>true</code> if the text component
0076 * is editable and <code>false</code> if not.
0077 *
0078 * @serial
0079 * @see #isEditable()
0080 */
0081 boolean editable = true;
0082
0083 /**
0084 * The selection refers to the selected text, and the
0085 * <code>selectionStart</code> is the start position
0086 * of the selected text.
0087 *
0088 * @serial
0089 * @see #getSelectionStart()
0090 * @see #setSelectionStart(int)
0091 */
0092 int selectionStart;
0093
0094 /**
0095 * The selection refers to the selected text, and the
0096 * <code>selectionEnd</code>
0097 * is the end position of the selected text.
0098 *
0099 * @serial
0100 * @see #getSelectionEnd()
0101 * @see #setSelectionEnd(int)
0102 */
0103 int selectionEnd;
0104
0105 // A flag used to tell whether the background has been set by
0106 // developer code (as opposed to AWT code). Used to determine
0107 // the background color of non-editable TextComponents.
0108 boolean backgroundSetByClientCode = false;
0109
0110 /**
0111 * True if this <code>TextComponent</code> has access
0112 * to the System clipboard.
0113 */
0114 transient private boolean canAccessClipboard;
0115
0116 transient protected TextListener textListener;
0117
0118 /*
0119 * JDK 1.1 serialVersionUID
0120 */
0121 private static final long serialVersionUID = -2214773872412987419L;
0122
0123 /**
0124 * Constructs a new text component initialized with the
0125 * specified text. Sets the value of the cursor to
0126 * <code>Cursor.TEXT_CURSOR</code>.
0127 * @param text the text to be displayed; if
0128 * <code>text</code> is <code>null</code>, the empty
0129 * string <code>""</code> will be displayed
0130 * @exception HeadlessException if
0131 * <code>GraphicsEnvironment.isHeadless</code>
0132 * returns true
0133 * @see java.awt.GraphicsEnvironment#isHeadless
0134 * @see java.awt.Cursor
0135 */
0136 TextComponent(String text) throws HeadlessException {
0137 GraphicsEnvironment.checkHeadless();
0138 this .text = (text != null) ? text : "";
0139 setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
0140 checkSystemClipboardAccess();
0141 }
0142
0143 private void enableInputMethodsIfNecessary() {
0144 if (checkForEnableIM) {
0145 checkForEnableIM = false;
0146 try {
0147 Toolkit toolkit = Toolkit.getDefaultToolkit();
0148 boolean shouldEnable = false;
0149 if (toolkit instanceof InputMethodSupport) {
0150 shouldEnable = ((InputMethodSupport) toolkit)
0151 .enableInputMethodsForTextComponent();
0152 }
0153 enableInputMethods(shouldEnable);
0154 } catch (Exception e) {
0155 // if something bad happens, just don't enable input methods
0156 }
0157 }
0158 }
0159
0160 /**
0161 * Enables or disables input method support for this text component. If input
0162 * method support is enabled and the text component also processes key events,
0163 * incoming events are offered to the current input method and will only be
0164 * processed by the component or dispatched to its listeners if the input method
0165 * does not consume them. Whether and how input method support for this text
0166 * component is enabled or disabled by default is implementation dependent.
0167 *
0168 * @param enable true to enable, false to disable
0169 * @see #processKeyEvent
0170 * @since 1.2
0171 */
0172 public void enableInputMethods(boolean enable) {
0173 checkForEnableIM = false;
0174 super .enableInputMethods(enable);
0175 }
0176
0177 boolean areInputMethodsEnabled() {
0178 // moved from the constructor above to here and addNotify below,
0179 // this call will initialize the toolkit if not already initialized.
0180 if (checkForEnableIM) {
0181 enableInputMethodsIfNecessary();
0182 }
0183
0184 // TextComponent handles key events without touching the eventMask or
0185 // having a key listener, so just check whether the flag is set
0186 return (eventMask & AWTEvent.INPUT_METHODS_ENABLED_MASK) != 0;
0187 }
0188
0189 public InputMethodRequests getInputMethodRequests() {
0190 TextComponentPeer peer = (TextComponentPeer) this .peer;
0191 if (peer != null)
0192 return peer.getInputMethodRequests();
0193 else
0194 return null;
0195 }
0196
0197 /**
0198 * Makes this Component displayable by connecting it to a
0199 * native screen resource.
0200 * This method is called internally by the toolkit and should
0201 * not be called directly by programs.
0202 * @see java.awt.TextComponent#removeNotify
0203 */
0204 public void addNotify() {
0205 super .addNotify();
0206 enableInputMethodsIfNecessary();
0207 }
0208
0209 /**
0210 * Removes the <code>TextComponent</code>'s peer.
0211 * The peer allows us to modify the appearance of the
0212 * <code>TextComponent</code> without changing its
0213 * functionality.
0214 */
0215 public void removeNotify() {
0216 synchronized (getTreeLock()) {
0217 TextComponentPeer peer = (TextComponentPeer) this .peer;
0218 if (peer != null) {
0219 text = peer.getText();
0220 selectionStart = peer.getSelectionStart();
0221 selectionEnd = peer.getSelectionEnd();
0222 }
0223 super .removeNotify();
0224 }
0225 }
0226
0227 /**
0228 * Sets the text that is presented by this
0229 * text component to be the specified text.
0230 * @param t the new text;
0231 * if this parameter is <code>null</code> then
0232 * the text is set to the empty string ""
0233 * @see java.awt.TextComponent#getText
0234 */
0235 public synchronized void setText(String t) {
0236 text = (t != null) ? t : "";
0237 TextComponentPeer peer = (TextComponentPeer) this .peer;
0238 if (peer != null) {
0239 peer.setText(text);
0240 }
0241 }
0242
0243 /**
0244 * Returns the text that is presented by this text component.
0245 * By default, this is an empty string.
0246 *
0247 * @return the value of this <code>TextComponent</code>
0248 * @see java.awt.TextComponent#setText
0249 */
0250 public synchronized String getText() {
0251 TextComponentPeer peer = (TextComponentPeer) this .peer;
0252 if (peer != null) {
0253 text = peer.getText();
0254 }
0255 return text;
0256 }
0257
0258 /**
0259 * Returns the selected text from the text that is
0260 * presented by this text component.
0261 * @return the selected text of this text component
0262 * @see java.awt.TextComponent#select
0263 */
0264 public synchronized String getSelectedText() {
0265 return getText().substring(getSelectionStart(),
0266 getSelectionEnd());
0267 }
0268
0269 /**
0270 * Indicates whether or not this text component is editable.
0271 * @return <code>true</code> if this text component is
0272 * editable; <code>false</code> otherwise.
0273 * @see java.awt.TextComponent#setEditable
0274 * @since JDK1.0
0275 */
0276 public boolean isEditable() {
0277 return editable;
0278 }
0279
0280 /**
0281 * Sets the flag that determines whether or not this
0282 * text component is editable.
0283 * <p>
0284 * If the flag is set to <code>true</code>, this text component
0285 * becomes user editable. If the flag is set to <code>false</code>,
0286 * the user cannot change the text of this text component.
0287 * By default, non-editable text components have a background color
0288 * of SystemColor.control. This default can be overridden by
0289 * calling setBackground.
0290 *
0291 * @param b a flag indicating whether this text component
0292 * is user editable.
0293 * @see java.awt.TextComponent#isEditable
0294 * @since JDK1.0
0295 */
0296 public synchronized void setEditable(boolean b) {
0297 if (editable == b) {
0298 return;
0299 }
0300
0301 editable = b;
0302 TextComponentPeer peer = (TextComponentPeer) this .peer;
0303 if (peer != null) {
0304 peer.setEditable(b);
0305 }
0306 }
0307
0308 /**
0309 * Gets the background color of this text component.
0310 *
0311 * By default, non-editable text components have a background color
0312 * of SystemColor.control. This default can be overridden by
0313 * calling setBackground.
0314 *
0315 * @return This text component's background color.
0316 * If this text component does not have a background color,
0317 * the background color of its parent is returned.
0318 * @see #setBackground(Color)
0319 * @since JDK1.0
0320 */
0321 public Color getBackground() {
0322 if (!editable && !backgroundSetByClientCode) {
0323 return SystemColor.control;
0324 }
0325
0326 return super .getBackground();
0327 }
0328
0329 /**
0330 * Sets the background color of this text component.
0331 *
0332 * @param c The color to become this text component's color.
0333 * If this parameter is null then this text component
0334 * will inherit the background color of its parent.
0335 * @see #getBackground()
0336 * @since JDK1.0
0337 */
0338 public void setBackground(Color c) {
0339 backgroundSetByClientCode = true;
0340 super .setBackground(c);
0341 }
0342
0343 /**
0344 * Gets the start position of the selected text in
0345 * this text component.
0346 * @return the start position of the selected text
0347 * @see java.awt.TextComponent#setSelectionStart
0348 * @see java.awt.TextComponent#getSelectionEnd
0349 */
0350 public synchronized int getSelectionStart() {
0351 TextComponentPeer peer = (TextComponentPeer) this .peer;
0352 if (peer != null) {
0353 selectionStart = peer.getSelectionStart();
0354 }
0355 return selectionStart;
0356 }
0357
0358 /**
0359 * Sets the selection start for this text component to
0360 * the specified position. The new start point is constrained
0361 * to be at or before the current selection end. It also
0362 * cannot be set to less than zero, the beginning of the
0363 * component's text.
0364 * If the caller supplies a value for <code>selectionStart</code>
0365 * that is out of bounds, the method enforces these constraints
0366 * silently, and without failure.
0367 * @param selectionStart the start position of the
0368 * selected text
0369 * @see java.awt.TextComponent#getSelectionStart
0370 * @see java.awt.TextComponent#setSelectionEnd
0371 * @since JDK1.1
0372 */
0373 public synchronized void setSelectionStart(int selectionStart) {
0374 /* Route through select method to enforce consistent policy
0375 * between selectionStart and selectionEnd.
0376 */
0377 select(selectionStart, getSelectionEnd());
0378 }
0379
0380 /**
0381 * Gets the end position of the selected text in
0382 * this text component.
0383 * @return the end position of the selected text
0384 * @see java.awt.TextComponent#setSelectionEnd
0385 * @see java.awt.TextComponent#getSelectionStart
0386 */
0387 public synchronized int getSelectionEnd() {
0388 TextComponentPeer peer = (TextComponentPeer) this .peer;
0389 if (peer != null) {
0390 selectionEnd = peer.getSelectionEnd();
0391 }
0392 return selectionEnd;
0393 }
0394
0395 /**
0396 * Sets the selection end for this text component to
0397 * the specified position. The new end point is constrained
0398 * to be at or after the current selection start. It also
0399 * cannot be set beyond the end of the component's text.
0400 * If the caller supplies a value for <code>selectionEnd</code>
0401 * that is out of bounds, the method enforces these constraints
0402 * silently, and without failure.
0403 * @param selectionEnd the end position of the
0404 * selected text
0405 * @see java.awt.TextComponent#getSelectionEnd
0406 * @see java.awt.TextComponent#setSelectionStart
0407 * @since JDK1.1
0408 */
0409 public synchronized void setSelectionEnd(int selectionEnd) {
0410 /* Route through select method to enforce consistent policy
0411 * between selectionStart and selectionEnd.
0412 */
0413 select(getSelectionStart(), selectionEnd);
0414 }
0415
0416 /**
0417 * Selects the text between the specified start and end positions.
0418 * <p>
0419 * This method sets the start and end positions of the
0420 * selected text, enforcing the restriction that the start position
0421 * must be greater than or equal to zero. The end position must be
0422 * greater than or equal to the start position, and less than or
0423 * equal to the length of the text component's text. The
0424 * character positions are indexed starting with zero.
0425 * The length of the selection is
0426 * <code>endPosition</code> - <code>startPosition</code>, so the
0427 * character at <code>endPosition</code> is not selected.
0428 * If the start and end positions of the selected text are equal,
0429 * all text is deselected.
0430 * <p>
0431 * If the caller supplies values that are inconsistent or out of
0432 * bounds, the method enforces these constraints silently, and
0433 * without failure. Specifically, if the start position or end
0434 * position is greater than the length of the text, it is reset to
0435 * equal the text length. If the start position is less than zero,
0436 * it is reset to zero, and if the end position is less than the
0437 * start position, it is reset to the start position.
0438 *
0439 * @param selectionStart the zero-based index of the first
0440 character (<code>char</code> value) to be selected
0441 * @param selectionEnd the zero-based end position of the
0442 text to be selected; the character (<code>char</code> value) at
0443 <code>selectionEnd</code> is not selected
0444 * @see java.awt.TextComponent#setSelectionStart
0445 * @see java.awt.TextComponent#setSelectionEnd
0446 * @see java.awt.TextComponent#selectAll
0447 */
0448 public synchronized void select(int selectionStart, int selectionEnd) {
0449 String text = getText();
0450 if (selectionStart < 0) {
0451 selectionStart = 0;
0452 }
0453 if (selectionStart > text.length()) {
0454 selectionStart = text.length();
0455 }
0456 if (selectionEnd > text.length()) {
0457 selectionEnd = text.length();
0458 }
0459 if (selectionEnd < selectionStart) {
0460 selectionEnd = selectionStart;
0461 }
0462
0463 this .selectionStart = selectionStart;
0464 this .selectionEnd = selectionEnd;
0465
0466 TextComponentPeer peer = (TextComponentPeer) this .peer;
0467 if (peer != null) {
0468 peer.select(selectionStart, selectionEnd);
0469 }
0470 }
0471
0472 /**
0473 * Selects all the text in this text component.
0474 * @see java.awt.TextComponent#select
0475 */
0476 public synchronized void selectAll() {
0477 this .selectionStart = 0;
0478 this .selectionEnd = getText().length();
0479
0480 TextComponentPeer peer = (TextComponentPeer) this .peer;
0481 if (peer != null) {
0482 peer.select(selectionStart, selectionEnd);
0483 }
0484 }
0485
0486 /**
0487 * Sets the position of the text insertion caret.
0488 * The caret position is constrained to be between 0
0489 * and the last character of the text, inclusive.
0490 * If the passed-in value is greater than this range,
0491 * the value is set to the last character (or 0 if
0492 * the <code>TextComponent</code> contains no text)
0493 * and no error is returned. If the passed-in value is
0494 * less than 0, an <code>IllegalArgumentException</code>
0495 * is thrown.
0496 *
0497 * @param position the position of the text insertion caret
0498 * @exception IllegalArgumentException if <code>position</code>
0499 * is less than zero
0500 * @since JDK1.1
0501 */
0502 public synchronized void setCaretPosition(int position) {
0503 if (position < 0) {
0504 throw new IllegalArgumentException(
0505 "position less than zero.");
0506 }
0507
0508 int maxposition = getText().length();
0509 if (position > maxposition) {
0510 position = maxposition;
0511 }
0512
0513 TextComponentPeer peer = (TextComponentPeer) this .peer;
0514 if (peer != null) {
0515 peer.setCaretPosition(position);
0516 } else {
0517 select(position, position);
0518 }
0519 }
0520
0521 /**
0522 * Returns the position of the text insertion caret.
0523 * The caret position is constrained to be between 0
0524 * and the last character of the text, inclusive.
0525 * If the text or caret have not been set, the default
0526 * caret position is 0.
0527 *
0528 * @return the position of the text insertion caret
0529 * @see #setCaretPosition(int)
0530 * @since JDK1.1
0531 */
0532 public synchronized int getCaretPosition() {
0533 TextComponentPeer peer = (TextComponentPeer) this .peer;
0534 int position = 0;
0535
0536 if (peer != null) {
0537 position = peer.getCaretPosition();
0538 } else {
0539 position = selectionStart;
0540 }
0541 int maxposition = getText().length();
0542 if (position > maxposition) {
0543 position = maxposition;
0544 }
0545 return position;
0546 }
0547
0548 /**
0549 * Adds the specified text event listener to receive text events
0550 * from this text component.
0551 * If <code>l</code> is <code>null</code>, no exception is
0552 * thrown and no action is performed.
0553 * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
0554 * >AWT Threading Issues</a> for details on AWT's threading model.
0555 *
0556 * @param l the text event listener
0557 * @see #removeTextListener
0558 * @see #getTextListeners
0559 * @see java.awt.event.TextListener
0560 */
0561 public synchronized void addTextListener(TextListener l) {
0562 if (l == null) {
0563 return;
0564 }
0565 textListener = AWTEventMulticaster.add(textListener, l);
0566 newEventsOnly = true;
0567 }
0568
0569 /**
0570 * Removes the specified text event listener so that it no longer
0571 * receives text events from this text component
0572 * If <code>l</code> is <code>null</code>, no exception is
0573 * thrown and no action is performed.
0574 * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
0575 * >AWT Threading Issues</a> for details on AWT's threading model.
0576 *
0577 * @param l the text listener
0578 * @see #addTextListener
0579 * @see #getTextListeners
0580 * @see java.awt.event.TextListener
0581 * @since JDK1.1
0582 */
0583 public synchronized void removeTextListener(TextListener l) {
0584 if (l == null) {
0585 return;
0586 }
0587 textListener = AWTEventMulticaster.remove(textListener, l);
0588 }
0589
0590 /**
0591 * Returns an array of all the text listeners
0592 * registered on this text component.
0593 *
0594 * @return all of this text component's <code>TextListener</code>s
0595 * or an empty array if no text
0596 * listeners are currently registered
0597 *
0598 *
0599 * @see #addTextListener
0600 * @see #removeTextListener
0601 * @since 1.4
0602 */
0603 public synchronized TextListener[] getTextListeners() {
0604 return (TextListener[]) (getListeners(TextListener.class));
0605 }
0606
0607 /**
0608 * Returns an array of all the objects currently registered
0609 * as <code><em>Foo</em>Listener</code>s
0610 * upon this <code>TextComponent</code>.
0611 * <code><em>Foo</em>Listener</code>s are registered using the
0612 * <code>add<em>Foo</em>Listener</code> method.
0613 *
0614 * <p>
0615 * You can specify the <code>listenerType</code> argument
0616 * with a class literal, such as
0617 * <code><em>Foo</em>Listener.class</code>.
0618 * For example, you can query a
0619 * <code>TextComponent</code> <code>t</code>
0620 * for its text listeners with the following code:
0621 *
0622 * <pre>TextListener[] tls = (TextListener[])(t.getListeners(TextListener.class));</pre>
0623 *
0624 * If no such listeners exist, this method returns an empty array.
0625 *
0626 * @param listenerType the type of listeners requested; this parameter
0627 * should specify an interface that descends from
0628 * <code>java.util.EventListener</code>
0629 * @return an array of all objects registered as
0630 * <code><em>Foo</em>Listener</code>s on this text component,
0631 * or an empty array if no such
0632 * listeners have been added
0633 * @exception ClassCastException if <code>listenerType</code>
0634 * doesn't specify a class or interface that implements
0635 * <code>java.util.EventListener</code>
0636 *
0637 * @see #getTextListeners
0638 * @since 1.3
0639 */
0640 public <T extends EventListener> T[] getListeners(
0641 Class<T> listenerType) {
0642 EventListener l = null;
0643 if (listenerType == TextListener.class) {
0644 l = textListener;
0645 } else {
0646 return super .getListeners(listenerType);
0647 }
0648 return AWTEventMulticaster.getListeners(l, listenerType);
0649 }
0650
0651 // REMIND: remove when filtering is done at lower level
0652 boolean eventEnabled(AWTEvent e) {
0653 if (e.id == TextEvent.TEXT_VALUE_CHANGED) {
0654 if ((eventMask & AWTEvent.TEXT_EVENT_MASK) != 0
0655 || textListener != null) {
0656 return true;
0657 }
0658 return false;
0659 }
0660 return super .eventEnabled(e);
0661 }
0662
0663 /**
0664 * Processes events on this text component. If the event is a
0665 * <code>TextEvent</code>, it invokes the <code>processTextEvent</code>
0666 * method else it invokes its superclass's <code>processEvent</code>.
0667 * <p>Note that if the event parameter is <code>null</code>
0668 * the behavior is unspecified and may result in an
0669 * exception.
0670 *
0671 * @param e the event
0672 */
0673 protected void processEvent(AWTEvent e) {
0674 if (e instanceof TextEvent) {
0675 processTextEvent((TextEvent) e);
0676 return;
0677 }
0678 super .processEvent(e);
0679 }
0680
0681 /**
0682 * Processes text events occurring on this text component by
0683 * dispatching them to any registered <code>TextListener</code> objects.
0684 * <p>
0685 * NOTE: This method will not be called unless text events
0686 * are enabled for this component. This happens when one of the
0687 * following occurs:
0688 * <ul>
0689 * <li>A <code>TextListener</code> object is registered
0690 * via <code>addTextListener</code>
0691 * <li>Text events are enabled via <code>enableEvents</code>
0692 * </ul>
0693 * <p>Note that if the event parameter is <code>null</code>
0694 * the behavior is unspecified and may result in an
0695 * exception.
0696 *
0697 * @param e the text event
0698 * @see Component#enableEvents
0699 */
0700 protected void processTextEvent(TextEvent e) {
0701 TextListener listener = textListener;
0702 if (listener != null) {
0703 int id = e.getID();
0704 switch (id) {
0705 case TextEvent.TEXT_VALUE_CHANGED:
0706 listener.textValueChanged(e);
0707 break;
0708 }
0709 }
0710 }
0711
0712 /**
0713 * Returns a string representing the state of this
0714 * <code>TextComponent</code>. This
0715 * method is intended to be used only for debugging purposes, and the
0716 * content and format of the returned string may vary between
0717 * implementations. The returned string may be empty but may not be
0718 * <code>null</code>.
0719 *
0720 * @return the parameter string of this text component
0721 */
0722 protected String paramString() {
0723 String str = super .paramString() + ",text=" + getText();
0724 if (editable) {
0725 str += ",editable";
0726 }
0727 return str + ",selection=" + getSelectionStart() + "-"
0728 + getSelectionEnd();
0729 }
0730
0731 /**
0732 * Assigns a valid value to the canAccessClipboard instance variable.
0733 */
0734 private void checkSystemClipboardAccess() {
0735 canAccessClipboard = true;
0736 SecurityManager sm = System.getSecurityManager();
0737 if (sm != null) {
0738 try {
0739 sm.checkSystemClipboardAccess();
0740 } catch (SecurityException e) {
0741 canAccessClipboard = false;
0742 }
0743 }
0744 }
0745
0746 /*
0747 * Serialization support.
0748 */
0749 /**
0750 * The textComponent SerializedDataVersion.
0751 *
0752 * @serial
0753 */
0754 private int textComponentSerializedDataVersion = 1;
0755
0756 /**
0757 * Writes default serializable fields to stream. Writes
0758 * a list of serializable TextListener(s) as optional data.
0759 * The non-serializable TextListener(s) are detected and
0760 * no attempt is made to serialize them.
0761 *
0762 * @serialData Null terminated sequence of zero or more pairs.
0763 * A pair consists of a String and Object.
0764 * The String indicates the type of object and
0765 * is one of the following :
0766 * textListenerK indicating and TextListener object.
0767 *
0768 * @see AWTEventMulticaster#save(ObjectOutputStream, String, EventListener)
0769 * @see java.awt.Component#textListenerK
0770 */
0771 private void writeObject(java.io.ObjectOutputStream s)
0772 throws IOException {
0773 // Serialization support. Since the value of the fields
0774 // selectionStart, selectionEnd, and text aren't necessarily
0775 // up to date, we sync them up with the peer before serializing.
0776 TextComponentPeer peer = (TextComponentPeer) this .peer;
0777 if (peer != null) {
0778 text = peer.getText();
0779 selectionStart = peer.getSelectionStart();
0780 selectionEnd = peer.getSelectionEnd();
0781 }
0782
0783 s.defaultWriteObject();
0784
0785 AWTEventMulticaster.save(s, textListenerK, textListener);
0786 s.writeObject(null);
0787 }
0788
0789 /**
0790 * Read the ObjectInputStream, and if it isn't null,
0791 * add a listener to receive text events fired by the
0792 * TextComponent. Unrecognized keys or values will be
0793 * ignored.
0794 *
0795 * @exception HeadlessException if
0796 * <code>GraphicsEnvironment.isHeadless()</code> returns
0797 * <code>true</code>
0798 * @see #removeTextListener
0799 * @see #addTextListener
0800 * @see java.awt.GraphicsEnvironment#isHeadless
0801 */
0802 private void readObject(ObjectInputStream s)
0803 throws ClassNotFoundException, IOException,
0804 HeadlessException {
0805 GraphicsEnvironment.checkHeadless();
0806 s.defaultReadObject();
0807
0808 // Make sure the state we just read in for text,
0809 // selectionStart and selectionEnd has legal values
0810 this .text = (text != null) ? text : "";
0811 select(selectionStart, selectionEnd);
0812
0813 Object keyOrNull;
0814 while (null != (keyOrNull = s.readObject())) {
0815 String key = ((String) keyOrNull).intern();
0816
0817 if (textListenerK == key) {
0818 addTextListener((TextListener) (s.readObject()));
0819 } else {
0820 // skip value for unrecognized key
0821 s.readObject();
0822 }
0823 }
0824 enableInputMethodsIfNecessary();
0825 checkSystemClipboardAccess();
0826 }
0827
0828 /////////////////
0829 // Accessibility support
0830 ////////////////
0831
0832 /**
0833 *
0834 */
0835 int getIndexAtPoint(Point p) {
0836 return -1;
0837 /* To be fully implemented in a future release
0838 if (peer == null) {
0839 return -1;
0840 }
0841 TextComponentPeer peer = (TextComponentPeer)this.peer;
0842 return peer.getIndexAtPoint(p.x, p.y);
0843 */
0844 }
0845
0846 /**
0847 *
0848 */
0849 Rectangle getCharacterBounds(int i) {
0850 return null;
0851 /* To be fully implemented in a future release
0852 if (peer == null) {
0853 return null;
0854 }
0855 TextComponentPeer peer = (TextComponentPeer)this.peer;
0856 return peer.getCharacterBounds(i);
0857 */
0858 }
0859
0860 /**
0861 * Gets the AccessibleContext associated with this TextComponent.
0862 * For text components, the AccessibleContext takes the form of an
0863 * AccessibleAWTTextComponent.
0864 * A new AccessibleAWTTextComponent instance is created if necessary.
0865 *
0866 * @return an AccessibleAWTTextComponent that serves as the
0867 * AccessibleContext of this TextComponent
0868 * @since 1.3
0869 */
0870 public AccessibleContext getAccessibleContext() {
0871 if (accessibleContext == null) {
0872 accessibleContext = new AccessibleAWTTextComponent();
0873 }
0874 return accessibleContext;
0875 }
0876
0877 /**
0878 * This class implements accessibility support for the
0879 * <code>TextComponent</code> class. It provides an implementation of the
0880 * Java Accessibility API appropriate to text component user-interface
0881 * elements.
0882 * @since 1.3
0883 */
0884 protected class AccessibleAWTTextComponent extends
0885 AccessibleAWTComponent implements AccessibleText,
0886 TextListener {
0887 /*
0888 * JDK 1.3 serialVersionUID
0889 */
0890 private static final long serialVersionUID = 3631432373506317811L;
0891
0892 /**
0893 * Constructs an AccessibleAWTTextComponent. Adds a listener to track
0894 * caret change.
0895 */
0896 public AccessibleAWTTextComponent() {
0897 TextComponent.this .addTextListener(this );
0898 }
0899
0900 /**
0901 * TextListener notification of a text value change.
0902 */
0903 public void textValueChanged(TextEvent textEvent) {
0904 Integer cpos = Integer.valueOf(TextComponent.this
0905 .getCaretPosition());
0906 firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, cpos);
0907 }
0908
0909 /**
0910 * Gets the state set of the TextComponent.
0911 * The AccessibleStateSet of an object is composed of a set of
0912 * unique AccessibleStates. A change in the AccessibleStateSet
0913 * of an object will cause a PropertyChangeEvent to be fired
0914 * for the AccessibleContext.ACCESSIBLE_STATE_PROPERTY property.
0915 *
0916 * @return an instance of AccessibleStateSet containing the
0917 * current state set of the object
0918 * @see AccessibleStateSet
0919 * @see AccessibleState
0920 * @see #addPropertyChangeListener
0921 */
0922 public AccessibleStateSet getAccessibleStateSet() {
0923 AccessibleStateSet states = super .getAccessibleStateSet();
0924 if (TextComponent.this .isEditable()) {
0925 states.add(AccessibleState.EDITABLE);
0926 }
0927 return states;
0928 }
0929
0930 /**
0931 * Gets the role of this object.
0932 *
0933 * @return an instance of AccessibleRole describing the role of the
0934 * object (AccessibleRole.TEXT)
0935 * @see AccessibleRole
0936 */
0937 public AccessibleRole getAccessibleRole() {
0938 return AccessibleRole.TEXT;
0939 }
0940
0941 /**
0942 * Get the AccessibleText associated with this object. In the
0943 * implementation of the Java Accessibility API for this class,
0944 * return this object, which is responsible for implementing the
0945 * AccessibleText interface on behalf of itself.
0946 *
0947 * @return this object
0948 */
0949 public AccessibleText getAccessibleText() {
0950 return this ;
0951 }
0952
0953 // --- interface AccessibleText methods ------------------------
0954
0955 /**
0956 * Many of these methods are just convenience methods; they
0957 * just call the equivalent on the parent
0958 */
0959
0960 /**
0961 * Given a point in local coordinates, return the zero-based index
0962 * of the character under that Point. If the point is invalid,
0963 * this method returns -1.
0964 *
0965 * @param p the Point in local coordinates
0966 * @return the zero-based index of the character under Point p.
0967 */
0968 public int getIndexAtPoint(Point p) {
0969 return TextComponent.this .getIndexAtPoint(p);
0970 }
0971
0972 /**
0973 * Determines the bounding box of the character at the given
0974 * index into the string. The bounds are returned in local
0975 * coordinates. If the index is invalid a null rectangle
0976 * is returned.
0977 *
0978 * @param i the index into the String >= 0
0979 * @return the screen coordinates of the character's bounding box
0980 */
0981 public Rectangle getCharacterBounds(int i) {
0982 return TextComponent.this .getCharacterBounds(i);
0983 }
0984
0985 /**
0986 * Returns the number of characters (valid indicies)
0987 *
0988 * @return the number of characters >= 0
0989 */
0990 public int getCharCount() {
0991 return TextComponent.this .getText().length();
0992 }
0993
0994 /**
0995 * Returns the zero-based offset of the caret.
0996 *
0997 * Note: The character to the right of the caret will have the
0998 * same index value as the offset (the caret is between
0999 * two characters).
1000 *
1001 * @return the zero-based offset of the caret.
1002 */
1003 public int getCaretPosition() {
1004 return TextComponent.this .getCaretPosition();
1005 }
1006
1007 /**
1008 * Returns the AttributeSet for a given character (at a given index).
1009 *
1010 * @param i the zero-based index into the text
1011 * @return the AttributeSet of the character
1012 */
1013 public AttributeSet getCharacterAttribute(int i) {
1014 return null; // No attributes in TextComponent
1015 }
1016
1017 /**
1018 * Returns the start offset within the selected text.
1019 * If there is no selection, but there is
1020 * a caret, the start and end offsets will be the same.
1021 * Return 0 if the text is empty, or the caret position
1022 * if no selection.
1023 *
1024 * @return the index into the text of the start of the selection >= 0
1025 */
1026 public int getSelectionStart() {
1027 return TextComponent.this .getSelectionStart();
1028 }
1029
1030 /**
1031 * Returns the end offset within the selected text.
1032 * If there is no selection, but there is
1033 * a caret, the start and end offsets will be the same.
1034 * Return 0 if the text is empty, or the caret position
1035 * if no selection.
1036 *
1037 * @return the index into teh text of the end of the selection >= 0
1038 */
1039 public int getSelectionEnd() {
1040 return TextComponent.this .getSelectionEnd();
1041 }
1042
1043 /**
1044 * Returns the portion of the text that is selected.
1045 *
1046 * @return the text, null if no selection
1047 */
1048 public String getSelectedText() {
1049 String selText = TextComponent.this .getSelectedText();
1050 // Fix for 4256662
1051 if (selText == null || selText.equals("")) {
1052 return null;
1053 }
1054 return selText;
1055 }
1056
1057 /**
1058 * Returns the String at a given index.
1059 *
1060 * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
1061 * or AccessibleText.SENTENCE to retrieve
1062 * @param index an index within the text >= 0
1063 * @return the letter, word, or sentence,
1064 * null for an invalid index or part
1065 */
1066 public String getAtIndex(int part, int index) {
1067 if (index < 0
1068 || index >= TextComponent.this .getText().length()) {
1069 return null;
1070 }
1071 switch (part) {
1072 case AccessibleText.CHARACTER:
1073 return TextComponent.this .getText().substring(index,
1074 index + 1);
1075 case AccessibleText.WORD: {
1076 String s = TextComponent.this .getText();
1077 BreakIterator words = BreakIterator.getWordInstance();
1078 words.setText(s);
1079 int end = words.following(index);
1080 return s.substring(words.previous(), end);
1081 }
1082 case AccessibleText.SENTENCE: {
1083 String s = TextComponent.this .getText();
1084 BreakIterator sentence = BreakIterator
1085 .getSentenceInstance();
1086 sentence.setText(s);
1087 int end = sentence.following(index);
1088 return s.substring(sentence.previous(), end);
1089 }
1090 default:
1091 return null;
1092 }
1093 }
1094
1095 private static final boolean NEXT = true;
1096 private static final boolean PREVIOUS = false;
1097
1098 /**
1099 * Needed to unify forward and backward searching.
1100 * The method assumes that s is the text assigned to words.
1101 */
1102 private int findWordLimit(int index, BreakIterator words,
1103 boolean direction, String s) {
1104 // Fix for 4256660 and 4256661.
1105 // Words iterator is different from character and sentence iterators
1106 // in that end of one word is not necessarily start of another word.
1107 // Please see java.text.BreakIterator JavaDoc. The code below is
1108 // based on nextWordStartAfter example from BreakIterator.java.
1109 int last = (direction == NEXT) ? words.following(index)
1110 : words.preceding(index);
1111 int current = (direction == NEXT) ? words.next() : words
1112 .previous();
1113 while (current != BreakIterator.DONE) {
1114 for (int p = Math.min(last, current); p < Math.max(
1115 last, current); p++) {
1116 if (Character.isLetter(s.charAt(p))) {
1117 return last;
1118 }
1119 }
1120 last = current;
1121 current = (direction == NEXT) ? words.next() : words
1122 .previous();
1123 }
1124 return BreakIterator.DONE;
1125 }
1126
1127 /**
1128 * Returns the String after a given index.
1129 *
1130 * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
1131 * or AccessibleText.SENTENCE to retrieve
1132 * @param index an index within the text >= 0
1133 * @return the letter, word, or sentence, null for an invalid
1134 * index or part
1135 */
1136 public String getAfterIndex(int part, int index) {
1137 if (index < 0
1138 || index >= TextComponent.this .getText().length()) {
1139 return null;
1140 }
1141 switch (part) {
1142 case AccessibleText.CHARACTER:
1143 if (index + 1 >= TextComponent.this .getText().length()) {
1144 return null;
1145 }
1146 return TextComponent.this .getText().substring(
1147 index + 1, index + 2);
1148 case AccessibleText.WORD: {
1149 String s = TextComponent.this .getText();
1150 BreakIterator words = BreakIterator.getWordInstance();
1151 words.setText(s);
1152 int start = findWordLimit(index, words, NEXT, s);
1153 if (start == BreakIterator.DONE || start >= s.length()) {
1154 return null;
1155 }
1156 int end = words.following(start);
1157 if (end == BreakIterator.DONE || end >= s.length()) {
1158 return null;
1159 }
1160 return s.substring(start, end);
1161 }
1162 case AccessibleText.SENTENCE: {
1163 String s = TextComponent.this .getText();
1164 BreakIterator sentence = BreakIterator
1165 .getSentenceInstance();
1166 sentence.setText(s);
1167 int start = sentence.following(index);
1168 if (start == BreakIterator.DONE || start >= s.length()) {
1169 return null;
1170 }
1171 int end = sentence.following(start);
1172 if (end == BreakIterator.DONE || end >= s.length()) {
1173 return null;
1174 }
1175 return s.substring(start, end);
1176 }
1177 default:
1178 return null;
1179 }
1180 }
1181
1182 /**
1183 * Returns the String before a given index.
1184 *
1185 * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
1186 * or AccessibleText.SENTENCE to retrieve
1187 * @param index an index within the text >= 0
1188 * @return the letter, word, or sentence, null for an invalid index
1189 * or part
1190 */
1191 public String getBeforeIndex(int part, int index) {
1192 if (index < 0
1193 || index > TextComponent.this .getText().length() - 1) {
1194 return null;
1195 }
1196 switch (part) {
1197 case AccessibleText.CHARACTER:
1198 if (index == 0) {
1199 return null;
1200 }
1201 return TextComponent.this .getText().substring(
1202 index - 1, index);
1203 case AccessibleText.WORD: {
1204 String s = TextComponent.this .getText();
1205 BreakIterator words = BreakIterator.getWordInstance();
1206 words.setText(s);
1207 int end = findWordLimit(index, words, PREVIOUS, s);
1208 if (end == BreakIterator.DONE) {
1209 return null;
1210 }
1211 int start = words.preceding(end);
1212 if (start == BreakIterator.DONE) {
1213 return null;
1214 }
1215 return s.substring(start, end);
1216 }
1217 case AccessibleText.SENTENCE: {
1218 String s = TextComponent.this .getText();
1219 BreakIterator sentence = BreakIterator
1220 .getSentenceInstance();
1221 sentence.setText(s);
1222 int end = sentence.following(index);
1223 end = sentence.previous();
1224 int start = sentence.previous();
1225 if (start == BreakIterator.DONE) {
1226 return null;
1227 }
1228 return s.substring(start, end);
1229 }
1230 default:
1231 return null;
1232 }
1233 }
1234 } // end of AccessibleAWTTextComponent
1235
1236 private boolean checkForEnableIM = true;
1237 }
|