001/* ----------------------------------------------------------------------------
002   The Kiwi Toolkit - A Java Class Library
003   Copyright (C) 1998-2004 Mark A. Lindner
004
005   This library is free software; you can redistribute it and/or
006   modify it under the terms of the GNU General Public License as
007   published by the Free Software Foundation; either version 2 of the
008   License, or (at your option) any later version.
009
010   This library is distributed in the hope that it will be useful,
011   but WITHOUT ANY WARRANTY; without even the implied warranty of
012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013   General Public License for more details.
014
015   You should have received a copy of the GNU General Public License
016   along with this library; if not, write to the Free Software
017   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018   02111-1307, USA.
019 
020   The author may be contacted at: mark_a_lindner@yahoo.com
021   ----------------------------------------------------------------------------
022   $Log: KTextArea.java,v $
023   Revision 1.2  2004/05/14 00:15:52  markl
024   automatically turn on word wrapping
025
026   Revision 1.1  2004/03/22 07:00:32  markl
027   new class
028   ----------------------------------------------------------------------------
029*/
030
031package kiwi.ui;
032
033import javax.swing.*;
034import javax.swing.event.*;
035import javax.swing.text.*;
036
037import kiwi.event.*;
038import kiwi.ui.model.KDocument;
039
040/** A specialization of <code>JTextArea</code> that can constrain the
041 * length of its input. The text area is preconfigured to have
042 * word-style line wrapping.
043 *
044 * @author Mark Lindner
045 * @since Kiwi 2.0
046 */
047
048public class KTextArea extends JTextArea
049  {
050  private ChangeSupport csupport;
051  private _DocumentListener documentListener = null;
052  private boolean adjusting = false;
053
054  /** Construct a new <code>KTextArea</code>.
055   */
056  
057  public KTextArea()
058    {
059    super();
060    _init(KDocument.NO_LIMIT);
061    }
062
063  /** Construct a new <code>KTextArea</code> with the specified size.
064   *
065   * @param rows The number of rows.
066   * @param columns The number of columns.
067   */
068  
069  public KTextArea(int rows, int columns)
070    {
071    super(rows, columns);
072    _init(KDocument.NO_LIMIT);
073    }
074
075  /** Construct a new <code>KTextArea</code> with the specified text.
076   *
077   * @param text The text to display.
078   */
079  
080  public KTextArea(String text)
081    {
082    super(text);
083    _init(KDocument.NO_LIMIT);
084    }
085
086  /** Construct a new <code>KTextArea</code> with the specified size and
087   * text.
088   *
089   * @param text The text to display.
090   * @param rows The number of rows.
091   * @param columns The number of columns.
092   */
093  
094  public KTextArea(String text, int rows, int columns)
095    {
096    super(text, rows, columns);
097    _init(KDocument.NO_LIMIT);
098    }
099
100  /*
101   */
102
103  private void _init(int maxLength)
104    {
105    documentListener = new _DocumentListener();
106    csupport = new ChangeSupport(this);
107    KDocument doc = new KDocument(maxLength);
108    setDocument(doc);
109    doc.addDocumentListener(documentListener);
110
111    setLineWrap(true);
112    setWrapStyleWord(true);
113    }
114
115  /** Set the editable state of this text area.
116   *
117   * @param flag A flag specifying whether this text area should be editable.
118   * Non-editable text areas are made transparent.
119   */
120  
121  public void setEditable(boolean flag)
122    {
123    super.setEditable(flag);
124    setOpaque(flag);
125    }
126
127  /** Set the maximum number of characters that may be entered into
128   * this text area.  This method will have no effect if the document
129   * has been changed from a <code>KDocument</code> via a call to
130   * <code>setDocument()</code>.
131   *
132   * @param length The new maximum length, or <code>KDocument.NO_LIMIT</code>
133   * for unlimited length.
134   * @see kiwi.ui.model.KDocument
135   */
136
137  public void setMaximumLength(int length)
138    {
139    Document d = getDocument();
140    if(d instanceof KDocument)
141      ((KDocument)d).setMaximumLength(length);
142    }
143
144  /** Get the maxmium number of characters that may be entered into this text
145   * area.
146   *
147   * @return The maximum length, or <code>KDocument.NO_LIMIT</code> if there
148   * is no limit.
149   */
150  
151  public int getMaximumLength()
152    {
153    Document d = getDocument();
154    if(d instanceof KDocument)
155      return(((KDocument)d).getMaximumLength());
156    else
157      return(KDocument.NO_LIMIT);
158    }
159
160  /** Set the document model for this text area.
161   *
162   * @param doc The new document model.
163   */
164  
165  public void setDocument(Document doc)
166    {
167    super.setDocument(doc);
168
169    Document oldDoc = getDocument();
170
171    if((documentListener != null) && (oldDoc != null))
172      {
173      oldDoc.removeDocumentListener(documentListener);
174      doc.addDocumentListener(documentListener);
175      }
176    }
177
178  /** Add a <code>ChangeListener</code> to this component's list of listeners.
179   * <code>ChangeEvent</code>s are fired when this text area's document model
180   * changes.
181   *
182   * @param listener The listener to add.
183   */
184  
185  public void addChangeListener(ChangeListener listener)
186    {
187    csupport.addChangeListener(listener);
188    }
189
190  /** Remove a <code>ChangeListener</code> from this component's list
191   * of listeners.
192   *
193   * @param listener The listener to remove.
194   */
195  
196  public void removeChangeListener(ChangeListener listener)
197    {
198    csupport.removeChangeListener(listener);
199    }
200
201  /* document listener */
202  
203  private class _DocumentListener implements DocumentListener
204    {
205    public void changedUpdate(DocumentEvent evt)
206      {
207      _fireChange();
208      }
209
210    public void insertUpdate(DocumentEvent evt)
211      {
212      _fireChange();
213      }
214
215    public void removeUpdate(DocumentEvent evt)
216      {
217      _fireChange();
218      }
219    }
220
221  /* Delay-fire a change event, but only if the current DocumentEvent is not
222   * the result of a call to setText().
223   */
224
225  private void _fireChange()
226    {
227    if(adjusting)
228      return;
229
230    SwingUtilities.invokeLater(new Runnable()
231                               {
232                               public void run()
233                                 {
234                                 csupport.fireChangeEvent();
235                                 }
236                               });
237    }
238
239  /** Set the text to be displayed by this text area. A
240   * <code>ChangeEvent</code> will <i>not</i> be fired when the data
241   * in the text area is modified via this call.
242   *
243   * @param text The text to set.
244   */
245  
246  public final synchronized void setText(String text)
247    {
248    adjusting = true;
249    super.setText(text);
250    adjusting = false;
251    }
252  
253  }
254
255/* end of source file */