1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49:
50: import ;
51: import ;
52: import ;
53: import ;
54:
55:
66: public class GapContent
67: implements AbstractDocument.Content, Serializable
68: {
69:
70:
73: private class GapContentPosition
74: implements Position, Comparable
75: {
76:
77:
78: int mark;
79:
80:
85: GapContentPosition(int mark)
86: {
87: this.mark = mark;
88: }
89:
90:
103: public int compareTo(Object o)
104: {
105: if (o instanceof Integer)
106: {
107: int otherMark = ((Integer) o).intValue();
108: return mark - otherMark;
109: }
110: else
111: {
112: GapContentPosition other = (GapContentPosition) o;
113: return mark - other.mark;
114: }
115: }
116:
117:
122: public int getOffset()
123: {
124:
125: assert mark <= gapStart || mark >= gapEnd : "mark: " + mark
126: + ", gapStart: " + gapStart
127: + ", gapEnd: " + gapEnd;
128: if (mark <= gapStart)
129: return mark;
130: else
131: return mark - (gapEnd - gapStart);
132: }
133: }
134:
135: private class InsertUndo extends AbstractUndoableEdit
136: {
137: public int where, length;
138: String text;
139: public InsertUndo(int start, int len)
140: {
141: where = start;
142: length = len;
143: }
144:
145: public void undo () throws CannotUndoException
146: {
147: super.undo();
148: try
149: {
150: text = getString(where, length);
151: remove(where, length);
152: }
153: catch (BadLocationException ble)
154: {
155: throw new CannotUndoException();
156: }
157: }
158:
159: public void redo () throws CannotUndoException
160: {
161: super.redo();
162: try
163: {
164: insertString(where, text);
165: }
166: catch (BadLocationException ble)
167: {
168: throw new CannotRedoException();
169: }
170: }
171:
172: }
173:
174: private class UndoRemove extends AbstractUndoableEdit
175: {
176: public int where;
177: String text;
178: public UndoRemove(int start, String removedText)
179: {
180: where = start;
181: text = removedText;
182: }
183:
184: public void undo () throws CannotUndoException
185: {
186: super.undo();
187: try
188: {
189: insertString(where, text);
190: }
191: catch (BadLocationException ble)
192: {
193: throw new CannotUndoException();
194: }
195: }
196:
197: public void redo () throws CannotUndoException
198: {
199: super.redo();
200: try
201: {
202: remove(where, text.length());
203: }
204: catch (BadLocationException ble)
205: {
206: throw new CannotRedoException();
207: }
208: }
209:
210: }
211:
212:
218: private class WeakPositionComparator
219: implements Comparator
220: {
221:
222:
226: public int compare(Object o1, Object o2)
227: {
228:
229: if (o1 instanceof WeakReference)
230: o1 = ((WeakReference) o1).get();
231: if (o2 instanceof WeakReference)
232: o2 = ((WeakReference) o2).get();
233:
234: GapContentPosition p1 = (GapContentPosition) o1;
235: GapContentPosition p2 = (GapContentPosition) o2;
236:
237: int retVal;
238: if (p1 == null || p2 == null)
239: retVal = -1;
240: else
241: retVal = p1.compareTo(p2);
242: return retVal;
243: }
244: }
245:
246:
247: private static final long serialVersionUID = -6226052713477823730L;
248:
249:
253: static final int DEFAULT_BUFSIZE = 10;
254:
255:
258: char[] buffer;
259:
260:
263: int gapStart;
264:
265:
268: int gapEnd;
269:
270:
275: private ArrayList positions;
276:
277:
280: public GapContent()
281: {
282: this(DEFAULT_BUFSIZE);
283: }
284:
285:
290: public GapContent(int size)
291: {
292: size = Math.max(size, 2);
293: buffer = (char[]) allocateArray(size);
294: gapStart = 1;
295: gapEnd = size;
296: buffer[0] = '\n';
297: positions = new ArrayList();
298: }
299:
300:
308: protected Object allocateArray(int size)
309: {
310: return new char[size];
311: }
312:
313:
318: protected int getArrayLength()
319: {
320: return buffer.length;
321: }
322:
323:
328: public int length()
329: {
330: return buffer.length - (gapEnd - gapStart);
331: }
332:
333:
344: public UndoableEdit insertString(int where, String str)
345: throws BadLocationException
346: {
347:
348: int length = length();
349: int strLen = str.length();
350:
351: if (where < 0)
352: throw new BadLocationException("The where argument cannot be smaller"
353: + " than the zero", where);
354:
355: if (where > length)
356: throw new BadLocationException("The where argument cannot be greater"
357: + " than the content length", where);
358:
359: replace(where, 0, str.toCharArray(), strLen);
360:
361: return new InsertUndo(where, strLen);
362: }
363:
364:
375: public UndoableEdit remove(int where, int nitems) throws BadLocationException
376: {
377:
378: int length = length();
379:
380: if ((where + nitems) >= length)
381: throw new BadLocationException("where + nitems cannot be greater"
382: + " than the content length", where + nitems);
383:
384: String removedText = getString(where, nitems);
385: replace(where, nitems, null, 0);
386:
387: return new UndoRemove(where, removedText);
388: }
389:
390:
399: public String getString(int where, int len) throws BadLocationException
400: {
401: Segment seg = new Segment();
402: try
403: {
404: getChars(where, len, seg);
405: return new String(seg.array, seg.offset, seg.count);
406: }
407: catch (StringIndexOutOfBoundsException ex)
408: {
409: int invalid = 0;
410: if (seg.offset < 0 || seg.offset >= seg.array.length)
411: invalid = seg.offset;
412: else
413: invalid = seg.offset + seg.count;
414: throw new BadLocationException("Illegal location: array.length = "
415: + seg.array.length + ", offset = "
416: + seg.offset + ", count = "
417: + seg.count, invalid);
418: }
419: }
420:
421:
435: public void getChars(int where, int len, Segment txt)
436: throws BadLocationException
437: {
438:
439: int length = length();
440: if (where < 0)
441: throw new BadLocationException("the where argument may not be below zero", where);
442: if (where >= length)
443: throw new BadLocationException("the where argument cannot be greater"
444: + " than the content length", where);
445: if ((where + len) > length)
446: throw new BadLocationException("len plus where cannot be greater"
447: + " than the content length", len + where);
448:
449:
450: if ((where < gapStart) && ((gapStart - where) < len))
451: {
452:
453: char[] copy = new char[len];
454: int lenFirst = gapStart - where;
455: System.arraycopy(buffer, where, copy, 0, lenFirst);
456: System.arraycopy(buffer, gapEnd, copy, lenFirst, len - lenFirst);
457: txt.array = copy;
458: txt.offset = 0;
459: txt.count = len;
460: }
461: else
462: {
463:
464:
465: txt.array = buffer;
466: if (where < gapStart)
467: txt.offset = where;
468: else
469: txt.offset = where + (gapEnd - gapStart);
470: txt.count = len;
471: }
472: }
473:
474:
484: public Position createPosition(final int offset) throws BadLocationException
485: {
486: if (offset < 0 || offset > length())
487: throw new BadLocationException("The offset was out of the bounds of this"
488: + " buffer", offset);
489:
490: clearPositionReferences();
491:
492:
493:
494: int mark = offset;
495: if (offset >= gapStart)
496: mark += gapEnd - gapStart;
497: GapContentPosition pos = new GapContentPosition(mark);
498: WeakReference r = new WeakReference(pos);
499:
500:
501: int index = Collections.binarySearch(positions, r,
502: new WeakPositionComparator());
503: if (index < 0)
504: index = -(index + 1);
505: positions.add(index, r);
506: return pos;
507: }
508:
509:
517: protected void shiftEnd(int newSize)
518: {
519: assert newSize > (gapEnd - gapStart) : "The new gap size must be greater "
520: + "than the old gap size";
521:
522: int delta = newSize - gapEnd + gapStart;
523:
524: adjustPositionsInRange(gapEnd, buffer.length - gapEnd, delta);
525:
526:
527: char[] newBuf = (char[]) allocateArray(length() + newSize);
528: System.arraycopy(buffer, 0, newBuf, 0, gapStart);
529: System.arraycopy(buffer, gapEnd, newBuf, gapStart + newSize, buffer.length
530: - gapEnd);
531: gapEnd = gapStart + newSize;
532: buffer = newBuf;
533:
534: }
535:
536:
541: protected void shiftGap(int newGapStart)
542: {
543: if (newGapStart == gapStart)
544: return;
545:
546: int newGapEnd = newGapStart + gapEnd - gapStart;
547: if (newGapStart < gapStart)
548: {
549:
550:
551: adjustPositionsInRange(newGapStart, gapStart - newGapStart, gapEnd - gapStart);
552: System.arraycopy(buffer, newGapStart, buffer, newGapEnd, gapStart
553: - newGapStart);
554: gapStart = newGapStart;
555: gapEnd = newGapEnd;
556: }
557: else
558: {
559:
560:
561: adjustPositionsInRange(gapEnd, newGapEnd - gapEnd, -(gapEnd - gapStart));
562: System.arraycopy(buffer, gapEnd, buffer, gapStart, newGapStart
563: - gapStart);
564: gapStart = newGapStart;
565: gapEnd = newGapEnd;
566: }
567: if (gapStart == 0)
568: resetMarksAtZero();
569: }
570:
571:
579: protected void shiftGapStartDown(int newGapStart)
580: {
581: if (newGapStart == gapStart)
582: return;
583:
584: assert newGapStart < gapStart : "The new gap start must be less than the "
585: + "old gap start.";
586: setPositionsInRange(newGapStart, gapStart - newGapStart, gapStart);
587: gapStart = newGapStart;
588: }
589:
590:
598: protected void shiftGapEndUp(int newGapEnd)
599: {
600: if (newGapEnd == gapEnd)
601: return;
602:
603: assert newGapEnd > gapEnd : "The new gap end must be greater than the "
604: + "old gap end.";
605: setPositionsInRange(gapEnd, newGapEnd - gapEnd, newGapEnd);
606: gapEnd = newGapEnd;
607: }
608:
609:
614: protected final Object getArray()
615: {
616: return buffer;
617: }
618:
619:
627: protected void replace(int position, int rmSize, Object addItems,
628: int addSize)
629: {
630: if (gapStart != position)
631: shiftGap(position);
632:
633:
634: if (rmSize > 0)
635: shiftGapEndUp(gapEnd + rmSize);
636:
637:
638: if ((gapEnd - gapStart) <= addSize)
639: shiftEnd((addSize - gapEnd + gapStart + 1) * 2 + gapEnd + DEFAULT_BUFSIZE);
640:
641:
642: if (addItems != null)
643: {
644: System.arraycopy(addItems, 0, buffer, gapStart, addSize);
645:
646:
647: resetMarksAtZero();
648:
649: gapStart += addSize;
650: }
651: }
652:
653:
658: protected final int getGapStart()
659: {
660: return gapStart;
661: }
662:
663:
668: protected final int getGapEnd()
669: {
670: return gapEnd;
671: }
672:
673:
683: protected Vector getPositionsInRange(Vector v, int offset, int length)
684: {
685: Vector res = v;
686: if (res == null)
687: res = new Vector();
688: else
689: res.clear();
690:
691: int endOffset = offset + length;
692:
693: int index1 = Collections.binarySearch(positions,
694: new GapContentPosition(offset),
695: new WeakPositionComparator());
696: if (index1 < 0)
697: index1 = -(index1 + 1);
698:
699:
700:
701: while (index1 > 0)
702: {
703: WeakReference r = (WeakReference) positions.get(index1 - 1);
704: GapContentPosition p = (GapContentPosition) r.get();
705: if (p != null && p.mark == offset || p == null)
706: index1--;
707: else
708: break;
709: }
710:
711: for (ListIterator i = positions.listIterator(index1); i.hasNext();)
712: {
713: WeakReference r = (WeakReference) i.next();
714: GapContentPosition p = (GapContentPosition) r.get();
715: if (p == null)
716: continue;
717:
718: if (p.mark > endOffset)
719: break;
720: if (p.mark >= offset && p.mark <= endOffset)
721: res.add(p);
722: }
723: return res;
724: }
725:
726:
735: private void setPositionsInRange(int offset, int length, int value)
736: {
737: int endOffset = offset + length;
738:
739: int index1 = Collections.binarySearch(positions,
740: new GapContentPosition(offset),
741: new WeakPositionComparator());
742: if (index1 < 0)
743: index1 = -(index1 + 1);
744:
745:
746:
747: while (index1 > 0)
748: {
749: WeakReference r = (WeakReference) positions.get(index1 - 1);
750: GapContentPosition p = (GapContentPosition) r.get();
751: if (p != null && p.mark == offset || p == null)
752: index1--;
753: else
754: break;
755: }
756:
757: for (ListIterator i = positions.listIterator(index1); i.hasNext();)
758: {
759: WeakReference r = (WeakReference) i.next();
760: GapContentPosition p = (GapContentPosition) r.get();
761: if (p == null)
762: continue;
763:
764: if (p.mark > endOffset)
765: break;
766:
767: if (p.mark >= offset && p.mark <= endOffset)
768: p.mark = value;
769: }
770: }
771:
772:
781: private void adjustPositionsInRange(int offset, int length, int incr)
782: {
783: int endOffset = offset + length;
784:
785: int index1 = Collections.binarySearch(positions,
786: new GapContentPosition(offset),
787: new WeakPositionComparator());
788: if (index1 < 0)
789: index1 = -(index1 + 1);
790:
791:
792:
793: while (index1 > 0)
794: {
795: WeakReference r = (WeakReference) positions.get(index1 - 1);
796: GapContentPosition p = (GapContentPosition) r.get();
797: if (p != null && p.mark == offset || p == null)
798: index1--;
799: else
800: break;
801: }
802:
803: for (ListIterator i = positions.listIterator(index1); i.hasNext();)
804: {
805: WeakReference r = (WeakReference) i.next();
806: GapContentPosition p = (GapContentPosition) r.get();
807: if (p == null)
808: continue;
809:
810: if (p.mark > endOffset)
811: break;
812:
813: if (p.mark >= offset && p.mark <= endOffset)
814: p.mark += incr;
815: }
816: }
817:
818:
824: protected void resetMarksAtZero()
825: {
826: if (gapStart != 0)
827: return;
828:
829: setPositionsInRange(gapEnd, 0, 0);
830: }
831:
832:
838: protected void updateUndoPositions(Vector positions, int offset, int length)
839: {
840:
841: }
842:
843:
848: private void dump()
849: {
850: System.err.println("GapContent debug information");
851: System.err.println("buffer length: " + buffer.length);
852: System.err.println("gap start: " + gapStart);
853: System.err.println("gap end: " + gapEnd);
854: for (int i = 0; i < buffer.length; i++)
855: {
856: if (i == gapStart)
857: System.err.print('<');
858: if (i == gapEnd)
859: System.err.print('>');
860:
861: if (!Character.isISOControl(buffer[i]))
862: System.err.print(buffer[i]);
863: else
864: System.err.print('.');
865: }
866: System.err.println();
867: }
868:
869: private void dumpPositions()
870: {
871: for (Iterator i = positions.iterator(); i.hasNext();)
872: {
873: WeakReference r = (WeakReference) i.next();
874: GapContentPosition pos = (GapContentPosition) r.get();
875: System.err.println("position at: " + pos.mark);
876: }
877: }
878:
879:
882: private void clearPositionReferences()
883: {
884: Iterator i = positions.iterator();
885: while (i.hasNext())
886: {
887: WeakReference r = (WeakReference) i.next();
888: if (r.get() == null)
889: i.remove();
890: }
891: }
892: }