KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > editor > ext > FormatTokenPositionSupport


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.ext;
21
22 import java.util.HashMap JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import javax.swing.text.Position JavaDoc;
25 import org.netbeans.editor.TokenItem;
26
27 /**
28 * Support class for mapping the token-positions
29 * to the tokens and providing additional operations.
30 *
31 * @author Miloslav Metelka
32 * @version 1.00
33 */

34
35 class FormatTokenPositionSupport {
36
37     private final FormatWriter formatWriter;
38
39     /** First save set in the chain */
40     private SaveSet firstSet;
41
42     /** Last save set in the chain */
43     private SaveSet lastSet;
44
45     /** Map holding the [token, token-position-list] pairs. */
46     private final HashMap JavaDoc tokens2positionLists = new HashMap JavaDoc();
47
48     FormatTokenPositionSupport(FormatWriter formatWriter) {
49         this.formatWriter = formatWriter;
50     }
51
52     private ArrayList JavaDoc getPosList(TokenItem token) {
53         ArrayList JavaDoc ret = (ArrayList JavaDoc)tokens2positionLists.get(token);
54         if (ret == null) {
55             ret = new ArrayList JavaDoc(3);
56             tokens2positionLists.put(token, ret);
57         }
58         return ret;
59     }
60
61     /** Get the token-position for the given token and offset.
62      * @param token token for which the token-position is being created.
63      * @param offset offset inside the token at which the position is being
64      * created.
65      */

66     synchronized ExtTokenPosition getTokenPosition(TokenItem token, int offset,
67     Position.Bias JavaDoc bias) {
68         // Check offset correctness
69
if (token == null) {
70             if (offset != 0) {
71                 throw new IllegalArgumentException JavaDoc(
72                     "Ending token position has non-zero offset=" + offset); // NOI18N
73
}
74
75         } else if (offset >= token.getImage().length()) {
76             throw new IllegalArgumentException JavaDoc("Offset=" + offset // NOI18N
77
+ " >= tokenLength=" + token.getImage().length()); // NOI18N
78
}
79
80         ArrayList JavaDoc posList = getPosList(token);
81         int cnt = posList.size();
82         ExtTokenPosition etp;
83         for (int i = 0; i < cnt; i++) {
84             etp = (ExtTokenPosition)posList.get(i);
85             if (etp.getOffset() == offset && etp.getBias() == bias) {
86                 return etp;
87             }
88         }
89
90         etp = new ExtTokenPosition(token, offset, bias);
91         posList.add(etp);
92         return etp;
93     }
94
95     /** Notify that the previous token was created with
96      * the appropriate text taken from the start of this token.
97      * It's now necessary to split the marks according
98      * @param token token that was split
99      * @param startLength initial length of the token-text
100      * that was cut and inserted into the previous token
101      * in the chain.
102      */

103     synchronized void splitStartTokenPositions(TokenItem token, int startLength) {
104         TokenItem prevToken = token.getPrevious();
105         if (prevToken != null) {
106             prevToken = formatWriter.findNonEmptyToken(prevToken, true);
107         }
108         ArrayList JavaDoc posList = getPosList(token);
109         int len = posList.size();
110         ArrayList JavaDoc prevPosList = getPosList(prevToken);
111         for (int i = 0; i < len; i++) {
112             ExtTokenPosition etp = (ExtTokenPosition)posList.get(i);
113             if (etp.offset < startLength) { // move to prevToken
114
etp.token = prevToken;
115                 posList.remove(i);
116                 prevPosList.add(etp);
117                 i--;
118                 len--;
119             }
120         }
121     }
122
123     /** Notify that the previous token was created with
124      * the appropriate text taken from the start of this token.
125      * It's now necessary to split the marks according
126      * @param token token that was split
127      * @param endLength initial length of the token-text
128      * that was cut and inserted into the previous token
129      * in the chain.
130      */

131     synchronized void splitEndTokenPositions(TokenItem token, int endLength) {
132         TokenItem nextToken = token.getNext();
133         if (nextToken != null) {
134             nextToken = formatWriter.findNonEmptyToken(nextToken, false);
135         }
136         ArrayList JavaDoc nextPosList = getPosList(nextToken);
137
138         ArrayList JavaDoc posList = getPosList(token);
139         int len = posList.size();
140         int offset = token.getImage().length() - endLength;
141         for (int i = 0; i < len; i++) {
142             ExtTokenPosition etp = (ExtTokenPosition)posList.get(i);
143             if (etp.offset >= offset) { // move to nextToken
144
etp.token = nextToken;
145                 etp.offset -= offset;
146                 posList.remove(i);
147                 nextPosList.add(etp);
148                 i--;
149                 len--;
150             }
151         }
152     }
153
154     /** Text in the token will be inserted. */
155     synchronized void tokenTextInsert(TokenItem token, int offset, int length) {
156         ArrayList JavaDoc posList = getPosList(token);
157         int len = posList.size();
158         // Add length to all positions after insertion point
159
for (int i = 0; i < len; i++) {
160             ExtTokenPosition etp = (ExtTokenPosition)posList.get(i);
161             if ((etp.bias == Position.Bias.Backward)
162                     ? (etp.offset > offset) : (etp.offset >= offset)) {
163                 etp.offset += length;
164             }
165         }
166
167         // Move bwd-bias marks from the next token if insert at end
168
if (token.getImage().length() == offset) {
169             TokenItem nextToken = token.getNext();
170             if (nextToken != null) {
171                 nextToken = formatWriter.findNonEmptyToken(nextToken, false);
172             }
173             posList = getPosList(nextToken);
174             len = posList.size();
175             for (int i = 0; i < len; i++) {
176                 ExtTokenPosition etp = (ExtTokenPosition)posList.get(i);
177                 if (etp.bias == Position.Bias.Backward && etp.offset == 0) {
178                     etp.token = token;
179                     etp.offset = offset;
180                 }
181             }
182         }
183
184
185     }
186
187     /** Text in the token will be removed. */
188     synchronized void tokenTextRemove(TokenItem token, int offset, int length) {
189         ArrayList JavaDoc posList = getPosList(token);
190         int len = posList.size();
191         int newLen = token.getImage().length() - length;
192         ArrayList JavaDoc nextList = getPosList(token.getNext());
193         for (int i = 0; i < len; i++) {
194             ExtTokenPosition etp = (ExtTokenPosition)posList.get(i);
195             if (etp.offset >= offset + length) { // move to nextToken
196
etp.offset -= length;
197
198             } else if (etp.offset >= offset) {
199                 etp.offset = offset;
200             }
201
202             // Check if pos right at the end of token and therefore invalid
203
if (etp.offset >= newLen) { // need to move to begining of next token
204
etp.token = token.getNext();
205                 etp.offset = 0;
206                 posList.remove(i);
207                 nextList.add(etp);
208                 i--;
209                 len--;
210             }
211         }
212     }
213
214     /** Whole token being removed. */
215     synchronized void tokenRemove(TokenItem token) {
216         TokenItem nextToken = token.getNext();
217         if (nextToken != null) {
218             nextToken = formatWriter.findNonEmptyToken(nextToken, false);
219         }
220         ArrayList JavaDoc nextPosList = getPosList(nextToken);
221
222         ArrayList JavaDoc posList = getPosList(token);
223         int len = posList.size();
224         for (int i = 0; i < len; i++) {
225             ExtTokenPosition etp = (ExtTokenPosition)posList.get(i);
226             etp.token = nextToken;
227             etp.offset = 0;
228             nextPosList.add(etp);
229         }
230         posList.clear();
231
232         // Remove the token from registry
233
tokens2positionLists.remove(token);
234     }
235
236     /** Given token was inserted into the chain */
237     synchronized void tokenInsert(TokenItem token) {
238         if (token.getImage().length() > 0) { // only for non-zero size
239
ArrayList JavaDoc posList = getPosList(token);
240
241             TokenItem nextToken = token.getNext();
242             if (nextToken != null) {
243                 nextToken = formatWriter.findNonEmptyToken(nextToken, false);
244             }
245             ArrayList JavaDoc nextPosList = getPosList(nextToken);
246
247             int nextLen = nextPosList.size();
248             for (int i = 0; i < nextLen; i++) {
249                 ExtTokenPosition etp = (ExtTokenPosition)nextPosList.get(i);
250                 if (etp.offset == 0 && etp.getBias() == Position.Bias.Backward) {
251                     etp.token = token; // offset will stay equal to zero
252
nextPosList.remove(i);
253                     i--;
254                     nextLen--;
255                     posList.add(etp);
256                 }
257             }
258         }
259     }
260
261     /** Clear all the save-sets. */
262     synchronized void clearSaveSets() {
263         firstSet = null;
264         lastSet = null;
265     }
266
267     /** Add the save-set to the registry and perform the checking
268      * whether the offsets are OK.
269      */

270     synchronized void addSaveSet(int baseOffset, int writtenLen,
271     int[] offsets, Position.Bias JavaDoc[] biases) {
272         // Check whether the offsets are OK
273
for (int i = 0; i < offsets.length; i++) {
274             if (offsets[i] < 0 || offsets[i] > writtenLen) {
275                 throw new IllegalArgumentException JavaDoc(
276                     "Invalid save-offset=" + offsets[i] + " at index=" + i // NOI18N
277
+ ". Written length is " + writtenLen); // NOI18N
278
}
279         }
280
281         SaveSet newSet = new SaveSet(baseOffset, offsets, biases);
282
283         if (firstSet != null) {
284             lastSet.next = newSet;
285             lastSet = newSet;
286
287         } else { // first set
288
firstSet = lastSet = newSet;
289         }
290     }
291
292     /** Create the token-positions for all the save sets */
293     synchronized void createPositions(FormatTokenPosition formatStartPosition) {
294         updateSaveOffsets(formatStartPosition);
295
296         SaveSet curSet = firstSet;
297         FormatWriter.FormatTokenItem token
298                 = (FormatWriter.FormatTokenItem)formatStartPosition.getToken();
299         boolean noText = (token == null);
300
301         while (curSet != null) {
302             int len = curSet.offsets.length;
303             for (int i = 0; i < len; i++) {
304                 if (noText) {
305                     curSet.positions[i] = getTokenPosition(null, 0, curSet.biases[i]);
306
307                 } else { // there's some text to be formatted
308

309                     // Find the covering token and create the position
310
int offset = curSet.offsets[i];
311                     while (token != null) {
312                         if (offset < token.getSaveOffset()) {
313                             token = (FormatWriter.FormatTokenItem)token.getPrevious();
314
315                         } else if ((offset > token.getSaveOffset() + token.getImage().length())
316                             || token.getImage().length() == 0
317                         ) {
318                             token = (FormatWriter.FormatTokenItem)token.getNext();
319
320                         } else { // the right token
321
curSet.positions[i] = getTokenPosition(token,
322                                     offset - token.getSaveOffset(), curSet.biases[i]);
323                             break; // break the loop
324
}
325                     }
326
327                     if (token == null) { // It is right at the end
328
curSet.positions[i] = getTokenPosition(null, 0, curSet.biases[i]);
329                         token = (FormatWriter.FormatTokenItem)formatWriter.getLastToken();
330                     }
331                 }
332             }
333
334             curSet = curSet.next;
335         }
336     }
337
338     synchronized void updateSaveSets(FormatTokenPosition formatStartPosition) {
339         updateSaveOffsets(formatStartPosition);
340
341         SaveSet curSet = firstSet;
342         int endOffset = 0; // offset of the null token
343
if (formatStartPosition.getToken() != null) {
344             endOffset = ((FormatWriter.FormatTokenItem)formatWriter.getLastToken()).getSaveOffset()
345                 + formatWriter.getLastToken().getImage().length();
346         }
347
348         while (curSet != null) {
349             int len = curSet.offsets.length;
350             for (int i = 0; i < len; i++) {
351                 FormatWriter.FormatTokenItem token
352                     = (FormatWriter.FormatTokenItem)curSet.positions[i].getToken();
353                 if (token == null) {
354                     curSet.offsets[i] = endOffset;
355
356                 } else { // non-null token
357
curSet.offsets[i] = token.getSaveOffset()
358                         + curSet.positions[i].getOffset();
359                 }
360             }
361         }
362     }
363
364     /** Number the tokens so that they are OK for finding out the
365      * offsets.
366      */

367     private void updateSaveOffsets(FormatTokenPosition formatStartPosition) {
368         if (firstSet != null) { // it has only sense if there are any save-sets
369
FormatWriter.FormatTokenItem ti
370                 = (FormatWriter.FormatTokenItem)formatStartPosition.getToken();
371             int offset = -formatStartPosition.getOffset();
372
373             while (ti != null) {
374                 ti.setSaveOffset(offset);
375                 offset += ti.getImage().length();
376
377                 ti = (FormatWriter.FormatTokenItem)ti.getNext();
378             }
379         }
380     }
381
382     /** Implementation of the extended-token-position that allows
383      * modification of its token and offset fields.
384      */

385     class ExtTokenPosition implements FormatTokenPosition {
386
387         TokenItem token;
388
389         int offset;
390
391         /** Whether the position should stay the same if inserted right at it. */
392         Position.Bias JavaDoc bias;
393
394         ExtTokenPosition(TokenItem token, int offset) {
395             this(token, offset, Position.Bias.Forward);
396         }
397
398         ExtTokenPosition(TokenItem token, int offset, Position.Bias JavaDoc bias) {
399             this.token = token;
400             this.offset = offset;
401             this.bias = bias;
402         }
403
404         public TokenItem getToken() {
405             return token;
406         }
407
408         public int getOffset() {
409             return (token != null) ? offset : 0;
410         }
411
412         public Position.Bias JavaDoc getBias() {
413             return bias;
414         }
415
416         public boolean equals(Object JavaDoc o) {
417             return equals(o, true); // ignore bias in comparison
418
}
419
420         public boolean equals(Object JavaDoc o, boolean ignoreBias) {
421             if (o instanceof FormatTokenPosition) {
422                 FormatTokenPosition tp = (FormatTokenPosition)o;
423
424                 return token == tp.getToken() && offset == tp.getOffset()
425                     && (ignoreBias || bias == tp.getBias());
426             }
427
428             return false;
429         }
430
431         public String JavaDoc toString() {
432             return "<" + getToken() + ", " + getOffset() + ", " + getBias() + ">"; // NOI18N
433
}
434
435     }
436
437     /** Class holding the info about the set of the offsets to save
438      * during the formatting.
439      */

440     static class SaveSet {
441
442         /** Next set in the chain. */
443         SaveSet next;
444
445         /** Base offset of the buffer corresponding to the offsets */
446         int baseOffset;
447
448         /** Offsets to save */
449         int[] offsets;
450
451         /** Biases for the positions */
452         Position.Bias JavaDoc[] biases;
453
454         /** Token positions corresponding to the offsets */
455         FormatTokenPosition[] positions;
456
457         SaveSet(int baseOffset, int[] offsets, Position.Bias JavaDoc[] biases) {
458             this.baseOffset = baseOffset;
459             this.offsets = offsets;
460             this.biases = biases;
461         }
462
463     }
464
465 }
466
Popular Tags