KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > text > PlainDocument


1 /*
2  * @(#)PlainDocument.java 1.43 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package javax.swing.text;
8
9 import java.util.Vector JavaDoc;
10 import javax.swing.event.*;
11
12 /**
13  * A plain document that maintains no character attributes. The
14  * default element structure for this document is a map of the lines in
15  * the text. The Element returned by getDefaultRootElement is
16  * a map of the lines, and each child element represents a line.
17  * This model does not maintain any character level attributes,
18  * but each line can be tagged with an arbitrary set of attributes.
19  * Line to offset, and offset to line translations can be quickly
20  * performed using the default root element. The structure information
21  * of the DocumentEvent's fired by edits will indicate the line
22  * structure changes.
23  * <p>
24  * The default content storage management is performed by a
25  * gapped buffer implementation (GapContent). It supports
26  * editing reasonably large documents with good efficiency when
27  * the edits are contiguous or clustered, as is typical.
28  * <p>
29  * <strong>Warning:</strong>
30  * Serialized objects of this class will not be compatible with
31  * future Swing releases. The current serialization support is
32  * appropriate for short term storage or RMI between applications running
33  * the same version of Swing. As of 1.4, support for long term storage
34  * of all JavaBeans<sup><font size="-2">TM</font></sup>
35  * has been added to the <code>java.beans</code> package.
36  * Please see {@link java.beans.XMLEncoder}.
37  *
38  * @author Timothy Prinzing
39  * @version 1.43 12/19/03
40  * @see Document
41  * @see AbstractDocument
42  */

43 public class PlainDocument extends AbstractDocument JavaDoc {
44
45     /**
46      * Name of the attribute that specifies the tab
47      * size for tabs contained in the content. The
48      * type for the value is Integer.
49      */

50     public static final String JavaDoc tabSizeAttribute = "tabSize";
51
52     /**
53      * Name of the attribute that specifies the maximum
54      * length of a line, if there is a maximum length.
55      * The type for the value is Integer.
56      */

57     public static final String JavaDoc lineLimitAttribute = "lineLimit";
58
59     /**
60      * Constructs a plain text document. A default model using
61      * <code>GapContent</code> is constructed and set.
62      */

63     public PlainDocument() {
64     this(new GapContent JavaDoc());
65     }
66
67     /**
68      * Constructs a plain text document. A default root element is created,
69      * and the tab size set to 8.
70      *
71      * @param c the container for the content
72      */

73     public PlainDocument(Content c) {
74     super(c);
75     putProperty(tabSizeAttribute, new Integer JavaDoc(8));
76     defaultRoot = createDefaultRoot();
77     }
78
79     /**
80      * Inserts some content into the document.
81      * Inserting content causes a write lock to be held while the
82      * actual changes are taking place, followed by notification
83      * to the observers on the thread that grabbed the write lock.
84      * <p>
85      * This method is thread safe, although most Swing methods
86      * are not. Please see
87      * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
88      * and Swing</A> for more information.
89      *
90      * @param offs the starting offset >= 0
91      * @param str the string to insert; does nothing with null/empty strings
92      * @param a the attributes for the inserted content
93      * @exception BadLocationException the given insert position is not a valid
94      * position within the document
95      * @see Document#insertString
96      */

97     public void insertString(int offs, String JavaDoc str, AttributeSet JavaDoc a) throws BadLocationException JavaDoc {
98     // fields don't want to have multiple lines. We may provide a field-specific
99
// model in the future in which case the filtering logic here will no longer
100
// be needed.
101
Object JavaDoc filterNewlines = getProperty("filterNewlines");
102     if ((filterNewlines instanceof Boolean JavaDoc) && filterNewlines.equals(Boolean.TRUE)) {
103         if ((str != null) && (str.indexOf('\n') >= 0)) {
104         StringBuffer JavaDoc filtered = new StringBuffer JavaDoc(str);
105         int n = filtered.length();
106         for (int i = 0; i < n; i++) {
107             if (filtered.charAt(i) == '\n') {
108             filtered.setCharAt(i, ' ');
109             }
110         }
111         str = filtered.toString();
112         }
113     }
114     super.insertString(offs, str, a);
115     }
116
117     /**
118      * Gets the default root element for the document model.
119      *
120      * @return the root
121      * @see Document#getDefaultRootElement
122      */

123     public Element JavaDoc getDefaultRootElement() {
124     return defaultRoot;
125     }
126
127     /**
128      * Creates the root element to be used to represent the
129      * default document structure.
130      *
131      * @return the element base
132      */

133     protected AbstractElement createDefaultRoot() {
134     BranchElement map = (BranchElement) createBranchElement(null, null);
135     Element JavaDoc line = createLeafElement(map, null, 0, 1);
136     Element JavaDoc[] lines = new Element JavaDoc[1];
137     lines[0] = line;
138     map.replace(0, 0, lines);
139     return map;
140     }
141
142     /**
143      * Get the paragraph element containing the given position. Since this
144      * document only models lines, it returns the line instead.
145      */

146     public Element JavaDoc getParagraphElement(int pos){
147         Element JavaDoc lineMap = getDefaultRootElement();
148         return lineMap.getElement( lineMap.getElementIndex( pos ) );
149     }
150     
151     /**
152      * Updates document structure as a result of text insertion. This
153      * will happen within a write lock. Since this document simply
154      * maps out lines, we refresh the line map.
155      *
156      * @param chng the change event describing the dit
157      * @param attr the set of attributes for the inserted text
158      */

159     protected void insertUpdate(DefaultDocumentEvent chng, AttributeSet JavaDoc attr) {
160     removed.removeAllElements();
161     added.removeAllElements();
162     BranchElement lineMap = (BranchElement) getDefaultRootElement();
163     int offset = chng.getOffset();
164     int length = chng.getLength();
165     if (offset > 0) {
166       offset -= 1;
167       length += 1;
168     }
169     int index = lineMap.getElementIndex(offset);
170     Element JavaDoc rmCandidate = lineMap.getElement(index);
171     int rmOffs0 = rmCandidate.getStartOffset();
172     int rmOffs1 = rmCandidate.getEndOffset();
173     int lastOffset = rmOffs0;
174     try {
175             if (s == null) {
176                 s = new Segment JavaDoc();
177             }
178             getContent().getChars(offset, length, s);
179         boolean hasBreaks = false;
180         for (int i = 0; i < length; i++) {
181                 char c = s.array[s.offset + i];
182         if (c == '\n') {
183             int breakOffset = offset + i + 1;
184             added.addElement(createLeafElement(lineMap, null, lastOffset, breakOffset));
185             lastOffset = breakOffset;
186             hasBreaks = true;
187         }
188         }
189         if (hasBreaks) {
190         int rmCount = 1;
191         removed.addElement(rmCandidate);
192         if ((offset + length == rmOffs1) && (lastOffset != rmOffs1) &&
193             ((index+1) < lineMap.getElementCount())) {
194             rmCount += 1;
195             Element JavaDoc e = lineMap.getElement(index+1);
196             removed.addElement(e);
197             rmOffs1 = e.getEndOffset();
198         }
199         if (lastOffset < rmOffs1) {
200             added.addElement(createLeafElement(lineMap, null, lastOffset, rmOffs1));
201         }
202
203         Element JavaDoc[] aelems = new Element JavaDoc[added.size()];
204         added.copyInto(aelems);
205         Element JavaDoc[] relems = new Element JavaDoc[removed.size()];
206         removed.copyInto(relems);
207         ElementEdit ee = new ElementEdit(lineMap, index, relems, aelems);
208         chng.addEdit(ee);
209         lineMap.replace(index, relems.length, aelems);
210         }
211         if (Utilities.isComposedTextAttributeDefined(attr)) {
212             insertComposedTextUpdate(chng, attr);
213         }
214     } catch (BadLocationException JavaDoc e) {
215         throw new Error JavaDoc("Internal error: " + e.toString());
216     }
217     super.insertUpdate(chng, attr);
218     }
219
220     /**
221      * Updates any document structure as a result of text removal.
222      * This will happen within a write lock. Since the structure
223      * represents a line map, this just checks to see if the
224      * removal spans lines. If it does, the two lines outside
225      * of the removal area are joined together.
226      *
227      * @param chng the change event describing the edit
228      */

229     protected void removeUpdate(DefaultDocumentEvent chng) {
230     removed.removeAllElements();
231     BranchElement map = (BranchElement) getDefaultRootElement();
232     int offset = chng.getOffset();
233     int length = chng.getLength();
234     int line0 = map.getElementIndex(offset);
235     int line1 = map.getElementIndex(offset + length);
236     if (line0 != line1) {
237         // a line was removed
238
for (int i = line0; i <= line1; i++) {
239         removed.addElement(map.getElement(i));
240         }
241         int p0 = map.getElement(line0).getStartOffset();
242         int p1 = map.getElement(line1).getEndOffset();
243         Element JavaDoc[] aelems = new Element JavaDoc[1];
244         aelems[0] = createLeafElement(map, null, p0, p1);
245         Element JavaDoc[] relems = new Element JavaDoc[removed.size()];
246         removed.copyInto(relems);
247         ElementEdit ee = new ElementEdit(map, line0, relems, aelems);
248         chng.addEdit(ee);
249         map.replace(line0, relems.length, aelems);
250     } else {
251         //Check for the composed text element
252
Element JavaDoc line = map.getElement(line0);
253         if (!line.isLeaf()) {
254             Element JavaDoc leaf = line.getElement(line.getElementIndex(offset));
255         if (Utilities.isComposedTextElement(leaf)) {
256                 Element JavaDoc[] aelem = new Element JavaDoc[1];
257                 aelem[0] = createLeafElement(map, null,
258                 line.getStartOffset(), line.getEndOffset());
259                 Element JavaDoc[] relem = new Element JavaDoc[1];
260                 relem[0] = line;
261                 ElementEdit ee = new ElementEdit(map, line0, relem, aelem);
262                 chng.addEdit(ee);
263                 map.replace(line0, 1, aelem);
264         }
265         }
266     }
267     super.removeUpdate(chng);
268     }
269   
270     //
271
// Inserts the composed text of an input method. The line element
272
// where the composed text is inserted into becomes an branch element
273
// which contains leaf elements of the composed text and the text
274
// backing store.
275
//
276
private void insertComposedTextUpdate(DefaultDocumentEvent chng, AttributeSet JavaDoc attr) {
277     added.removeAllElements();
278     BranchElement lineMap = (BranchElement) getDefaultRootElement();
279     int offset = chng.getOffset();
280     int length = chng.getLength();
281     int index = lineMap.getElementIndex(offset);
282     Element JavaDoc elem = lineMap.getElement(index);
283     int elemStart = elem.getStartOffset();
284     int elemEnd = elem.getEndOffset();
285     BranchElement[] abelem = new BranchElement[1];
286     abelem[0] = (BranchElement) createBranchElement(lineMap, null);
287     Element JavaDoc[] relem = new Element JavaDoc[1];
288     relem[0] = elem;
289     if (elemStart != offset)
290         added.addElement(createLeafElement(abelem[0], null, elemStart, offset));
291     added.addElement(createLeafElement(abelem[0], attr, offset, offset+length));
292     if (elemEnd != offset+length)
293         added.addElement(createLeafElement(abelem[0], null, offset+length, elemEnd));
294     Element JavaDoc[] alelem = new Element JavaDoc[added.size()];
295     added.copyInto(alelem);
296     ElementEdit ee = new ElementEdit(lineMap, index, relem, abelem);
297     chng.addEdit(ee);
298
299     abelem[0].replace(0, 0, alelem);
300     lineMap.replace(index, 1, abelem);
301     }
302
303     private AbstractElement defaultRoot;
304     private Vector JavaDoc added = new Vector JavaDoc(); // Vector<Element>
305
private Vector JavaDoc removed = new Vector JavaDoc(); // Vector<Element>
306
private transient Segment JavaDoc s;
307 }
308
Popular Tags