1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47:
48: import ;
49: import ;
50: import ;
51: import ;
52:
53:
60: public final class StringContent
61: implements AbstractDocument.Content, Serializable
62: {
63:
67: private class UndoPosRef
68: {
69:
72: private Mark mark;
73:
74:
77: private int undoOffset;
78:
79:
84: UndoPosRef(Mark m)
85: {
86: mark = m;
87: undoOffset = mark.mark;
88: }
89:
90:
94: void reset()
95: {
96: mark.mark = undoOffset;
97: }
98: }
99:
100:
107: private class Mark
108: {
109:
112: int mark;
113:
114:
115:
120: int refCount;
121:
122:
127: Mark(int offset)
128: {
129: mark = offset;
130: }
131: }
132:
133:
134: private static final long serialVersionUID = 4755994433709540381L;
135:
136:
137: char[] content;
138:
139: private int count;
140:
141:
146: Vector marks;
147:
148: private class InsertUndo extends AbstractUndoableEdit
149: {
150: private int start;
151:
152: private int length;
153:
154: private String redoContent;
155:
156: private Vector positions;
157:
158: public InsertUndo(int start, int length)
159: {
160: super();
161: this.start = start;
162: this.length = length;
163: }
164:
165: public void undo()
166: {
167: super.undo();
168: try
169: {
170: if (marks != null)
171: positions = getPositionsInRange(null, start, length);
172: redoContent = getString(start, length);
173: remove(start, length);
174: }
175: catch (BadLocationException b)
176: {
177: throw new CannotUndoException();
178: }
179: }
180:
181: public void redo()
182: {
183: super.redo();
184: try
185: {
186: insertString(start, redoContent);
187: redoContent = null;
188: if (positions != null)
189: {
190: updateUndoPositions(positions);
191: positions = null;
192: }
193: }
194: catch (BadLocationException b)
195: {
196: throw new CannotRedoException();
197: }
198: }
199: }
200:
201: private class RemoveUndo extends AbstractUndoableEdit
202: {
203: private int start;
204: private int len;
205: private String undoString;
206:
207: Vector positions;
208:
209: public RemoveUndo(int start, String str)
210: {
211: super();
212: this.start = start;
213: len = str.length();
214: this.undoString = str;
215: if (marks != null)
216: positions = getPositionsInRange(null, start, str.length());
217: }
218:
219: public void undo()
220: {
221: super.undo();
222: try
223: {
224: StringContent.this.insertString(this.start, this.undoString);
225: if (positions != null)
226: {
227: updateUndoPositions(positions);
228: positions = null;
229: }
230: undoString = null;
231: }
232: catch (BadLocationException bad)
233: {
234: throw new CannotUndoException();
235: }
236: }
237:
238: public void redo()
239: {
240: super.redo();
241: try
242: {
243: undoString = getString(start, len);
244: if (marks != null)
245: positions = getPositionsInRange(null, start, len);
246: remove(this.start, len);
247: }
248: catch (BadLocationException bad)
249: {
250: throw new CannotRedoException();
251: }
252: }
253: }
254:
255: private class StickyPosition implements Position
256: {
257: Mark mark;
258:
259: public StickyPosition(int offset)
260: {
261:
262: garbageCollect();
263:
264: mark = new Mark(offset);
265: mark.refCount++;
266: marks.add(mark);
267:
268: new WeakReference(this, queueOfDeath);
269: }
270:
271:
274: public int getOffset()
275: {
276: return mark.mark;
277: }
278: }
279:
280:
283: private static final char[] EMPTY = new char[0];
284:
285:
292: ReferenceQueue queueOfDeath;
293:
294:
299: public StringContent()
300: {
301: this(10);
302: }
303:
304:
310: public StringContent(int initialLength)
311: {
312: super();
313: queueOfDeath = new ReferenceQueue();
314: if (initialLength < 1)
315: initialLength = 1;
316: this.content = new char[initialLength];
317: this.content[0] = '\n';
318: this.count = 1;
319: }
320:
321: protected Vector getPositionsInRange(Vector v,
322: int offset,
323: int length)
324: {
325: Vector refPos = v == null ? new Vector() : v;
326: Iterator iter = marks.iterator();
327: while(iter.hasNext())
328: {
329: Mark m = (Mark) iter.next();
330: if (offset <= m.mark && m.mark <= offset + length)
331: refPos.add(new UndoPosRef(m));
332: }
333: return refPos;
334: }
335:
336:
346: public Position createPosition(int offset) throws BadLocationException
347: {
348:
349: if (marks == null)
350: marks = new Vector();
351: StickyPosition sp = new StickyPosition(offset);
352: return sp;
353: }
354:
355:
361: public int length()
362: {
363: return count;
364: }
365:
366:
376: public UndoableEdit insertString(int where, String str)
377: throws BadLocationException
378: {
379: checkLocation(where, 0);
380: if (where == this.count)
381: throw new BadLocationException("Invalid location", 1);
382: if (str == null)
383: throw new NullPointerException();
384: char[] insert = str.toCharArray();
385: replace(where, 0, insert);
386:
387:
388: if (marks != null)
389: {
390: Iterator iter = marks.iterator();
391: int start = where;
392: if (start == 0)
393: start = 1;
394: while (iter.hasNext())
395: {
396: Mark m = (Mark) iter.next();
397: if (m.mark >= start)
398: m.mark += str.length();
399: }
400: }
401:
402: InsertUndo iundo = new InsertUndo(where, insert.length);
403: return iundo;
404: }
405:
406:
418: public UndoableEdit remove(int where, int nitems) throws BadLocationException
419: {
420: checkLocation(where, nitems + 1);
421: RemoveUndo rundo = new RemoveUndo(where, new String(this.content, where,
422: nitems));
423:
424: replace(where, nitems, EMPTY);
425:
426: if (marks != null)
427: {
428: Iterator iter = marks.iterator();
429: while (iter.hasNext())
430: {
431: Mark m = (Mark) iter.next();
432: if (m.mark >= where + nitems)
433: m.mark -= nitems;
434: else if (m.mark >= where)
435: m.mark = where;
436: }
437: }
438: return rundo;
439: }
440:
441: private void replace(int offs, int numRemove, char[] insert)
442: {
443: int insertLength = insert.length;
444: int delta = insertLength - numRemove;
445: int src = offs + numRemove;
446: int numMove = count - src;
447: int dest = src + delta;
448: if (count + delta >= content.length)
449: {
450:
451: int newLength = Math.max(2 * content.length, count + delta);
452: char[] newContent = new char[newLength];
453: System.arraycopy(content, 0, newContent, 0, offs);
454: System.arraycopy(insert, 0, newContent, offs, insertLength);
455: System.arraycopy(content, src, newContent, dest, numMove);
456: content = newContent;
457: }
458: else
459: {
460: System.arraycopy(content, src, content, dest, numMove);
461: System.arraycopy(insert, 0, content, offs, insertLength);
462: }
463: count += delta;
464: }
465:
466:
478: public String getString(int where, int len) throws BadLocationException
479: {
480:
481:
482: checkLocation(where, len);
483: return new String(this.content, where, len);
484: }
485:
486:
499: public void getChars(int where, int len, Segment txt)
500: throws BadLocationException
501: {
502: if (where + len > count)
503: throw new BadLocationException("Invalid location", where + len);
504: txt.array = content;
505: txt.offset = where;
506: txt.count = len;
507: }
508:
509:
510:
517: protected void updateUndoPositions(Vector positions)
518: {
519: for (Iterator i = positions.iterator(); i.hasNext();)
520: {
521: UndoPosRef pos = (UndoPosRef) i.next();
522: pos.reset();
523: }
524: }
525:
526:
536: void checkLocation(int where, int len) throws BadLocationException
537: {
538: if (where < 0)
539: throw new BadLocationException("Invalid location", 1);
540: else if (where > this.count)
541: throw new BadLocationException("Invalid location", this.count);
542: else if ((where + len) > this.count)
543: throw new BadLocationException("Invalid range", this.count);
544: }
545:
546:
553: void garbageCollect()
554: {
555: Reference ref = queueOfDeath.poll();
556: while (ref != null)
557: {
558: if (ref != null)
559: {
560: StickyPosition pos = (StickyPosition) ref.get();
561: Mark m = pos.mark;
562: m.refCount--;
563: if (m.refCount == 0)
564: marks.remove(m);
565: }
566: ref = queueOfDeath.poll();
567: }
568: }
569: }