KickJava   Java API By Example, From Geeks To Geeks.

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


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.BadLocationException JavaDoc;
23 import javax.swing.text.Document JavaDoc;
24 import javax.swing.text.Position JavaDoc;
25
26 /**
27 * Support class for chain of MarkBlocks
28 *
29 * @author Miloslav Metelka
30 * @version 1.00
31 */

32
33 public class MarkBlockChain {
34
35     /** Chain of all blocks */
36     protected MarkBlock chain;
37
38     /** Current block to make checks faster */
39     protected MarkBlock currentBlock;
40
41     /** Document for this block */
42     protected BaseDocument doc;
43
44     /** Construct chain using regular base marks */
45     public MarkBlockChain(BaseDocument doc) {
46         this.doc = doc;
47     }
48
49     public final MarkBlock getChain() {
50         return chain;
51     }
52
53     /** Tests whether the position range is partly or fully inside
54     * some mark block from the chain.
55     * @param startPos starting position of tested area
56     * @param endPos ending position of tested area for removal or same
57     * as startPos when insert is made
58     * @return relation of currentBlock to the given block
59     */

60     public int compareBlock(int startPos, int endPos) {
61         if (currentBlock == null) {
62             currentBlock = chain;
63             if (currentBlock == null) {
64                 return MarkBlock.INVALID;
65             }
66         }
67
68         int rel; // relation of block to particular mark block
69
boolean afterPrev = false; // blk is after previous block
70
boolean beforeNext = false; // blk is before next block
71
boolean cont = false; // blk continued currentBlock in previous match
72
MarkBlock contBlk = null;
73         int contRel = 0;
74         while (true) {
75             rel = currentBlock.compare(startPos, endPos);
76             if ((rel & MarkBlock.OVERLAP) != 0) {
77                 return rel;
78             }
79
80             if ((rel & MarkBlock.AFTER) != 0) { // after this mark block
81
if (beforeNext) {
82                     if (!cont || (rel & MarkBlock.CONTINUE) != 0) {
83                         return rel;
84                     } else { // continues with contBlk and this relation is pure after
85
currentBlock = contBlk;
86                         return contRel;
87                     }
88                 } else { // going from begining of chain
89
if (currentBlock.next != null) {
90                         afterPrev = true;
91                         cont = ((rel & MarkBlock.CONTINUE) != 0);
92                         if (cont) {
93                             contRel = rel;
94                             contBlk = currentBlock;
95                         }
96                         currentBlock = currentBlock.next;
97                     } else { // end of chain
98
return rel;
99                     }
100                 }
101             } else { // before this mark block
102
if (afterPrev) {
103                     if (!cont || (rel & MarkBlock.EXTEND) != 0) {
104                         return rel;
105                     } else {
106                         currentBlock = contBlk;
107                         return contRel;
108                     }
109                 } else { // going from end of chain
110
if (currentBlock.prev != null) {
111                         beforeNext = true;
112                         cont = ((rel & MarkBlock.CONTINUE) != 0);
113                         if (cont) {
114                             contRel = rel;
115                             contBlk = currentBlock;
116                         }
117                         currentBlock = currentBlock.prev;
118                     } else { // begining of chain
119
return rel;
120                     }
121                 }
122             }
123         }
124     }
125
126     public void removeEmptyBlocks() {
127         try {
128             MarkBlock blk = chain;
129             while (blk != null) {
130                 if (blk.startMark.getOffset() == blk.endMark.getOffset()) { // empty block
131
blk = checkedRemove(blk); // remove current block and get the next one
132
} else {
133                     blk = blk.next;
134                 }
135             }
136         } catch (InvalidMarkException e) {
137             Utilities.annotateLoggable(e);
138         }
139     }
140
141     protected MarkBlock createBlock(int startPos, int endPos)
142     throws BadLocationException JavaDoc {
143         return new MarkBlock(doc, createBlockStartMark(), createBlockEndMark(),
144                              startPos, endPos);
145     }
146
147     protected Mark createBlockStartMark() {
148         return new Mark();
149     }
150
151     protected Mark createBlockEndMark() {
152         return new Mark();
153     }
154     
155     private void removeCurrentIfEmpty() {
156         try {
157             while (currentBlock != null) {
158                 // For backward bias the following condition may become ">"
159
if (currentBlock.startMark.getOffset() >= currentBlock.endMark.getOffset()) {
160                     checkedRemove(currentBlock);
161                     currentBlock = chain;
162                 } else { // not empty block
163
break;
164                 }
165             }
166         } catch (InvalidMarkException e) {
167             Utilities.annotateLoggable(e);
168         }
169     }
170
171
172     /** Add non-empty block to the chain of blocks
173     * @param concat whether concatenate adjacent blocks
174     */

175     public void addBlock(int startPos, int endPos, boolean concat) {
176         if (startPos == endPos) {
177             return;
178         }
179         removeCurrentIfEmpty();
180         try {
181             int rel = compareBlock(startPos, endPos) & MarkBlock.IGNORE_EMPTY;
182             if ((rel & MarkBlock.BEFORE) != 0) { // before currentBlock or continue_begin
183
if (concat && rel == MarkBlock.CONTINUE_BEGIN) { // concatenate
184
currentBlock.startMark.move(doc, startPos);
185                 } else { // insert new block at begining
186
boolean first = (currentBlock == chain);
187                     MarkBlock blk = currentBlock.insertChain(createBlock(startPos, endPos));
188                     if (first) {
189                         chain = blk;
190                     }
191                 }
192             } else if ((rel & MarkBlock.AFTER) != 0) { // after currentBlock or continue_end
193
if (concat && rel == MarkBlock.CONTINUE_END) {
194                     currentBlock.endMark.move(doc, endPos);
195                 } else { // add new block to the chain
196
currentBlock.addChain(createBlock(startPos, endPos));
197                 }
198             } else { // overlap or invalid relation
199
if (currentBlock == null) { // no current block
200
chain = createBlock(startPos, endPos);
201                 } else { // overlap
202
// the block is partly hit - extend it by positions
203
currentBlock.extendStart(startPos);
204                     currentBlock.extendEnd(endPos);
205                     // remove the blocks covered by startPos to endPos
206
MarkBlock blk = chain;
207                     while (blk != null) {
208                         if (blk != currentBlock) { // except self
209
if (currentBlock.extend(blk, concat)) { // if they overlapped
210
MarkBlock tempCurBlk = currentBlock;
211                                 blk = checkedRemove(blk); // will clear currentBlock
212
currentBlock = tempCurBlk;
213                             } else { // didn't overlap, go to next
214
blk = blk.next;
215                             }
216                         } else {
217                             blk = blk.next;
218                         }
219                     }
220                 }
221             }
222         } catch (InvalidMarkException e) {
223             Utilities.annotateLoggable(e);
224         } catch (BadLocationException JavaDoc e) {
225             Utilities.annotateLoggable(e);
226         }
227     }
228
229     /** Remove non-empty block from area covered by blocks from chain */
230     public void removeBlock(int startPos, int endPos) {
231         if (startPos == endPos) {
232             return;
233         }
234         try {
235             int rel;
236             while (((rel = compareBlock(startPos, endPos)) & MarkBlock.OVERLAP) != 0) {
237                 if ((rel & MarkBlock.THIS_EMPTY) != 0) { // currentBlock is empty
238
checkedRemove(currentBlock);
239                 } else {
240                     switch (currentBlock.shrink(startPos, endPos)) {
241                     case MarkBlock.INNER: // tested block inside currentBlock -> divide
242
int endMarkPos = currentBlock.endMark.getOffset();
243                         currentBlock.endMark.move(doc, startPos);
244                         currentBlock.addChain(createBlock(endPos, endMarkPos));
245                         return;
246                     case MarkBlock.INSIDE_BEGIN:
247                     case MarkBlock.OVERLAP_BEGIN:
248                         currentBlock.startMark.move(doc, endPos);
249                         return;
250                     case MarkBlock.INSIDE_END:
251                     case MarkBlock.OVERLAP_END:
252                         currentBlock.endMark.move(doc, startPos);
253                         return;
254                     default: // EXTEND
255
checkedRemove(currentBlock);
256                         break;
257                     }
258                 }
259             }
260         } catch (BadLocationException JavaDoc e) {
261             Utilities.annotateLoggable(e);
262         } catch (InvalidMarkException e) {
263             Utilities.annotateLoggable(e);
264         }
265     }
266
267     /** Removes mark block and possibly updates the chain.
268     * @return next block after removed one
269     */

270     protected MarkBlock checkedRemove(MarkBlock blk) {
271         boolean first = (blk == chain);
272         blk = blk.removeChain();
273         if (first) {
274             chain = blk;
275         }
276         currentBlock = null; // make sure current block is cleared
277
return blk;
278     }
279
280     public int adjustToBlockEnd(int pos) {
281         int rel = compareBlock(pos, pos) & MarkBlock.IGNORE_EMPTY;
282         if (rel == MarkBlock.INSIDE_BEGIN || rel == MarkBlock.INNER) { // inside blk
283
pos = currentBlock.getEndOffset();
284         }
285         return pos;
286     }
287
288     /** Return the position adjusted to the start of the next mark-block.
289     */

290     public int adjustToNextBlockStart(int pos) {
291         // !!! what about empty blocks
292
int rel = compareBlock(pos, pos) & MarkBlock.IGNORE_EMPTY;
293         if ((rel & MarkBlock.BEFORE) != 0) {
294             pos = currentBlock.getStartOffset();
295         } else { // after the block or inside
296
if (currentBlock != null) {
297                 MarkBlock nextBlk = currentBlock.getNext();
298                 if (nextBlk != null) {
299                     pos = nextBlk.getStartOffset();
300                 } else { // no next block
301
pos = -1;
302                 }
303             } else { // no current block
304
pos = -1;
305             }
306         }
307         return pos;
308     }
309
310     public static class LayerChain extends MarkBlockChain {
311
312         private String JavaDoc layerName;
313
314         public LayerChain(BaseDocument doc, String JavaDoc layerName) {
315             super(doc);
316             this.layerName = layerName;
317         }
318
319         public final String JavaDoc getLayerName() {
320             return layerName;
321         }
322
323         protected Mark createBlockStartMark() {
324             MarkFactory.DrawMark startMark = new MarkFactory.DrawMark(layerName, null);
325             startMark.activateLayer = true;
326             return startMark;
327         }
328
329         protected Mark createBlockEndMark() {
330             MarkFactory.DrawMark endMark = new MarkFactory.DrawMark(layerName, null, Position.Bias.Backward);
331             return endMark;
332         }
333
334     }
335
336     public String JavaDoc toString() {
337         return "MarkBlockChain: currentBlock=" + currentBlock + "\nblock chain: " // NOI18N
338
+ (chain != null ? ("\n" + chain.toStringChain()) : " Empty"); // NOI18N
339
}
340
341 }
342
Popular Tags