View Javadoc

1   /*
2    * Copyright (c) 1998, 2005 Gargoyle Software Inc. All rights reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, are permitted provided that the following conditions are met:
6    *
7    * 1. Redistributions of source code must retain the above copyright notice,
8    *    this list of conditions and the following disclaimer.
9    * 2. Redistributions in binary form must reproduce the above copyright notice,
10   *    this list of conditions and the following disclaimer in the documentation
11   *    and/or other materials provided with the distribution.
12   * 3. The end-user documentation included with the redistribution, if any, must
13   *    include the following acknowledgment:
14   *
15   *       "This product includes software developed by Gargoyle Software Inc.
16   *        (http://www.GargoyleSoftware.com/)."
17   *
18   *    Alternately, this acknowledgment may appear in the software itself, if
19   *    and wherever such third-party acknowledgments normally appear.
20   * 4. The name "Gargoyle Software" must not be used to endorse or promote
21   *    products derived from this software without prior written permission.
22   *    For written permission, please contact info@GargoyleSoftware.com.
23   * 5. Products derived from this software may not be called "GSBase", nor may
24   *    "GSBase" appear in their name, without prior written permission of
25   *    Gargoyle Software Inc.
26   *
27   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
28   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
29   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
30   * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
33   * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
36   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37   */
38  package com.gargoylesoftware.base.util;
39  
40  import javax.swing.event.DocumentListener;
41  import javax.swing.event.UndoableEditListener;
42  import javax.swing.text.AttributeSet;
43  import javax.swing.text.BadLocationException;
44  import javax.swing.text.Document;
45  import javax.swing.text.Element;
46  import javax.swing.text.PlainDocument;
47  import javax.swing.text.Position;
48  import javax.swing.text.Segment;
49  
50  /***
51   * Various utility methods relating to documents.
52   *
53   * @version $Revision: 1.5 $
54   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
55   */
56  public class DocumentUtil {
57  
58      /***
59       * Private constructor to prevent instantiation of this class.
60       */
61      private DocumentUtil() {
62      }
63  
64      /***
65       * Return a wrapper document that converts all input to uppercase.
66       * @param document The document to wrapper.
67       * @return The new wrapper document.
68       */
69      public static Document upperCaseDocument( final Document document ) {
70          return new PassthroughDocument(document) {
71              public void insertString(
72                      final int offset,
73                      final String str,
74                      final AttributeSet a)
75                  throws
76                      BadLocationException {
77  
78                  super.insertString(offset, str.toUpperCase(), a);
79              }
80          };
81      }
82  
83      /***
84       * Return a PlainDocument wrappered so that it accepts uppercase
85       * input only.
86       * @return The new wrapper document.
87       */
88      public static Document upperCaseDocument() {
89          return upperCaseDocument( new PlainDocument() );
90      }
91  
92      /***
93       * Return a wrapper document that prevents the user from typing more
94       * than a specified number of characters.
95       * @param document The document to wrapper.
96       * @param maxLength The maximum number of characters that can be placed in
97       * this document.
98       * @return The new wrapper document.
99       */
100     public static Document lengthLimitedDocument( final Document document,
101                                                   final int maxLength ) {
102         return new LengthLimitedDocument(document,maxLength);
103     }
104 
105     /***
106      * Return a PlainDocument wrappered so that it is length limited.
107      * @param maxLength The maximum number of characters that can be placed in
108      * this document.
109      * @return The new wrapper document.
110      */
111     public static Document lengthLimitedDocument( final int maxLength ) {
112         return lengthLimitedDocument( new PlainDocument(), maxLength );
113     }
114 
115     /***
116      * A wrapper document that prevents the user from typing more than
117      * a specified number of characters.
118      */
119     private static class LengthLimitedDocument extends PassthroughDocument {
120         private int maxLength_;
121 
122         /***
123          * Create an instance
124          * @param document The document to wrap
125          * @param maxLength The maximum number of characters that can be entered into this document
126          */
127         public LengthLimitedDocument( final Document document,
128                                       final int maxLength ) {
129             super(document);
130             if( maxLength < 0 ) {
131                 throw new DetailedIllegalArgumentException(
132                     "maxLength", new Integer(maxLength), "May not be less than zero");
133             }
134             maxLength_ = maxLength;
135         }
136         /*** @inheritDoc Document.insertString(int,String,AttributeSet) */
137         public void insertString(
138                 final int offset,
139                 final String string,
140                 final AttributeSet attributeSet)
141             throws
142                 BadLocationException {
143 
144             final int documentLength = getLength();
145             final int stringLength = string.length();
146 
147             if( documentLength == maxLength_ ) {
148                 return;
149             }
150             else if( documentLength + stringLength <= maxLength_ ) {
151                 super.insertString( offset, string, attributeSet );
152             }
153             else {
154                 super.insertString( offset,
155                                     string.substring(0, maxLength_ - documentLength),
156                                     attributeSet );
157             }
158         }
159     }
160 
161     /***
162      * A document that merely passes all requests through to another document.
163      * This is used as the base class for the custom documents provided here.
164      */
165     private abstract static class PassthroughDocument implements Document {
166         private final Document delegate_;
167 
168         /***
169          * Create an instance
170          * @param delegate The document to wrap.
171          */
172         public PassthroughDocument( final Document delegate ) {
173             if( delegate == null ) {
174                 throw new DetailedNullPointerException("delegate");
175             }
176             delegate_ = delegate;
177         }
178         /*** @inheritDoc Document.getLength() */
179         public int getLength() {
180             return delegate_.getLength();
181         }
182 
183         /*** @inheritDoc Document.addDocumentListener(DocumentListener) */
184         public void addDocumentListener(DocumentListener listener) {
185             delegate_.addDocumentListener(listener);
186         }
187 
188         /*** @inheritDoc Document.removeDocumentListener(DocumentListener) */
189         public void removeDocumentListener(DocumentListener listener) {
190             delegate_.removeDocumentListener(listener);
191         }
192 
193         /*** @inheritDoc Document.addUndoableEditListener(UndoableEditListener) */
194         public void addUndoableEditListener(UndoableEditListener listener) {
195             delegate_.addUndoableEditListener(listener);
196         }
197 
198         /*** @inheritDoc Document.removeUndoableEditListener(UndoableEditListener) */
199         public void removeUndoableEditListener(UndoableEditListener listener) {
200             delegate_.removeUndoableEditListener(listener);
201         }
202 
203         /*** @inheritDoc Document.getProperty(Object) */
204         public Object getProperty(Object key) {
205             return delegate_.getProperty(key);
206         }
207 
208         /*** @inheritDoc Document.putProperty(Object,Object) */
209         public void putProperty(Object key, Object value) {
210             delegate_.putProperty(key,value);
211         }
212 
213         /*** @inheritDoc Document.remove(int,int) */
214         public void remove(int offs, int len) throws BadLocationException {
215             delegate_.remove(offs, len);
216         }
217 
218         /*** @inheritDoc Document.insertString(int,String,AttributeSet) */
219         public void insertString(int offset, String str, AttributeSet a) throws BadLocationException {
220             delegate_.insertString(offset, str, a);
221         }
222 
223         /*** @inheritDoc Document.getText(int,int) */
224         public String getText(int offset, int length) throws BadLocationException {
225             return delegate_.getText(offset, length);
226         }
227 
228         /*** @inheritDoc Document.getText(int,int,Segment) */
229         public void getText(int offset, int length, Segment txt) throws BadLocationException {
230             delegate_.getText(offset, length, txt);
231         }
232 
233         /*** @inheritDoc Document.getStartPosition() */
234         public Position getStartPosition() {
235             return delegate_.getStartPosition();
236         }
237 
238         /*** @inheritDoc Document.getEndPosition() */
239         public Position getEndPosition() {
240             return delegate_.getEndPosition();
241         }
242 
243         /*** @inheritDoc Document.createPosition(int) */
244         public Position createPosition(int offs) throws BadLocationException {
245             return delegate_.createPosition(offs);
246         }
247 
248         /*** @inheritDoc getRootElements() */
249         public Element[] getRootElements() {
250             return delegate_.getRootElements();
251         }
252 
253         /*** @inheritDoc Document.getDefaultRootElement() */
254         public Element getDefaultRootElement() {
255             return delegate_.getDefaultRootElement();
256         }
257 
258         /*** @inheritDoc Document.render(Runnable) */
259         public void render(Runnable r) {
260             delegate_.render(r);
261         }
262     }
263 }
264