1 /* TextComponent.java -- Widgets for entering text
2 Copyright (C) 1999, 2002, 2003 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., 59 Temple Place, Suite 330, 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
70 // Constant for serialization
71 private static final long serialVersionUID
= -2214773872412987419L;
78 * @serial Indicates whether or not this component is editable.
80 private boolean editable
;
83 * @serial The starting position of the selected text region.
85 private int selectionStart
;
88 * @serial The ending position of the selected text region.
90 private int selectionEnd
;
93 * @serial The text in the component
98 * A list of listeners that will receive events from this object.
100 protected transient TextListener textListener
;
102 protected class AccessibleAWTTextComponent
103 extends AccessibleAWTComponent
104 implements AccessibleText
, TextListener
107 // Adds a listener for tracking caret changes
108 public AccessibleAWTTextComponent()
110 TextComponent
.this.addTextListener(this);
113 public AccessibleRole
getAccessibleRole()
115 return AccessibleRole
.TEXT
;
118 public AccessibleStateSet
getAccessibleStateSet()
120 // TODO: Docs say PropertyChangeEvent will fire if this state changes.
121 // That means that the event has to fire when editable changes.
122 AccessibleStateSet ss
= super.getAccessibleStateSet();
124 ss
.add(AccessibleState
.EDITABLE
);
128 public AccessibleText
getAccessibleText()
134 * @see javax.accessibility.AccessibleText#getIndexAtPoint(java.awt.Point)
136 public int getIndexAtPoint(Point point
)
138 return TextComponent
.this.getIndexAtPoint(point
);
142 * @see javax.accessibility.AccessibleText#getCharacterBounds(int)
144 public Rectangle
getCharacterBounds(int index
)
146 return TextComponent
.this.getCharacterBounds(index
);
150 * @see javax.accessibility.AccessibleText#getCharCount()
152 public int getCharCount()
154 return text
.length();
158 * @see javax.accessibility.AccessibleText#getCaretPosition()
160 public int getCaretPosition()
162 return TextComponent
.this.getCaretPosition();
166 * @see javax.accessibility.AccessibleText#getAtIndex(int, int)
168 public String
getAtIndex(int part
, int index
)
170 if (index
< 0 || index
>= text
.length())
172 BreakIterator it
= null;
176 return text
.substring(index
, index
+ 1);
178 it
= BreakIterator
.getWordInstance();
181 it
= BreakIterator
.getSentenceInstance();
188 if (!it
.isBoundary(index
))
189 start
= it
.preceding(index
);
190 int end
= it
.following(index
);
192 return text
.substring(index
);
194 return text
.substring(index
, end
);
198 * @see javax.accessibility.AccessibleText#getAfterIndex(int, int)
200 public String
getAfterIndex(int part
, int index
) {
201 if (index
< 0 || index
>= text
.length())
203 BreakIterator it
= null;
207 return text
.substring(index
, index
+ 1);
209 it
= BreakIterator
.getWordInstance();
212 it
= BreakIterator
.getSentenceInstance();
219 if (!it
.isBoundary(index
))
220 start
= it
.following(index
);
221 // Make sure there was a complete unit. I.e. if index is in the middle
222 // of a word, return null if there is no word after the that one.
225 int end
= it
.following(start
);
227 return text
.substring(index
);
229 return text
.substring(index
, end
);
233 * @see javax.accessibility.AccessibleText#getBeforeIndex(int, int)
235 public String
getBeforeIndex(int part
, int index
)
237 if (index
< 1 || index
>= text
.length())
239 BreakIterator it
= null;
243 return text
.substring(index
- 1, index
);
245 it
= BreakIterator
.getWordInstance();
248 it
= BreakIterator
.getSentenceInstance();
255 if (!it
.isBoundary(index
))
256 end
= it
.preceding(index
);
257 // Make sure there was a complete unit. I.e. if index is in the middle
258 // of a word, return null if there is no word before that one.
261 int start
= it
.preceding(end
);
263 return text
.substring(0, end
);
265 return text
.substring(start
, end
);
269 * @see javax.accessibility.AccessibleText#getCharacterAttribute(int)
271 public AttributeSet
getCharacterAttribute(int index
)
273 // FIXME: I suspect this really gets filled in by subclasses.
278 * @see javax.accessibility.AccessibleText#getSelectionStart()
280 public int getSelectionStart() {
281 // TODO Auto-generated method stub
282 return selectionStart
;
286 * @see javax.accessibility.AccessibleText#getSelectionEnd()
288 public int getSelectionEnd()
294 * @see javax.accessibility.AccessibleText#getSelectedText()
296 public String
getSelectedText()
298 if (selectionEnd
- selectionStart
> 0)
299 return text
.substring(selectionStart
, selectionEnd
);
305 * @see java.awt.event.TextListener#textValueChanged(java.awt.event.TextEvent)
307 public void textValueChanged(TextEvent event
)
309 // TODO Auto-generated method stub
315 /*************************************************************************/
321 TextComponent(String text
)
324 this.editable
= true;
327 /*************************************************************************/
334 * Returns the text in this component
336 * @return The text in this component.
338 public synchronized String
341 TextComponentPeer tcp
= (TextComponentPeer
)getPeer();
343 text
= tcp
.getText();
348 /*************************************************************************/
351 * Sets the text in this component to the specified string.
353 * @param text The new text for this component.
355 public synchronized void
363 TextComponentPeer tcp
= (TextComponentPeer
)getPeer();
369 /*************************************************************************/
372 * Returns a string that contains the text that is currently selected.
374 * @return The currently selected text region.
376 public synchronized String
379 String alltext
= getText();
380 int start
= getSelectionStart();
381 int end
= getSelectionEnd();
383 return(alltext
.substring(start
, end
));
386 /*************************************************************************/
389 * Returns the starting position of the selected text region.
390 * If the text is not selected then caret position is returned.
392 * @return The starting position of the selected text region.
394 public synchronized int
397 TextComponentPeer tcp
= (TextComponentPeer
)getPeer();
399 selectionStart
= tcp
.getSelectionStart();
401 return(selectionStart
);
404 /*************************************************************************/
407 * Sets the starting position of the selected region to the
408 * specified value. If the specified value is out of range, then it
409 * will be silently changed to the nearest legal value.
411 * @param selectionStart The new start position for selected text.
413 public synchronized void
414 setSelectionStart(int selectionStart
)
416 select(selectionStart
, getSelectionEnd());
419 /*************************************************************************/
422 * Returns the ending position of the selected text region.
423 * If the text is not selected, then caret position is returned
425 * @return The ending position of the selected text region.
427 public synchronized int
430 TextComponentPeer tcp
= (TextComponentPeer
)getPeer();
432 selectionEnd
= tcp
.getSelectionEnd();
434 return(selectionEnd
);
437 /*************************************************************************/
440 * Sets the ending position of the selected region to the
441 * specified value. If the specified value is out of range, then it
442 * will be silently changed to the nearest legal value.
444 * @param selectionEnd The new start position for selected text.
446 public synchronized void
447 setSelectionEnd(int selectionEnd
)
449 select(getSelectionStart(), selectionEnd
);
452 /*************************************************************************/
455 * This method sets the selected text range to the text between the
456 * specified start and end positions. Illegal values for these
457 * positions are silently fixed.
459 * @param selectionStart The new start position for the selected text.
460 * @param selectionEnd The new end position for the selected text.
462 public synchronized void
463 select(int selectionStart
, int selectionEnd
)
465 if (selectionStart
< 0)
468 if (selectionStart
> getText().length())
469 selectionStart
= text
.length();
471 if (selectionEnd
> text
.length())
472 selectionEnd
= text
.length();
474 if (selectionStart
> getSelectionEnd())
475 selectionStart
= selectionEnd
;
477 this.selectionStart
= selectionStart
;
478 this.selectionEnd
= selectionEnd
;
480 TextComponentPeer tcp
= (TextComponentPeer
)getPeer();
482 tcp
.select(selectionStart
, selectionEnd
);
485 /*************************************************************************/
488 * Selects all of the text in the component.
490 public synchronized void
493 select(0, getText().length());
496 /*************************************************************************/
499 * Returns the current caret position in the text.
501 * @return The caret position in the text.
503 public synchronized int
506 TextComponentPeer tcp
= (TextComponentPeer
)getPeer();
508 return(tcp
.getCaretPosition());
513 /*************************************************************************/
516 * Sets the caret position to the specified value.
518 * @param caretPosition The new caret position.
520 * @exception IllegalArgumentException If the value supplied for position
525 public synchronized void
526 setCaretPosition(int caretPosition
)
528 if (caretPosition
< 0)
529 throw new IllegalArgumentException ();
531 TextComponentPeer tcp
= (TextComponentPeer
)getPeer();
533 tcp
.setCaretPosition(caretPosition
);
536 /*************************************************************************/
539 * Tests whether or not this component's text can be edited.
541 * @return <code>true</code> if the text can be edited, <code>false</code>
550 /*************************************************************************/
553 * Sets whether or not this component's text can be edited.
555 * @param editable <code>true</code> to enable editing of the text,
556 * <code>false</code> to disable it.
558 public synchronized void
559 setEditable(boolean editable
)
561 this.editable
= editable
;
563 TextComponentPeer tcp
= (TextComponentPeer
)getPeer();
565 tcp
.setEditable(editable
);
568 /*************************************************************************/
571 * Notifies the component that it should destroy its native peer.
576 super.removeNotify();
579 /*************************************************************************/
582 * Adds a new listener to the list of text listeners for this
585 * @param listener The listener to be added.
587 public synchronized void
588 addTextListener(TextListener listener
)
590 textListener
= AWTEventMulticaster
.add(textListener
, listener
);
592 enableEvents(AWTEvent
.TEXT_EVENT_MASK
);
595 /*************************************************************************/
598 * Removes the specified listener from the list of listeners
599 * for this component.
601 * @param listener The listener to remove.
603 public synchronized void
604 removeTextListener(TextListener listener
)
606 textListener
= AWTEventMulticaster
.remove(textListener
, listener
);
609 /*************************************************************************/
612 * Processes the specified event for this component. Text events are
613 * processed by calling the <code>processTextEvent()</code> method.
614 * All other events are passed to the superclass method.
616 * @param event The event to process.
619 processEvent(AWTEvent event
)
621 if (event
instanceof TextEvent
)
622 processTextEvent((TextEvent
)event
);
624 super.processEvent(event
);
627 /*************************************************************************/
630 * Processes the specified text event by dispatching it to any listeners
631 * that are registered. Note that this method will only be called
632 * if text event's are enabled. This will be true if there are any
633 * registered listeners, or if the event has been specifically
634 * enabled using <code>enableEvents()</code>.
636 * @param event The text event to process.
639 processTextEvent(TextEvent event
)
641 if (textListener
!= null)
642 textListener
.textValueChanged(event
);
646 dispatchEventImpl(AWTEvent e
)
648 if (e
.id
<= TextEvent
.TEXT_LAST
649 && e
.id
>= TextEvent
.TEXT_FIRST
650 && (textListener
!= null
651 || (eventMask
& AWTEvent
.TEXT_EVENT_MASK
) != 0))
654 super.dispatchEventImpl(e
);
657 /*************************************************************************/
660 * Returns a debugging string.
662 * @return A debugging string.
667 return(getClass().getName() + "(text=" + getText() + ")");
671 * Returns an array of all the objects currently registered as FooListeners
672 * upon this <code>TextComponent</code>. FooListeners are registered using
673 * the addFooListener method.
675 * @exception ClassCastException If listenerType doesn't specify a class or
676 * interface that implements java.util.EventListener.
678 public EventListener
[] getListeners (Class listenerType
)
680 if (listenerType
== TextListener
.class)
681 return AWTEventMulticaster
.getListeners (textListener
, listenerType
);
683 return super.getListeners (listenerType
);
687 * Returns all text listeners registered to this object.
689 public TextListener
[] getTextListeners ()
691 return (TextListener
[]) getListeners (TextListener
.class);
695 * Gets the AccessibleContext associated with this <code>TextComponent</code>.
696 * The context is created, if necessary.
698 * @return the associated context
700 public AccessibleContext
getAccessibleContext()
702 /* Create the context if this is the first request */
703 if (accessibleContext
== null)
704 accessibleContext
= new AccessibleAWTTextComponent();
705 return accessibleContext
;
709 /*******************************/
710 // Provide AccessibleAWTTextComponent access to several peer functions that
711 // aren't publicly exposed.
712 private synchronized int
713 getIndexAtPoint(Point p
)
715 TextComponentPeer tcp
= (TextComponentPeer
)getPeer();
717 return tcp
.getIndexAtPoint(p
.x
, p
.y
);
721 private synchronized Rectangle
722 getCharacterBounds(int i
)
724 TextComponentPeer tcp
= (TextComponentPeer
)getPeer();
726 return tcp
.getCharacterBounds(i
);
733 } // class TextComponent