Merge from the pain train
[official-gcc.git] / libjava / java / awt / TextComponent.java
blob4c384391adf6817983d78b92d121ab3e12810875
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)
9 any later version.
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
19 02111-1307 USA.
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
24 combination.
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. */
39 package java.awt;
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;
56 /**
57 * This class provides common functionality for widgets than
58 * contain text.
60 * @author Aaron M. Renn (arenn@urbanophile.com)
62 public class TextComponent extends Component
63 implements Serializable, Accessible
67 * Static Variables
70 // Constant for serialization
71 private static final long serialVersionUID = -2214773872412987419L;
74 * Instance Variables
77 /**
78 * @serial Indicates whether or not this component is editable.
80 private boolean editable;
82 /**
83 * @serial The starting position of the selected text region.
85 private int selectionStart;
87 /**
88 * @serial The ending position of the selected text region.
90 private int selectionEnd;
92 /**
93 * @serial The text in the component
95 private String text;
97 /**
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
106 // Constructor
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();
123 if (editable)
124 ss.add(AccessibleState.EDITABLE);
125 return ss;
128 public AccessibleText getAccessibleText()
130 return this;
133 /* (non-Javadoc)
134 * @see javax.accessibility.AccessibleText#getIndexAtPoint(java.awt.Point)
136 public int getIndexAtPoint(Point point)
138 return TextComponent.this.getIndexAtPoint(point);
141 /* (non-Javadoc)
142 * @see javax.accessibility.AccessibleText#getCharacterBounds(int)
144 public Rectangle getCharacterBounds(int index)
146 return TextComponent.this.getCharacterBounds(index);
149 /* (non-Javadoc)
150 * @see javax.accessibility.AccessibleText#getCharCount()
152 public int getCharCount()
154 return text.length();
157 /* (non-Javadoc)
158 * @see javax.accessibility.AccessibleText#getCaretPosition()
160 public int getCaretPosition()
162 return TextComponent.this.getCaretPosition();
165 /* (non-Javadoc)
166 * @see javax.accessibility.AccessibleText#getAtIndex(int, int)
168 public String getAtIndex(int part, int index)
170 if (index < 0 || index >= text.length())
171 return null;
172 BreakIterator it = null;
173 switch (part)
175 case CHARACTER:
176 return text.substring(index, index + 1);
177 case WORD:
178 it = BreakIterator.getWordInstance();
179 break;
180 case SENTENCE:
181 it = BreakIterator.getSentenceInstance();
182 break;
183 default:
184 return null;
186 it.setText(text);
187 int start = index;
188 if (!it.isBoundary(index))
189 start = it.preceding(index);
190 int end = it.following(index);
191 if (end == -1)
192 return text.substring(index);
193 else
194 return text.substring(index, end);
197 /* (non-Javadoc)
198 * @see javax.accessibility.AccessibleText#getAfterIndex(int, int)
200 public String getAfterIndex(int part, int index) {
201 if (index < 0 || index >= text.length())
202 return null;
203 BreakIterator it = null;
204 switch (part)
206 case CHARACTER:
207 return text.substring(index, index + 1);
208 case WORD:
209 it = BreakIterator.getWordInstance();
210 break;
211 case SENTENCE:
212 it = BreakIterator.getSentenceInstance();
213 break;
214 default:
215 return null;
217 it.setText(text);
218 int start = index;
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.
223 if (start == -1)
224 return null;
225 int end = it.following(start);
226 if (end == -1)
227 return text.substring(index);
228 else
229 return text.substring(index, end);
232 /* (non-Javadoc)
233 * @see javax.accessibility.AccessibleText#getBeforeIndex(int, int)
235 public String getBeforeIndex(int part, int index)
237 if (index < 1 || index >= text.length())
238 return null;
239 BreakIterator it = null;
240 switch (part)
242 case CHARACTER:
243 return text.substring(index - 1, index);
244 case WORD:
245 it = BreakIterator.getWordInstance();
246 break;
247 case SENTENCE:
248 it = BreakIterator.getSentenceInstance();
249 break;
250 default:
251 return null;
253 it.setText(text);
254 int end = index;
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.
259 if (end == -1)
260 return null;
261 int start = it.preceding(end);
262 if (start == -1)
263 return text.substring(0, end);
264 else
265 return text.substring(start, end);
268 /* (non-Javadoc)
269 * @see javax.accessibility.AccessibleText#getCharacterAttribute(int)
271 public AttributeSet getCharacterAttribute(int index)
273 // FIXME: I suspect this really gets filled in by subclasses.
274 return null;
277 /* (non-Javadoc)
278 * @see javax.accessibility.AccessibleText#getSelectionStart()
280 public int getSelectionStart() {
281 // TODO Auto-generated method stub
282 return selectionStart;
285 /* (non-Javadoc)
286 * @see javax.accessibility.AccessibleText#getSelectionEnd()
288 public int getSelectionEnd()
290 return selectionEnd;
293 /* (non-Javadoc)
294 * @see javax.accessibility.AccessibleText#getSelectedText()
296 public String getSelectedText()
298 if (selectionEnd - selectionStart > 0)
299 return text.substring(selectionStart, selectionEnd);
300 else
301 return null;
304 /* (non-Javadoc)
305 * @see java.awt.event.TextListener#textValueChanged(java.awt.event.TextEvent)
307 public void textValueChanged(TextEvent event)
309 // TODO Auto-generated method stub
315 /*************************************************************************/
318 * Constructors
321 TextComponent(String text)
323 this.text = text;
324 this.editable = true;
327 /*************************************************************************/
330 * Instance Methods
334 * Returns the text in this component
336 * @return The text in this component.
338 public synchronized String
339 getText()
341 TextComponentPeer tcp = (TextComponentPeer)getPeer();
342 if (tcp != null)
343 text = tcp.getText();
345 return(text);
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
356 setText(String text)
358 if (text == null)
359 text = "";
361 this.text = text;
363 TextComponentPeer tcp = (TextComponentPeer)getPeer();
364 if (tcp != null)
365 tcp.setText(text);
366 setCaretPosition(0);
369 /*************************************************************************/
372 * Returns a string that contains the text that is currently selected.
374 * @return The currently selected text region.
376 public synchronized String
377 getSelectedText()
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
395 getSelectionStart()
397 TextComponentPeer tcp = (TextComponentPeer)getPeer();
398 if (tcp != null)
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
428 getSelectionEnd()
430 TextComponentPeer tcp = (TextComponentPeer)getPeer();
431 if (tcp != null)
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)
466 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();
481 if (tcp != null)
482 tcp.select(selectionStart, selectionEnd);
485 /*************************************************************************/
488 * Selects all of the text in the component.
490 public synchronized void
491 selectAll()
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
504 getCaretPosition()
506 TextComponentPeer tcp = (TextComponentPeer)getPeer();
507 if (tcp != null)
508 return(tcp.getCaretPosition());
509 else
510 return(0);
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
521 * is less than zero.
523 * @since 1.1
525 public synchronized void
526 setCaretPosition(int caretPosition)
528 if (caretPosition < 0)
529 throw new IllegalArgumentException ();
531 TextComponentPeer tcp = (TextComponentPeer)getPeer();
532 if (tcp != null)
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>
542 * otherwise.
544 public boolean
545 isEditable()
547 return(editable);
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();
564 if (tcp != null)
565 tcp.setEditable(editable);
568 /*************************************************************************/
571 * Notifies the component that it should destroy its native peer.
573 public void
574 removeNotify()
576 super.removeNotify();
579 /*************************************************************************/
582 * Adds a new listener to the list of text listeners for this
583 * component.
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.
618 protected void
619 processEvent(AWTEvent event)
621 if (event instanceof TextEvent)
622 processTextEvent((TextEvent)event);
623 else
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.
638 protected void
639 processTextEvent(TextEvent event)
641 if (textListener != null)
642 textListener.textValueChanged(event);
645 void
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))
652 processEvent(e);
653 else
654 super.dispatchEventImpl(e);
657 /*************************************************************************/
660 * Returns a debugging string.
662 * @return A debugging string.
664 protected String
665 paramString()
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();
716 if (tcp != null)
717 return tcp.getIndexAtPoint(p.x, p.y);
718 return -1;
721 private synchronized Rectangle
722 getCharacterBounds(int i)
724 TextComponentPeer tcp = (TextComponentPeer)getPeer();
725 if (tcp != null)
726 return tcp.getCharacterBounds(i);
727 return null;
733 } // class TextComponent