KickJava   Java API By Example, From Geeks To Geeks.

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


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
25 /**
26 * Block of text created using two marks. These blocks can be chained.
27 * Existing block can be compared to other block (better pair of positions)
28 * and there's extensive list of result values of such comparison.
29 *
30 * @author Miloslav Metelka
31 * @version 1.00
32 */

33
34 public class MarkBlock {
35
36     /** This value is not used directly in this class
37     * but can be used by other classes to report that
38     * the comparison of blocks has no sense for some reason.
39     */

40     public static final int INVALID = 0;
41
42     /** Single bit value that means that tested block
43     * and THIS block partially or fully overlap. If this bit is not
44     * set then the blocks don't overlap at all. The values for which
45     * this bit is set are: OVERLAP_BEGIN, OVERLAP_END, EXTEND_BEGIN,
46     * EXTEND_END, INCLUDE, INSIDE_BEGIN, INSIDE_END, SAME, INNER.
47     * The values for which this bit is not set are: BEFORE, AFTER,
48     * CONTINUE_BEGIN, CONTINUE_END.
49     */

50     public static final int OVERLAP = 1;
51
52     /** Single bit value that means that the tested block doesn't
53     * overlap with THIS block, but either its start position
54     * is equal to end position of THIS block or its end position
55     * is equal to the start position of THIS block. Simply they together
56     * make one continuous block. The values for which this bit is set
57     * are: CONTINUE_BEGIN, CONTINUE_END.
58     */

59     public static final int CONTINUE = 2;
60
61     /** Single bit value meaning that the tested block has zero size.
62     */

63     public static final int EMPTY = 4;
64
65     /** Single bit value meaning that THIS block has zero size.
66     */

67     public static final int THIS_EMPTY = 8;
68
69     /** Two bit value meaning that the tested block fully
70     * includes THIS block. The block must be extended at least by
71     * one character, otherwise the 'inside' values will be used.
72     * It is included in the following
73     * values: EXTEND_BEGIN, INCLUDE, EXTEND_END.
74     * The value includes OVERLAP.
75     */

76     public static final int EXTEND = 16 | OVERLAP;
77
78     /** Two bit value meaning that the tested block is fully
79     * inside THIS block. It is included in the following
80     * values: INSIDE_BEGIN, SAME, INSIDE_END.
81     * The value includes OVERLAP.
82     */

83     public static final int INSIDE = 32 | OVERLAP;
84
85
86     /** Tested block completely before THIS mark block.
87     */

88     public static final int BEFORE = 64;
89
90     /** Tested block completely after THIS mark block.
91     */

92     public static final int AFTER = 128;
93
94     /** Tested block completely before THIS mark block but its
95     * end position equals to the start position of THIS block.
96     * They together make one continuous block.
97     * The value is BEFORE | CONTINUE.
98     */

99     public static final int CONTINUE_BEGIN = BEFORE | CONTINUE;
100
101     /** Tested block completely after THIS mark block but its
102     * start position equals to the end position of THIS block.
103     * They together make one continuous block.
104     * The value is AFTER | CONTINUE.
105     */

106     public static final int CONTINUE_END = AFTER | CONTINUE;
107
108     /** Tested block partly covers begining of THIS mark block.
109     * The value includes OVERLAP.
110     */

111     public static final int OVERLAP_BEGIN = 256 | OVERLAP;
112
113     /** Tested block partly covers end of THIS mark block.
114     * The value includes OVERLAP.
115     */

116     public static final int OVERLAP_END = 512 | OVERLAP;
117
118     /** Start position of the tested block is lower than
119     * the start position of THIS block and both end positions
120     * are the same.
121     * The value is OVERLAP_BEGIN | EXTEND.
122     */

123     public static final int EXTEND_BEGIN = OVERLAP_BEGIN | EXTEND;
124
125     /** End position of the tested block is greater than
126     * the end position of THIS block and both start positions
127     * are the same.
128     * The value is OVERLAP_END | EXTEND.
129     */

130     public static final int EXTEND_END = OVERLAP_END | EXTEND;
131
132     /** Tested block fully includes THIS block and extends it
133     * by at least one character in both directions.
134     * The value is EXTEND_BEGIN | EXTEND_END.
135     */

136     public static final int INCLUDE = EXTEND_BEGIN | EXTEND_END;
137
138     /** Tested block completely inside THIS block and its end
139     * position is lower than end position of THIS block
140     * and start positions are the same.
141     * The value includes INSIDE.
142     */

143     public static final int INSIDE_BEGIN = 1024 | INSIDE;
144
145     /** Tested block completely inside THIS block and its start
146     * position is greater than THIS block start position and
147     * end positions are the same.
148     * The value includes INSIDE.
149     */

150     public static final int INSIDE_END = 2048 | INSIDE;
151
152     /** Tested block is fully inside THIS block and there
153     * is at least one more character left in THIS block
154     * after the end of the tested block in both directions.
155     * The value includes INSIDE.
156     */

157     public static final int INNER = 4096 | INSIDE;
158
159     /** The blocks have exactly the same start and end positions.
160     * They simply cover exactly the same area.
161     * The value is INSIDE_BEGIN | INSIDE_END.
162     */

163     public static final int SAME = INSIDE_BEGIN | INSIDE_END;
164
165
166     /** This value can be used to clear the two bits saying
167     * if the tested or THIS block are empty (The EMPTY and THIS_EMPTY are cleared).
168     * To do that, use value ANDed by IGNORE_EMPTY expression.
169     */

170     public static final int IGNORE_EMPTY = ~(EMPTY | THIS_EMPTY);
171
172
173     /** Next block in the chain */
174     protected MarkBlock next;
175
176     /** Previous block in the chain */
177     protected MarkBlock prev;
178
179     public Mark startMark;
180
181     public Mark endMark;
182
183     protected BaseDocument doc;
184     
185     public MarkBlock(BaseDocument doc, Mark startMark,
186                      Mark endMark) {
187         this.doc = doc;
188         this.startMark = startMark;
189         this.endMark = endMark;
190     }
191
192     /** Construct block with given marks */
193     public MarkBlock(BaseDocument doc, int startPos, int endPos)
194     throws BadLocationException JavaDoc {
195         this(doc, new Mark(), new Mark(), startPos, endPos);
196     }
197
198     /** Construct block from positions on some document */
199     public MarkBlock(BaseDocument doc, Mark startMark,
200                      Mark endMark, int startPos, int endPos)
201     throws BadLocationException JavaDoc {
202         this(doc, startMark, endMark);
203         try {
204             startMark.insert(doc, startPos);
205             try {
206                 endMark.insert(doc, endPos);
207             } catch (BadLocationException JavaDoc e) {
208                 try {
209                     startMark.remove();
210                 } catch (InvalidMarkException e2) {
211                     Utilities.annotateLoggable(e2);
212                 }
213                 throw e;
214             } catch (InvalidMarkException e) {
215                 Utilities.annotateLoggable(e);
216             }
217         } catch (InvalidMarkException e) {
218             Utilities.annotateLoggable(e);
219         }
220     }
221
222     /** Insert block before this one
223     * @return inserted block
224     */

225     public MarkBlock insertChain(MarkBlock blk) {
226         MarkBlock thisPrev = this.prev;
227         blk.prev = thisPrev;
228         blk.next = this;
229         if (thisPrev != null) {
230             thisPrev.next = blk;
231         }
232         this.prev = blk;
233         return blk;
234     }
235
236     /** Add block after this one
237     * @return added block
238     */

239     public MarkBlock addChain(MarkBlock blk) {
240         if (next != null) {
241             next.insertChain(blk);
242         } else {
243             setNextChain(blk);
244         }
245         return blk;
246     }
247
248     /** Remove this block from the chain
249     * @return next chain member or null for end of chain
250     */

251     public MarkBlock removeChain() {
252         MarkBlock thisNext = this.next;
253         MarkBlock thisPrev = this.prev;
254         if (thisPrev != null) { // not the first
255
thisPrev.next = thisNext;
256             this.prev = null;
257         }
258         if (thisNext != null) {
259             thisNext.prev = thisPrev;
260             this.next = null;
261         }
262         destroyMarks();
263         return thisNext;
264     }
265
266     /** Compares the position of the given block against current block.
267     * @param startPos starting position of the compared block
268     * @param endPos ending position of the compared block or it is the same
269     * as startPos when testing just for insert
270     * @return relation of compared block against this guarded block
271     */

272     public int compare(int startPos, int endPos) {
273         try {
274             int startThis = startMark.getOffset();
275             int endThis = endMark.getOffset();
276             if (startThis > endThis) { // swap if necessary
277
int tmp = startThis;
278                 startThis = endThis;
279                 endThis = tmp;
280             }
281             int ret = 0;
282             if (startPos == endPos) { // tested empty
283
if (startThis == endThis) { // both empty
284
if (startPos < startThis) {
285                         return EMPTY | THIS_EMPTY | BEFORE;
286                     } else if (startPos > startThis) {
287                         return EMPTY | THIS_EMPTY | AFTER;
288                     } else {
289                         return EMPTY | THIS_EMPTY | SAME;
290                     }
291                 } else { // tested empty, this non-empty
292
if (startPos <= startThis) {
293                         return (startPos < startThis) ? (EMPTY | BEFORE)
294                                : (EMPTY | INSIDE_BEGIN);
295                     } else if (startPos >= endThis) {
296                         return (startPos > endThis) ? (EMPTY | AFTER)
297                                : (EMPTY | INSIDE_END);
298                     } else {
299                         return EMPTY | INNER;
300                     }
301                 }
302
303             }
304             if (startThis == endThis) { // this empty, tested non-empty
305
if (startPos >= startThis) {
306                     return (startPos > startThis) ? (THIS_EMPTY | AFTER)
307                            : (THIS_EMPTY | EXTEND_END);
308                 } else if (endPos >= startThis) {
309                     return (endPos > startThis) ? (THIS_EMPTY | BEFORE)
310                            : (THIS_EMPTY | EXTEND_BEGIN);
311                 } else {
312                     return THIS_EMPTY | INCLUDE;
313                 }
314             }
315             // both non-empty
316
if (endPos <= startThis) {
317                 return (endPos < startThis) ? BEFORE : CONTINUE_BEGIN;
318             } else if (startPos >= endThis) {
319                 return (startPos > endThis) ? AFTER : CONTINUE_END;
320             } else {
321                 if (endPos < endThis) {
322                     if (startPos > startThis) {
323                         return INNER;
324                     } else if (startPos == startThis) {
325                         return INSIDE_BEGIN;
326                     } else { // startPos < startThis
327
return OVERLAP_BEGIN;
328                     }
329                 } else if (endPos == endThis) {
330                     if (startPos > startThis) {
331                         return INSIDE_END;
332                     } else if (startPos == startThis) {
333                         return SAME;
334                     } else { // startPos < startThis
335
return EXTEND_BEGIN;
336                     }
337                 } else { // endPos > endThis
338
if (startPos > startThis) {
339                         return OVERLAP_END;
340                     } else if (startPos == startThis) {
341                         return EXTEND_END;
342                     } else { // startPos < startThis
343
return INCLUDE;
344                     }
345                 }
346             }
347         } catch (InvalidMarkException e) {
348             return INVALID;
349         }
350     }
351
352     public final MarkBlock getNext() {
353         return next;
354     }
355
356     public final void setNext(MarkBlock b) {
357         next = b;
358     }
359
360     /** Set the next block of this one in the chain. */
361     public void setNextChain(MarkBlock b) {
362         this.next = b;
363         if (b != null) {
364             b.prev = this;
365         }
366     }
367
368     public final MarkBlock getPrev() {
369         return prev;
370     }
371
372     public final void setPrev(MarkBlock b) {
373         prev = b;
374     }
375
376     /** Set the previous block of this one in the chain */
377     public void setPrevChain(MarkBlock b) {
378         this.prev = b;
379         if (b != null) {
380             b.next = this;
381         }
382     }
383
384     public boolean isReverse() {
385         try {
386             return (startMark.getOffset() > endMark.getOffset());
387         } catch (InvalidMarkException e) {
388             return false;
389         }
390     }
391
392     public void reverse() {
393         Mark tmp = startMark;
394         startMark = endMark;
395         endMark = tmp;
396     }
397
398     public boolean checkReverse() {
399         if (isReverse()) {
400             reverse();
401             return true;
402         }
403         return false;
404     }
405
406     /** Possibly move start mark if its position is above the given number.
407     * @return new position
408     */

409     public int extendStart(int startPos) throws BadLocationException JavaDoc {
410         try {
411             int markPos = startMark.getOffset();
412             startPos = Math.min(startPos, markPos);
413             if (startPos != markPos) {
414                 startMark.move(doc, startPos);
415             }
416             return startPos;
417         } catch (InvalidMarkException e) {
418             Utilities.annotateLoggable(e);
419             return 0;
420         }
421     }
422
423     /** Possibly move end mark if its position is above the given number.
424     * @return new position
425     */

426     public int extendEnd(int endPos) throws BadLocationException JavaDoc {
427         try {
428             int markPos = endMark.getOffset();
429             endPos = Math.max(endPos, markPos);
430             if (endPos != markPos) {
431                 endMark.move(doc, endPos);
432             }
433             return endPos;
434         } catch (InvalidMarkException e) {
435             Utilities.annotateLoggable(e);
436             return 0;
437         }
438     }
439
440     /** Extend this mark block by start and end positions. First test whether
441     * the given block intersects with this mark block. If not nothing is done.
442     * @return whether this mark block has been extended
443     */

444     public boolean extend(int startPos, int endPos, boolean concat) throws BadLocationException JavaDoc {
445         try {
446             boolean extended = false;
447             int rel = compare(startPos, endPos);
448             if ((rel & OVERLAP_BEGIN) == OVERLAP_BEGIN
449                     || ((rel & CONTINUE_BEGIN) == CONTINUE_BEGIN && concat)
450                ) {
451                 extended = true;
452                 startMark.move(doc, startPos);
453             }
454             if ((rel & OVERLAP_END) == OVERLAP_END
455                     || ((rel & CONTINUE_END) == CONTINUE_END && concat)
456                ) {
457                 extended = true;
458                 endMark.move(doc, endPos);
459             }
460             return extended;
461         } catch (InvalidMarkException e) {
462             Utilities.annotateLoggable(e);
463             return false;
464         }
465     }
466
467     /** Extend this mark block by some other block.
468     * @return whether the block was extended. If it was, the caller
469     * is responsible for possibly removing blk from the chain
470     */

471     public boolean extend(MarkBlock blk, boolean concat) {
472         try {
473             return extend(blk.startMark.getOffset(), blk.endMark.getOffset(), concat);
474         } catch (BadLocationException JavaDoc e) {
475             Utilities.annotateLoggable(e);
476         } catch (InvalidMarkException e) {
477             Utilities.annotateLoggable(e);
478         }
479         return false;
480     }
481
482     /** Shrink this mark block by the block specified.
483     * startMark is moved to the endPos if OVERLAP_BEGIN
484     * or INSIDE_BEGIN is returned from compare().
485     * endMark is moved to the startPos if OVERLAP_END
486     * or INSIDE_END is returned from compare().
487     * If other status is returned or either block
488     * is empty, then no action is taken. It's up
489     * to caller to handle these situations.
490     * @return relation of tested block to mark block
491     */

492     public int shrink(int startPos, int endPos) throws BadLocationException JavaDoc {
493         try {
494             int rel = compare(startPos, endPos);
495             switch (rel) {
496             case OVERLAP_BEGIN:
497             case INSIDE_BEGIN:
498                 startMark.move(doc, endPos);
499                 break;
500             case OVERLAP_END:
501             case INSIDE_END:
502                 endMark.move(doc, startPos);
503                 break;
504             }
505             return rel;
506         } catch (InvalidMarkException e) {
507             Utilities.annotateLoggable(e);
508             return INVALID;
509         }
510     }
511
512     public Document JavaDoc getDocument() {
513         return doc;
514     }
515
516     public int getStartOffset() {
517         try {
518             return startMark.getOffset();
519         } catch (InvalidMarkException e) {
520             return 0;
521         }
522     }
523
524     public int getEndOffset() {
525         try {
526             return endMark.getOffset();
527         } catch (InvalidMarkException e) {
528             return 0;
529         }
530     }
531
532     /** Remove the marks if they were not removed yet */
533     void destroyMarks() {
534         // now remove the marks
535
try {
536             if (startMark != null) {
537                 startMark.remove();
538                 startMark = null;
539             }
540         } catch (InvalidMarkException e) {
541             // already removed
542
}
543         try {
544             if (endMark != null) {
545                 endMark.remove();
546                 endMark = null;
547             }
548         } catch (InvalidMarkException e) {
549             // already removed
550
}
551     }
552
553     /** Destroy the marks if necessary */
554     protected void finalize() throws Throwable JavaDoc {
555         destroyMarks();
556         super.finalize();
557     }
558
559     /** Debugs this mark block */
560     public String JavaDoc toString() {
561         try {
562             return "startPos="
563                     + ((startMark != null) // NOI18N
564
? (String.valueOf(startMark.getOffset()) + '['
565                             + Utilities.debugPosition(doc, startMark.getOffset()) + ']')
566                         : "null")
567                     + ", endPos=" // NOI18N
568
+ ((endMark != null)
569                             ? (String.valueOf(endMark.getOffset()) + '['
570                                 + Utilities.debugPosition(doc, endMark.getOffset()) + ']')
571                             : "null") // NOI18N
572
+ ", " + ((prev != null) ? ((next != null) ? "chain member" // NOI18N
573
: "last member") : ((next != null) ? "first member" // NOI18N
574
: "standalone member")); // NOI18N
575
} catch (InvalidMarkException e) {
576             return ""; // NOI18N
577
}
578     }
579
580     /** Debug possibly whole chain of marks */
581     public String JavaDoc toStringChain() {
582         return toString() + ((next != null) ? ("\n" + next.toStringChain()) : ""); // NOI18N
583
}
584
585     public static String JavaDoc debugRelation(int rel) {
586         String JavaDoc s = ((rel & EMPTY) != 0) ? "EMPTY | " : ""; // NOI18N
587
s += ((rel & THIS_EMPTY) != 0) ? "THIS_EMPTY | " : ""; // NOI18N
588
rel &= IGNORE_EMPTY;
589         switch (rel) {
590         case BEFORE:
591             return s + "BEFORE"; // NOI18N
592
case AFTER:
593             return s + "AFTER"; // NOI18N
594
case CONTINUE_BEGIN:
595             return s + "CONTINUE_BEGIN"; // NOI18N
596
case CONTINUE_END:
597             return s + "CONTINUE_END"; // NOI18N
598
case OVERLAP_BEGIN:
599             return s + "OVERLAP_BEGIN"; // NOI18N
600
case OVERLAP_END:
601             return s + "OVERLAP_END"; // NOI18N
602
case EXTEND_BEGIN:
603             return s + "EXTEND_BEGIN"; // NOI18N
604
case EXTEND_END:
605             return s + "EXTEND_END"; // NOI18N
606
case INCLUDE:
607             return s + "INCLUDE"; // NOI18N
608
case INSIDE_BEGIN:
609             return s + "INSIDE_BEGIN"; // NOI18N
610
case INSIDE_END:
611             return s + "INSIDE_END"; // NOI18N
612
case INNER:
613             return s + "INNER"; // NOI18N
614
case SAME:
615             return s + "SAME"; // NOI18N
616
case INVALID:
617             return s + "INVALID"; // NOI18N
618
default:
619             return s + "UNKNOWN_STATE " + rel; // NOI18N
620
}
621     }
622
623 }
624
Popular Tags