001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Alexey A. Ivanov, Roman I. Chernyatchik
019: * @version $Revision$
020: */package javax.swing.text;
021:
022: import java.lang.ref.PhantomReference;
023: import java.lang.ref.Reference;
024: import java.lang.ref.ReferenceQueue;
025: import java.lang.ref.WeakReference;
026: import java.util.ArrayList;
027: import java.util.Collections;
028: import java.util.List;
029: import java.util.Vector;
030:
031: import org.apache.harmony.x.swing.internal.nls.Messages;
032:
033: abstract class ContentPositions {
034: public final class DocumentMark implements Position, Comparable {
035: protected int index;
036:
037: protected final Reference ref;
038:
039: private DocumentMark(final int offset) {
040: setOffset(offset);
041: ref = null;
042: }
043:
044: private DocumentMark(final int offset, final Position pos) {
045: setOffset(offset);
046: this .ref = new MarkReference(pos, this , positionQueue);
047: insertPosition(this );
048: }
049:
050: /*
051: * @see java.lang.Comparable#compareTo(java.lang.Object)
052: */
053: public int compareTo(final Object obj) {
054: return compare((DocumentMark) obj);
055: }
056:
057: public int getOffset() {
058: return getOffsetForDocumentMark(index);
059: }
060:
061: protected int compare(final DocumentMark dm) {
062: return index - dm.index;
063: }
064:
065: protected boolean isEqual(final DocumentMark dm) {
066: return compare(dm) == 0;
067: }
068:
069: protected boolean isGreater(final DocumentMark dm) {
070: return compare(dm) > 0;
071: }
072:
073: protected boolean isLess(final DocumentMark dm) {
074: return compare(dm) < 0;
075: }
076:
077: protected void setOffset(final int offset) {
078: index = setOffsetForDocumentMark(offset);
079: }
080: }
081:
082: private static final class MarkReference extends PhantomReference {
083: protected final DocumentMark hostMark;
084:
085: public MarkReference(final Object userMark,
086: final DocumentMark hostMark, final ReferenceQueue queue) {
087: super (userMark, queue);
088: this .hostMark = hostMark;
089: }
090: }
091:
092: private final class UndoPosRef {
093: private int documentOffset;
094:
095: private WeakReference posWeakRef;
096:
097: protected UndoPosRef(final WeakReference weakReference) {
098: posWeakRef = weakReference;
099: DocumentMark positionMark = (DocumentMark) posWeakRef.get();
100: if (positionMark != null) {
101: documentOffset = positionMark.getOffset();
102: }
103: }
104:
105: protected void restorePos() {
106: DocumentMark positionMark = (DocumentMark) posWeakRef.get();
107: if (positionMark != null) {
108: positionMark.setOffset(documentOffset);
109: }
110: }
111: }
112:
113: private final class WeakPosition implements Position {
114: private final DocumentMark mark;
115:
116: public WeakPosition(final int offset) {
117: mark = new DocumentMark(offset, this );
118: }
119:
120: public int getOffset() {
121: return mark.getOffset();
122: }
123: }
124:
125: protected List positionList = new ArrayList();
126:
127: private ReferenceQueue positionQueue = new ReferenceQueue();
128:
129: private DocumentMark searchMark = new DocumentMark(0);
130:
131: public Position createPosition(final int offset)
132: throws BadLocationException {
133:
134: if (offset < 0) {
135: throw new BadLocationException(Messages
136: .getString("swing.85"), offset); //$NON-NLS-1$
137: }
138:
139: return new WeakPosition(offset);
140: }
141:
142: /**
143: * Deletes position instances from the list that were cleared by the garbage
144: * collector. It is called (or must be called) in the methods modifying this
145: * list before the modification is done.
146: */
147: public void deletePositions() {
148: MarkReference ref;
149: while ((ref = (MarkReference) positionQueue.poll()) != null) {
150: removePosition(ref.hostMark);
151: ref.clear();
152: }
153: }
154:
155: public Vector getPositionsInRange(final Vector vector,
156: final int offset, final int len) {
157: Vector vect = vector;
158: if (vect == null) {
159: vect = new Vector();
160: }
161:
162: deletePositions();
163:
164: for (int i = getStartIndexByOffset(offset); i < positionList
165: .size(); i++) {
166:
167: DocumentMark documentMark = (DocumentMark) positionList
168: .get(i);
169:
170: final int markOffset = documentMark.getOffset();
171: assert offset <= markOffset : "Failed @ " + i + ": "
172: + offset + " > " + markOffset;
173: if (markOffset <= offset + len) {
174: vect
175: .add(new UndoPosRef(new WeakReference(
176: documentMark)));
177: } else {
178: break;
179: }
180: }
181: return vect;
182: }
183:
184: public void moveMarkIndexes(final int startIndex, final int diff) {
185:
186: moveMarkIndexesByPosListIndexes(
187: getStartIndexByIndex(startIndex), positionList.size(),
188: diff);
189:
190: }
191:
192: public void moveMarkIndexes(final int startIndex,
193: final int endIndex, final int diff) {
194:
195: moveMarkIndexesByPosListIndexes(
196: getStartIndexByIndex(startIndex),
197: getEndIndexByIndex(endIndex), diff);
198: }
199:
200: public void setMarkIndexes(final int startIndex,
201: final int endIndex, final int newIndex) {
202:
203: final int limit = getEndIndexByIndex(endIndex);
204: for (int i = getStartIndexByIndex(startIndex); i < limit; i++) {
205: DocumentMark dm = (DocumentMark) positionList.get(i);
206: dm.index = newIndex;
207: }
208: }
209:
210: public void updateUndoPositions(final Vector positions) {
211:
212: UndoPosRef undoPositionReference;
213:
214: deletePositions();
215:
216: for (int i = 0; i < positions.size(); i++) {
217: Object item = positions.get(i);
218: if (!(item instanceof UndoPosRef)) {
219: continue;
220: }
221:
222: undoPositionReference = (UndoPosRef) item;
223: undoPositionReference.restorePos();
224: }
225:
226: Collections.sort(positionList);
227: }
228:
229: protected abstract int getOffsetForDocumentMark(final int index);
230:
231: protected abstract int setOffsetForDocumentMark(final int offset);
232:
233: private int getStartIndexByOffset(final int offset) {
234: searchMark.setOffset(offset);
235: return getStartIndexByIndex(searchMark.index);
236: }
237:
238: private int getStartIndexByIndex(final int index) {
239: if (index == 0) {
240: // Marks at index 0 must never be updated
241: for (int i = 0; i < positionList.size(); i++) {
242: DocumentMark dm = (DocumentMark) positionList.get(i);
243: if (dm.index > 0) {
244: return i;
245: }
246: }
247: return positionList.size();
248: }
249:
250: searchMark.index = index;
251: int result = findIndex(searchMark);
252: if (result > 0) {
253: DocumentMark dm;
254: do {
255: dm = (DocumentMark) positionList.get(result - 1);
256: } while (!dm.isLess(searchMark) && --result > 0);
257: }
258: return result;
259: }
260:
261: private int getEndIndexByIndex(final int index) {
262: final int lastMark = positionList.size() - 1;
263: if (index == -1 || lastMark < 0) {
264: return lastMark + 1;
265: }
266:
267: DocumentMark dm = (DocumentMark) positionList.get(lastMark);
268: if (index >= dm.index) {
269: return lastMark + 1;
270: }
271:
272: searchMark.index = index;
273: int result = findIndex(searchMark);
274: if (result < lastMark) {
275: do {
276: dm = (DocumentMark) positionList.get(result);
277: } while (!dm.isGreater(searchMark) && ++result < lastMark);
278: }
279: return result;
280: }
281:
282: private int findIndex(final DocumentMark documentMark) {
283: int result = Collections.binarySearch(positionList,
284: documentMark);
285: return result < 0 ? -result - 1 : result + 1;
286: }
287:
288: private void moveMarkIndexesByPosListIndexes(
289: final int startPosListIndex, final int endPosListIndex,
290: final int diff) {
291:
292: for (int i = startPosListIndex; i < endPosListIndex; i++) {
293: DocumentMark dm = (DocumentMark) positionList.get(i);
294: dm.index += diff;
295: }
296: }
297:
298: private void insertPosition(final DocumentMark documentMark) {
299: deletePositions();
300:
301: final int index = findIndex(documentMark);
302: positionList.add(index, documentMark);
303: }
304:
305: private void removePosition(final DocumentMark position) {
306: int foundPos = Collections.binarySearch(positionList, position);
307: int pos = foundPos;
308: Position current = null;
309: while (pos >= 0
310: && (current = (Position) positionList.get(pos)) != position
311: && current.getOffset() == position.getOffset()) {
312: pos--;
313: }
314: if (current == position) {
315: positionList.remove(pos);
316: return;
317: }
318:
319: current = null;
320: pos = foundPos + 1;
321: while (pos < positionList.size()
322: && (current = (Position) positionList.get(pos)) != position
323: && current.getOffset() == position.getOffset()) {
324: pos++;
325: }
326: if (current == position) {
327: positionList.remove(pos);
328: }
329: }
330: }
|