1 /* TextComponent.java -- Widgets for entering text
2 Copyright (C) 1999, 2002, 2003, 2006, Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
41 import java.awt.event.TextEvent;
42 import java.awt.event.TextListener;
43 import java.awt.peer.TextComponentPeer;
44 import java.io.Serializable;
45 import java.text.BreakIterator;
46 import java.util.EventListener;
48 import javax.accessibility.Accessible;
49 import javax.accessibility.AccessibleContext;
50 import javax.accessibility.AccessibleRole;
51 import javax.accessibility.AccessibleState;
52 import javax.accessibility.AccessibleStateSet;
53 import javax.accessibility.AccessibleText;
54 import javax.swing.text.AttributeSet;
57 * This class provides common functionality for widgets than
60 * @author Aaron M. Renn (arenn@urbanophile.com)
62 public class TextComponent extends Component
63 implements Serializable, Accessible
66 private static final long serialVersionUID = -2214773872412987419L;
69 * @serial Indicates whether or not this component is editable.
70 * This is package-private to avoid an accessor method.
75 * @serial The starting position of the selected text region.
76 * This is package-private to avoid an accessor method.
81 * @serial The ending position of the selected text region.
82 * This is package-private to avoid an accessor method.
87 * @serial The text in the component
88 * This is package-private to avoid an accessor method.
93 * A list of listeners that will receive events from this object.
95 protected transient TextListener textListener;
97 protected class AccessibleAWTTextComponent
98 extends AccessibleAWTComponent
99 implements AccessibleText, TextListener
101 private static final long serialVersionUID = 3631432373506317811L;
104 // Adds a listener for tracking caret changes
105 public AccessibleAWTTextComponent()
107 TextComponent.this.addTextListener(this);
110 public AccessibleRole getAccessibleRole()
112 return AccessibleRole.TEXT;
115 public AccessibleStateSet getAccessibleStateSet()
117 // TODO: Docs say PropertyChangeEvent will fire if this state changes.
118 // That means that the event has to fire when editable changes.
119 AccessibleStateSet ss = super.getAccessibleStateSet();
121 ss.add(AccessibleState.EDITABLE);
125 public AccessibleText getAccessibleText()
131 * @see javax.accessibility.AccessibleText#getIndexAtPoint(java.awt.Point)
133 public int getIndexAtPoint(Point point)
135 return TextComponent.this.getIndexAtPoint(point);
139 * @see javax.accessibility.AccessibleText#getCharacterBounds(int)
141 public Rectangle getCharacterBounds(int index)
143 return TextComponent.this.getCharacterBounds(index);
147 * @see javax.accessibility.AccessibleText#getCharCount()
149 public int getCharCount()
151 return text.length();
155 * @see javax.accessibility.AccessibleText#getCaretPosition()
157 public int getCaretPosition()
159 return TextComponent.this.getCaretPosition();
163 * @see javax.accessibility.AccessibleText#getAtIndex(int, int)
165 public String getAtIndex(int part, int index)
167 if (index < 0 || index >= text.length())
169 BreakIterator it = null;
173 return text.substring(index, index + 1);
175 it = BreakIterator.getWordInstance();
178 it = BreakIterator.getSentenceInstance();
185 if (!it.isBoundary(index))
186 start = it.preceding(index);
187 int end = it.following(index);
189 return text.substring(index);
191 return text.substring(index, end);
195 * @see javax.accessibility.AccessibleText#getAfterIndex(int, int)
197 public String getAfterIndex(int part, int index) {
198 if (index < 0 || index >= text.length())
200 BreakIterator it = null;
204 return text.substring(index, index + 1);
206 it = BreakIterator.getWordInstance();
209 it = BreakIterator.getSentenceInstance();
216 if (!it.isBoundary(index))
217 start = it.following(index);
218 // Make sure there was a complete unit. I.e. if index is in the middle
219 // of a word, return null if there is no word after the that one.
222 int end = it.following(start);
224 return text.substring(index);
226 return text.substring(index, end);
230 * @see javax.accessibility.AccessibleText#getBeforeIndex(int, int)
232 public String getBeforeIndex(int part, int index)
234 if (index < 1 || index >= text.length())
236 BreakIterator it = null;
240 return text.substring(index - 1, index);
242 it = BreakIterator.getWordInstance();
245 it = BreakIterator.getSentenceInstance();
252 if (!it.isBoundary(index))
253 end = it.preceding(index);
254 // Make sure there was a complete unit. I.e. if index is in the middle
255 // of a word, return null if there is no word before that one.
258 int start = it.preceding(end);
260 return text.substring(0, end);
262 return text.substring(start, end);
266 * @see javax.accessibility.AccessibleText#getCharacterAttribute(int)
268 public AttributeSet getCharacterAttribute(int index)
270 // FIXME: I suspect this really gets filled in by subclasses.
275 * @see javax.accessibility.AccessibleText#getSelectionStart()
277 public int getSelectionStart() {
278 // TODO Auto-generated method stub
279 return selectionStart;
283 * @see javax.accessibility.AccessibleText#getSelectionEnd()
285 public int getSelectionEnd()
291 * @see javax.accessibility.AccessibleText#getSelectedText()
293 public String getSelectedText()
295 if (selectionEnd - selectionStart > 0)
296 return text.substring(selectionStart, selectionEnd);
302 * @see java.awt.event.TextListener#textValueChanged(java.awt.event.TextEvent)
304 public void textValueChanged(TextEvent event)
306 // TODO Auto-generated method stub
313 TextComponent(String text)
320 this.editable = true;
325 * Returns the text in this component
327 * @return The text in this component.
329 public synchronized String getText()
331 TextComponentPeer tcp = (TextComponentPeer) getPeer();
333 text = tcp.getText();
339 * Sets the text in this component to the specified string.
341 * @param text The new text for this component.
343 public synchronized void setText(String text)
350 TextComponentPeer tcp = (TextComponentPeer) getPeer();
357 * Returns a string that contains the text that is currently selected.
359 * @return The currently selected text region.
361 public synchronized String getSelectedText()
363 String alltext = getText();
364 int start = getSelectionStart();
365 int end = getSelectionEnd();
367 return(alltext.substring(start, end));
371 * Returns the starting position of the selected text region.
372 * If the text is not selected then caret position is returned.
374 * @return The starting position of the selected text region.
376 public synchronized int getSelectionStart()
378 TextComponentPeer tcp = (TextComponentPeer) getPeer();
380 selectionStart = tcp.getSelectionStart();
382 return(selectionStart);
386 * Sets the starting position of the selected region to the
387 * specified value. If the specified value is out of range, then it
388 * will be silently changed to the nearest legal value.
390 * @param selectionStart The new start position for selected text.
392 public synchronized void setSelectionStart(int selectionStart)
394 select(selectionStart,
395 (getSelectionEnd() < selectionStart)
396 ? selectionStart : getSelectionEnd());
400 * Returns the ending position of the selected text region.
401 * If the text is not selected, then caret position is returned
403 * @return The ending position of the selected text region.
405 public synchronized int getSelectionEnd()
407 TextComponentPeer tcp = (TextComponentPeer) getPeer();
409 selectionEnd = tcp.getSelectionEnd();
411 return(selectionEnd);
415 * Sets the ending position of the selected region to the
416 * specified value. If the specified value is out of range, then it
417 * will be silently changed to the nearest legal value.
419 * @param selectionEnd The new start position for selected text.
421 public synchronized void setSelectionEnd(int selectionEnd)
423 select(getSelectionStart(), selectionEnd);
427 * This method sets the selected text range to the text between the
428 * specified start and end positions. Illegal values for these
429 * positions are silently fixed.
431 * @param selectionStart The new start position for the selected text.
432 * @param selectionEnd The new end position for the selected text.
434 public synchronized void select(int selectionStart, int selectionEnd)
436 if (selectionStart < 0)
439 if (selectionStart > getText().length())
440 selectionStart = text.length();
442 if (selectionEnd > text.length())
443 selectionEnd = text.length();
445 if (selectionStart > selectionEnd)
446 selectionStart = selectionEnd;
448 this.selectionStart = selectionStart;
449 this.selectionEnd = selectionEnd;
451 TextComponentPeer tcp = (TextComponentPeer) getPeer();
453 tcp.select(selectionStart, selectionEnd);
457 * Selects all of the text in the component.
459 public synchronized void selectAll()
461 select(0, getText().length());
465 * Returns the current caret position in the text.
467 * @return The caret position in the text.
469 public synchronized int getCaretPosition()
471 TextComponentPeer tcp = (TextComponentPeer) getPeer();
473 return(tcp.getCaretPosition());
479 * Sets the caret position to the specified value.
481 * @param caretPosition The new caret position.
483 * @exception IllegalArgumentException If the value supplied for position
488 public synchronized void setCaretPosition(int caretPosition)
490 if (caretPosition < 0)
491 throw new IllegalArgumentException();
493 TextComponentPeer tcp = (TextComponentPeer) getPeer();
495 tcp.setCaretPosition(caretPosition);
499 * Tests whether or not this component's text can be edited.
501 * @return <code>true</code> if the text can be edited, <code>false</code>
504 public boolean isEditable()
510 * Sets whether or not this component's text can be edited.
512 * @param editable <code>true</code> to enable editing of the text,
513 * <code>false</code> to disable it.
515 public synchronized void setEditable(boolean editable)
517 this.editable = editable;
519 TextComponentPeer tcp = (TextComponentPeer) getPeer();
521 tcp.setEditable(editable);
525 * Notifies the component that it should destroy its native peer.
527 public void removeNotify()
529 super.removeNotify();
533 * Adds a new listener to the list of text listeners for this
536 * @param listener The listener to be added.
538 public synchronized void addTextListener(TextListener listener)
540 textListener = AWTEventMulticaster.add(textListener, listener);
542 enableEvents(AWTEvent.TEXT_EVENT_MASK);
546 * Removes the specified listener from the list of listeners
547 * for this component.
549 * @param listener The listener to remove.
551 public synchronized void removeTextListener(TextListener listener)
553 textListener = AWTEventMulticaster.remove(textListener, listener);
557 * Processes the specified event for this component. Text events are
558 * processed by calling the <code>processTextEvent()</code> method.
559 * All other events are passed to the superclass method.
561 * @param event The event to process.
563 protected void processEvent(AWTEvent event)
565 if (event instanceof TextEvent)
566 processTextEvent((TextEvent)event);
568 super.processEvent(event);
572 * Processes the specified text event by dispatching it to any listeners
573 * that are registered. Note that this method will only be called
574 * if text event's are enabled. This will be true if there are any
575 * registered listeners, or if the event has been specifically
576 * enabled using <code>enableEvents()</code>.
578 * @param event The text event to process.
580 protected void processTextEvent(TextEvent event)
582 if (textListener != null)
583 textListener.textValueChanged(event);
586 void dispatchEventImpl(AWTEvent e)
588 if (e.id <= TextEvent.TEXT_LAST
589 && e.id >= TextEvent.TEXT_FIRST
590 && (textListener != null
591 || (eventMask & AWTEvent.TEXT_EVENT_MASK) != 0))
594 super.dispatchEventImpl(e);
598 * Returns a debugging string.
600 * @return A debugging string.
602 protected String paramString()
604 return(getClass().getName() + "(text=" + getText() + ")");
608 * Returns an array of all the objects currently registered as FooListeners
609 * upon this <code>TextComponent</code>. FooListeners are registered using
610 * the addFooListener method.
612 * @exception ClassCastException If listenerType doesn't specify a class or
613 * interface that implements java.util.EventListener.
615 public <T extends EventListener> T[] getListeners(Class<T> listenerType)
617 if (listenerType == TextListener.class)
618 return AWTEventMulticaster.getListeners(textListener, listenerType);
620 return super.getListeners(listenerType);
624 * Returns all text listeners registered to this object.
626 public TextListener[] getTextListeners()
628 return (TextListener[]) getListeners(TextListener.class);
632 * Gets the AccessibleContext associated with this <code>TextComponent</code>.
633 * The context is created, if necessary.
635 * @return the associated context
637 public AccessibleContext getAccessibleContext()
639 /* Create the context if this is the first request */
640 if (accessibleContext == null)
641 accessibleContext = new AccessibleAWTTextComponent();
642 return accessibleContext;
646 // Provide AccessibleAWTTextComponent access to several peer functions that
647 // aren't publicly exposed. This is package-private to avoid an accessor
649 synchronized int getIndexAtPoint(Point p)
651 TextComponentPeer tcp = (TextComponentPeer) getPeer();
653 return tcp.getIndexAtPoint(p.x, p.y);
657 synchronized Rectangle getCharacterBounds(int i)
659 TextComponentPeer tcp = (TextComponentPeer) getPeer();
661 return tcp.getCharacterBounds(i);
666 * All old mouse events for this component should
669 * @return true to ignore all old mouse events.
671 static boolean ignoreOldMouseEvents()
676 } // class TextComponent