001: /*
002: * Sun Public License Notice
003: *
004: * The contents of this file are subject to the Sun Public License
005: * Version 1.0 (the "License"). You may not use this file except in
006: * compliance with the License. A copy of the License is available at
007: * http://www.sun.com/
008: *
009: * The Original Code is NetBeans. The Initial Developer of the Original
010: * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
011: * Microsystems, Inc. All Rights Reserved.
012: */
013:
014: package org.netbeans.editor;
015:
016: import javax.swing.text.BadLocationException;
017:
018: /**
019: * Support class for chain of MarkBlocks
020: *
021: * @author Miloslav Metelka
022: * @version 1.00
023: */
024:
025: public class MarkChain {
026:
027: /** Chain of all marks */
028: protected MarkFactory.ChainDrawMark chain;
029:
030: /** Current mark to make checks faster */
031: protected MarkFactory.ChainDrawMark curMark;
032:
033: /** Document for this mark */
034: protected BaseDocument doc;
035:
036: /**
037: * If this chain uses draw marks, then this is the name for the draw layer
038: * that will be used for the marks
039: */
040: protected String layerName;
041:
042: /**
043: * The mark created by addMark() method is stored in this variable. In case
044: * the mark was not created, because there already was some on this
045: * position, the already existing mark is returned.
046: */
047: private MarkFactory.ChainDrawMark recentlyAddedMark;
048:
049: /** Construct chain using draw marks */
050: public MarkChain(BaseDocument doc, String layerName) {
051: this .doc = doc;
052: this .layerName = layerName;
053: }
054:
055: public final MarkFactory.ChainDrawMark getChain() {
056: return chain;
057: }
058:
059: public final MarkFactory.ChainDrawMark getCurMark() {
060: return curMark;
061: }
062:
063: /**
064: * Tests whether the position range is partly or fully inside some mark
065: * block from the chain.
066: *
067: * @param pos
068: * compared position
069: * @return relation of curMark to the given position
070: */
071: public int compareMark(int pos) {
072: try {
073: if (curMark == null) {
074: curMark = chain;
075: if (curMark == null) {
076: return -1; // no marks yet
077: }
078: }
079:
080: int rel;
081: boolean after = false;
082: boolean before = false;
083: while ((rel = curMark.compare(pos)) != 0) { // just match
084: if (rel > 0) { // this mark after pos
085: if (before) {
086: return rel;
087: }
088: if (curMark.prev != null) {
089: after = true;
090: curMark = curMark.prev;
091: } else { // end of chain
092: return rel;
093: }
094: } else { // this mark before pos
095: if (after) {
096: return rel;
097: }
098: if (curMark.next != null) {
099: before = true;
100: curMark = curMark.next;
101: } else { // start of chain
102: return rel;
103: }
104: }
105: }
106: return 0; // match
107: } catch (InvalidMarkException e) {
108: if (Boolean.getBoolean("netbeans.debug.exceptions")) { // NOI18N
109: e.printStackTrace();
110: }
111: return -1; // don't match, but what to return?
112: }
113: }
114:
115: protected MarkFactory.ChainDrawMark createAndInsertNewMark(int pos)
116: throws BadLocationException {
117: MarkFactory.ChainDrawMark mark = createMark();
118: try {
119: doc.op.insertMark(mark, pos);
120: } catch (InvalidMarkException e) {
121: if (Boolean.getBoolean("netbeans.debug.exceptions")) { // NOI18N
122: e.printStackTrace();
123: }
124: }
125: return mark;
126: }
127:
128: protected MarkFactory.ChainDrawMark createMark() {
129: MarkFactory.ChainDrawMark mark = new MarkFactory.ChainDrawMark(
130: layerName, null);
131: mark.backwardBias = true; // stay at line begining
132: mark.activateLayer = true;
133: return mark;
134: }
135:
136: /**
137: * Add mark to the chain
138: *
139: * @return true if the mark was added false if there's already mark at that
140: * pos
141: */
142: public boolean addMark(int pos) throws BadLocationException {
143: int rel = compareMark(pos);
144: if (rel == 0) {
145: recentlyAddedMark = curMark;
146: return false; // already exists
147: } else if (rel > 0) { // curMark after pos
148: MarkFactory.ChainDrawMark mark = createAndInsertNewMark(pos);
149: recentlyAddedMark = mark;
150: if (curMark != null) {
151: if (curMark == chain) { // curMark is first mark
152: chain = curMark.insertChain(mark);
153: } else { // curMark is not first mark
154: curMark.insertChain(mark);
155: }
156: } else { // no marks in chain
157: chain = mark;
158: }
159: } else { // curMark before pos
160: MarkFactory.ChainDrawMark mark = createAndInsertNewMark(pos);
161: recentlyAddedMark = mark;
162: if (curMark != null) {
163: if (curMark.next != null) {
164: curMark.next.insertChain(mark);
165: } else { // last mark in chain
166: curMark.setNextChain(mark);
167: }
168: } else { // no marks in chain
169: chain = mark;
170: }
171: }
172: return true;
173: }
174:
175: /**
176: * The mark created by addMark() method is returned by this method. In case
177: * the mark was not created, because there already was some on requested
178: * position, the already existing mark is returned.
179: */
180: public MarkFactory.ChainDrawMark getAddedMark() {
181: return recentlyAddedMark;
182: }
183:
184: /** Remove non-empty block from area covered by blocks from chain */
185: public boolean removeMark(int pos) {
186: int rel = compareMark(pos);
187: if (rel == 0) {
188: boolean first = (curMark == chain);
189: curMark = curMark.removeChain();
190: if (first) {
191: chain = curMark;
192: }
193: return true;
194: } else { // not found
195: return false;
196: }
197: }
198:
199: /** Is there mark at given position? */
200: public boolean isMark(int pos) {
201: return (compareMark(pos) == 0);
202: }
203:
204: /**
205: * Toggle the mark so that if it didn't exist it is created and if it
206: * existed it's removed
207: *
208: * @return true if the new mark was added false if the existing mark was
209: * removed
210: */
211: public boolean toggleMark(int pos) throws BadLocationException {
212: int rel = compareMark(pos);
213: if (rel == 0) { // exists
214: removeMark(pos);
215: return false;
216: } else { // didn't exist
217: addMark(pos);
218: return true;
219: }
220: }
221:
222: public String toString() {
223: return "MarkChain: curMark=" + curMark
224: + ", mark chain: " // NOI18N
225: + (chain != null ? ("\n" + chain.toStringChain())
226: : "Empty"); // NOI18N
227: }
228:
229: }
|