KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > lib > editor > util > swing > GapBranchElement


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.lib.editor.util.swing;
21
22 import javax.swing.text.Element JavaDoc;
23 import javax.swing.event.DocumentEvent JavaDoc;
24 import javax.swing.undo.AbstractUndoableEdit JavaDoc;
25 import javax.swing.undo.CannotUndoException JavaDoc;
26 import javax.swing.undo.CannotRedoException JavaDoc;
27 import org.netbeans.lib.editor.util.GapList;
28
29 /**
30  * Branch element that uses gap list to maintain its child elements.
31  *
32  * @author Miloslav Metelka
33  * @version 1.00
34  */

35
36 public abstract class GapBranchElement implements Element JavaDoc {
37
38     protected static final Element JavaDoc[] EMPTY_ELEMENT_ARRAY = new Element JavaDoc[0];
39
40     private GapList children;
41     
42     public GapBranchElement() {
43         children = new GapList();
44     }
45     
46     public int getElementCount() {
47         return children.size();
48     }
49     
50     public Element JavaDoc getElement(int index) {
51         return (Element JavaDoc)children.get(index);
52     }
53     
54     public void copyElements(int srcBegin, int srcEnd, Element JavaDoc dst[], int dstBegin) {
55         children.copyElements(srcBegin, srcEnd, dst, dstBegin);
56     }
57
58     /**
59      * Gets the child element index closest to the given offset.
60      * The offset is specified relative to the beginning of the
61      * document. Returns <code>-1</code> if the
62      * <code>Element</code> is a leaf, otherwise returns
63      * the index of the <code>Element</code> that best represents
64      * the given location. Returns <code>0</code> if the location
65      * is less than the start offset. Returns
66      * <code>getElementCount() - 1</code> if the location is
67      * greater than or equal to the end offset.
68      *
69      * <p>
70      * This implementation is in sync with the original
71      * <code>Element.getElementIndex()</code> specification
72      * but it differs
73      * from <code>AbstractDocument.BranchElement.getElementIndex()</code>
74      * which returns 0 in case it does not have any children.
75      * <br>
76      * This implementation returns -1 in that case because in fact
77      * the element act as a leaf element in such case.
78      * <br>
79      * Nonetheless there should be no difference in functionality
80      * if this implementation is used for line elements
81      * because there is always at least one line element even
82      * for empty doc because of the extra '\n' after the end
83      * of the AbstractDocument-based implementations.
84      *
85      * @param offset the specified offset >= 0
86      * @return the element index >= 0
87      */

88     public int getElementIndex(int offset) {
89         int low = 0;
90         int high = getElementCount() - 1;
91         
92         if (high == -1) { // no children => return -1
93
return -1;
94         }
95         
96         while (low <= high) {
97             int mid = (low + high) / 2;
98             int elemStartOffset = getElement(mid).getStartOffset();
99             
100             if (elemStartOffset < offset) {
101                 low = mid + 1;
102             } else if (elemStartOffset > offset) {
103                 high = mid - 1;
104             } else { // element starts at offset
105
return mid;
106             }
107         }
108
109         if (high < 0) { // if offset < getElement(0).getStartOffset()
110
high = 0;
111         }
112         return high;
113     }
114
115     public boolean isLeaf() {
116         return false;
117     }
118     
119     protected void replace(int index, int removeCount, Element JavaDoc[] addedElems) {
120         if (removeCount > 0) {
121             children.remove(index, removeCount);
122         }
123         if (addedElems != null) {
124             children.addArray(index, addedElems);
125         }
126     }
127     
128     /** Get info about <CODE>DocMarks</CODE>. */
129     public String JavaDoc toString() {
130         return children.toString();
131     }
132
133     public class Edit extends AbstractUndoableEdit JavaDoc
134     implements DocumentEvent.ElementChange JavaDoc {
135         
136         private int index;
137         
138         private Element JavaDoc[] childrenAdded;
139         
140         private Element JavaDoc[] childrenRemoved;
141        
142         public Edit(int index, Element JavaDoc[] childrenRemoved, Element JavaDoc[] childrenAdded) {
143             this.index = index;
144             this.childrenRemoved = childrenRemoved;
145             this.childrenAdded = childrenAdded;
146         }
147         
148     public Element JavaDoc getElement() {
149             return GapBranchElement.this;
150         }
151
152     public int getIndex() {
153             return index;
154         }
155
156         public Element JavaDoc[] getChildrenRemoved() {
157             return childrenRemoved;
158         }
159
160         public Element JavaDoc[] getChildrenAdded() {
161             return childrenAdded;
162         }
163
164         public void undo() throws CannotUndoException JavaDoc {
165             super.undo();
166
167             replace(index, childrenAdded.length, childrenRemoved);
168
169             // Switch childrenAdded with childrenRemoved
170
Element JavaDoc[] tmp = childrenRemoved;
171             childrenRemoved = childrenAdded;
172             childrenAdded = tmp;
173         }
174         
175         public void redo() throws CannotRedoException JavaDoc {
176             super.redo();
177
178             // Switch childrenAdded with childrenRemoved
179
Element JavaDoc[] tmp = childrenRemoved;
180             childrenRemoved = childrenAdded;
181             childrenAdded = tmp;
182
183             replace(index, childrenRemoved.length, childrenAdded);
184         }
185         
186     }
187
188     /**
189      * Extension of {@link GapBranchElement}
190      * that overrides {@link #getElementIndex(int)}
191      * which remembers the last returned element index.
192      */

193     public abstract class LastIndex {
194         
195         private int lastReturnedElementIndex;
196     
197         /**
198          * Implementation that remembers the last returned element index
199          * and checks the element at the last index when next called.
200          * <br>
201          * This may improve performance if there are typically many repetitive calls
202          * with offset values hitting the last returned element index.
203          */

204         public int getElementIndex(int offset) {
205             int low = 0;
206             int high = getElementCount() - 1;
207
208             if (high == -1) { // no children => return -1
209
return -1;
210             }
211
212             int lastIndex = lastReturnedElementIndex; // make copy to be thread-safe
213
if (lastIndex >= low && lastIndex <= high) {
214                 Element JavaDoc lastElem = getElement(lastIndex);
215                 int lastElemStartOffset = lastElem.getStartOffset();
216                 if (offset >= lastElemStartOffset) {
217                     int lastElemEndOffset = lastElem.getEndOffset();
218                     if (offset < lastElemEndOffset) { // hit
219
return lastIndex;
220                     } else { // above
221
low = lastIndex + 1;
222                     }
223                 } else { // below lastIndex
224
high = lastIndex - 1;
225                 }
226             }
227
228             while (low <= high) {
229                 int mid = (low + high) / 2;
230                 int elemStartOffset = ((Element JavaDoc)children.get(mid)).getStartOffset();
231
232                 if (elemStartOffset < offset) {
233                     low = mid + 1;
234                 } else if (elemStartOffset > offset) {
235                     high = mid - 1;
236                 } else { // element starts at offset
237
lastReturnedElementIndex = mid;
238                     return mid;
239                 }
240             }
241
242             if (high < 0) {
243                 high = 0;
244             }
245             lastReturnedElementIndex = high;
246             return high;
247         }
248         
249     }
250
251 }
252
Popular Tags