KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > editor > LineRootElement


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.editor;
21
22 import javax.swing.text.AbstractDocument JavaDoc;
23 import javax.swing.text.Element JavaDoc;
24 import javax.swing.text.Document JavaDoc;
25 import javax.swing.text.AttributeSet JavaDoc;
26 import javax.swing.text.Position JavaDoc;
27 import javax.swing.undo.UndoableEdit JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import javax.swing.text.BadLocationException JavaDoc;
30 import javax.swing.text.Segment JavaDoc;
31 import javax.swing.text.StyleContext JavaDoc;
32 import org.netbeans.lib.editor.util.swing.DocumentUtilities;
33 import org.netbeans.lib.editor.util.swing.GapBranchElement;
34 import org.openide.ErrorManager;
35
36 /**
37  * Line root element implementation.
38  *
39  * @author Miloslav Metelka
40  * @version 1.00
41  */

42
43 final class LineRootElement extends GapBranchElement {
44     
45     private static final LineElement[] EMPTY_LINE_ELEMENT_ARRAY = new LineElement[0];
46  
47     private static final String JavaDoc NAME
48         = AbstractDocument.SectionElementName;
49     
50     private BaseDocument doc;
51     
52     private LineElement[] addedLines = EMPTY_LINE_ELEMENT_ARRAY;
53     
54     LineRootElement(BaseDocument doc) {
55         this.doc = doc;
56
57         assert (doc.getLength() == 0) : "Cannot start with non-empty document"; // NOI18N
58

59         Position JavaDoc startPos = doc.getStartPosition();
60         assert (startPos.getOffset() == 0) : "Document.getStartPosition() != 0"; // NOI18N
61

62         Position JavaDoc endPos = doc.getEndPosition();
63         assert (endPos.getOffset() == 1) : "Document.getEndPosition() != 1"; // NOI18N
64

65         Element JavaDoc line = new LineElement(this, startPos, endPos);
66         replace(0, 0, new Element JavaDoc[]{ line });
67
68         assert (getElement(0) != null);
69     }
70     
71     /**
72      * Double size of the addedLines array and return
73      * the index value that corresponds to the original zero index.
74      */

75     private int doubleAddedLinesCapacity() {
76         int addedLinesLength = addedLines.length;
77         int newCapacity = Math.max(4, addedLinesLength * 2);
78         LineElement[] newAddedLines = new LineElement[newCapacity];
79         // Copy current contents to end of array
80
System.arraycopy(addedLines, 0, newAddedLines,
81             newCapacity - addedLinesLength, addedLinesLength);
82         addedLines = newAddedLines;
83         return (newCapacity - addedLinesLength); // value for original index zero
84
}
85     
86     public Element JavaDoc getElement(int index) {
87         if (index < 0) {
88             throw new IndexOutOfBoundsException JavaDoc("Invalid line index=" + index + " < 0"); // NOI18N
89
}
90         int elementCount = getElementCount();
91         if (index >= elementCount) {
92             throw new IndexOutOfBoundsException JavaDoc("Invalid line index=" + index // NOI18N
93
+ " >= lineCount=" + elementCount); // NOI18N
94
}
95         
96         LineElement elem = (LineElement)super.getElement(index);
97         assert (elem != null);
98         return elem;
99     }
100
101     UndoableEdit JavaDoc insertUpdate(int insertOffset, int insertLength) {
102         int lastInsertedCharOffset = insertOffset + insertLength - 1;
103         CharSequence JavaDoc text = DocumentUtilities.getText(doc);
104         Edit JavaDoc edit = null;
105         
106         int index = -1; // Index of the elements modification
107
Element JavaDoc[] removeElements = null; // Removed line elements
108
// Index in the addedLines array - adding from last to first
109
int firstAddedLineIndex = addedLines.length; // nothing added yet
110

111         int offset = lastInsertedCharOffset;
112         // insertAtPrevLineEndOffset - whether the insert was done at the end (after '\n')
113
// of a previous line i.e. in fact at a begining of the next line.
114
boolean insertAtPrevLineEndOffset;
115         int beforeInsertOffset; // in fact Math.max(insertOffset - 1, 0)
116
if (insertOffset == 0) { // [swing] marks (and elements) at offset zero do not move up
117
beforeInsertOffset = 0;
118             insertAtPrevLineEndOffset = false;
119         } else { // inserting inside doc
120
beforeInsertOffset = insertOffset - 1; // check char before offset for '\n'
121
insertAtPrevLineEndOffset = (text.charAt(beforeInsertOffset) == '\n');
122         }
123
124         try {
125             // Go through all the inserted lines plus the char at beforeInsertOffset (if exists)
126
// and create new line elements at every occurrence of '\n'
127
Position JavaDoc futureAddedLineEndPos = null;
128             while (offset >= beforeInsertOffset) {
129                 if (text.charAt(offset) == '\n') { // line break at offset
130
boolean addLine = true; // whether line element should be added
131
if (futureAddedLineEndPos == null) {
132                         // Find the first line element that will be removed
133
index = getElementIndex(insertOffset);
134                         LineElement removeLine = (LineElement)getElement(index);
135                         // If inserting at begining of line (insertAtPrevLineEndOffset == true)
136
// and the inserted chars do not end with '\n'
137
// then not only current line must be removed
138
// but the next one as well.
139
if (insertAtPrevLineEndOffset) { // '\n' at (insertOffset - 1)
140
if (offset == lastInsertedCharOffset) { // inserted 'xxx\n'
141
removeElements = new Element JavaDoc[] { removeLine };
142                                 futureAddedLineEndPos = removeLine.getEndPosition();
143                                 addLine = false; // do not add new line in this case
144
} else {
145                                 LineElement nextRemoveLine = (LineElement)getElement(index + 1);
146                                 removeElements = new Element JavaDoc[] {
147                                     removeLine,
148                                     nextRemoveLine
149                                 };
150                                 futureAddedLineEndPos = nextRemoveLine.getEndPosition();
151                             }
152                                 
153                         } else { // otherwise use the next element as the next for added
154
removeElements = new Element JavaDoc[] { removeLine };
155                             futureAddedLineEndPos = removeLine.getEndPosition();
156                         }
157                     }
158
159                     if (addLine) {
160                         if (firstAddedLineIndex == 0) { // no more space to add
161
firstAddedLineIndex = doubleAddedLinesCapacity();
162                         }
163                         firstAddedLineIndex--; // will fill in added line element soon
164
Position JavaDoc lineStartPos = doc.createPosition(offset + 1);
165                         addedLines[firstAddedLineIndex] = new LineElement(
166                             this, lineStartPos, futureAddedLineEndPos);
167                         futureAddedLineEndPos = lineStartPos;
168                     }
169                 }
170                 offset--;
171             }
172
173             if (futureAddedLineEndPos != null) { // will add (and remove) lines
174
// Create array of added lines and add extra one at begining
175
int addedLineCount = addedLines.length - firstAddedLineIndex;
176                 Element JavaDoc[] addElements = new Element JavaDoc[addedLineCount + 1];
177                 System.arraycopy(addedLines, firstAddedLineIndex, addElements, 1, addedLineCount);
178                 addElements[0] = new LineElement(
179                     this,
180                     ((LineElement)removeElements[0]).getStartPosition(),
181                     futureAddedLineEndPos
182                 );
183
184                 replace(index, removeElements.length, addElements);
185                 edit = new Edit JavaDoc(index, removeElements, addElements);
186             }
187
188         } catch (BadLocationException JavaDoc e) {
189             // Should never happen but in case it happens
190
// retain the current consistent state (no replace is done)
191
// and report this as serious error
192
ErrorManager.getDefault().notify(ErrorManager.ERROR, e);
193         }
194         // checkConsistency();
195
return edit;
196     }
197
198     UndoableEdit JavaDoc removeUpdate(int removeOffset, int removeLength) {
199         // The algorithm here is similar to the one in PlainDocument.removeUpdate().
200
// Unfortunately in case exactly a line element (or multiple line elements)
201
// the algorithm removes extra line that follows the end of removed area.
202
// That could be improved but compatibility with PlainDocument would be lost.
203
Edit JavaDoc edit = null;
204         int removeEndOffset = removeOffset + removeLength;
205         int line0 = getElementIndex(removeOffset);
206         int line1 = getElementIndex(removeEndOffset);
207         if (line0 != line1) {
208             // at least one line was removed
209
line1++; // will remove the line where remove ends as well
210
Element JavaDoc[] removeElements = new Element JavaDoc[line1 - line0];
211             copyElements(line0, line1, removeElements, 0);
212             Element JavaDoc[] addElements = new Element JavaDoc[] {
213                 new LineElement(this,
214                     ((LineElement)removeElements[0]).getStartPosition(),
215                     ((LineElement)removeElements[removeElements.length - 1]).getEndPosition()
216                 )
217             };
218             
219             replace(line0, removeElements.length, addElements);
220             edit = new Edit JavaDoc(line0, removeElements, addElements);
221         }
222         // checkConsistency();
223
return edit;
224     }
225
226 /* protected void compact() {
227         super.compact();
228         addedLines = EMPTY_LINE_ELEMENT_ARRAY;
229     }
230  */

231
232     public Document JavaDoc getDocument() {
233         return doc;
234     }
235     
236     public Element JavaDoc getParentElement() {
237         return null;
238     }
239
240     public String JavaDoc getName() {
241         return NAME;
242     }
243
244     public AttributeSet JavaDoc getAttributes() {
245         return StyleContext.getDefaultStyleContext().getEmptySet();
246     }
247
248     public int getStartOffset() {
249         return 0;
250     }
251
252     public int getEndOffset() {
253         return doc.getLength() + 1;
254     }
255
256     public int getElementIndex(int offset) {
257         if (offset == 0) { // NB uses this frequently to just get the parent
258
return 0;
259         }
260
261         return super.getElementIndex(offset);
262     }
263
264     private void checkConsistency() {
265         int lineCount = getElementCount();
266         assert (lineCount > 0); // Should be 1 or greater
267
int prevLineEndOffset = 0;
268         for (int i = 0; i < lineCount; i++) {
269             LineElement elem = (LineElement)getElement(i);
270             assert (prevLineEndOffset == elem.getStartOffset());
271             assert (prevLineEndOffset < elem.getEndOffset())
272                 : "Line " + i + " of " + lineCount + ": " + lineToString(elem); // NOI18N
273
prevLineEndOffset = elem.getEndOffset();
274         }
275         assert (prevLineEndOffset == (doc.getLength() + 1));
276     }
277     
278     private String JavaDoc lineToString(Element JavaDoc line) {
279         return "<" + line.getStartOffset() + ", " // NOI18N
280
+ line.getEndOffset() + ">"; // NOI18N
281
}
282
283 }
284
Popular Tags