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:
64: public class GapContent
65: implements AbstractDocument.Content, Serializable
66: {
67:
70: class GapContentPosition
71: implements Position, Comparable
72: {
73:
74:
75: int mark;
76:
77:
82: GapContentPosition(int mark)
83: {
84: this.mark = mark;
85: }
86:
87:
100: public int compareTo(Object o)
101: {
102: if (o instanceof Integer)
103: {
104: int otherMark = ((Integer) o).intValue();
105: return mark - otherMark;
106: }
107: else
108: {
109: GapContentPosition other = (GapContentPosition) o;
110: return mark - other.mark;
111: }
112: }
113:
114:
119: public int getOffset()
120: {
121:
122: assert mark <= gapStart || mark >= gapEnd : "mark: " + mark
123: + ", gapStart: " + gapStart
124: + ", gapEnd: " + gapEnd;
125:
126: if (mark <= gapStart)
127: return mark;
128: else
129: return mark - (gapEnd - gapStart);
130: }
131: }
132:
133: class UndoInsertString extends AbstractUndoableEdit
134: {
135: public int where, length;
136: String text;
137: public UndoInsertString(int start, int len)
138: {
139: where = start;
140: length = len;
141: }
142:
143: public void undo () throws CannotUndoException
144: {
145: super.undo();
146: try
147: {
148: text = getString(where, length);
149: remove(where, length);
150: }
151: catch (BadLocationException ble)
152: {
153: throw new CannotUndoException();
154: }
155: }
156:
157: public void redo () throws CannotUndoException
158: {
159: super.redo();
160: try
161: {
162: insertString(where, text);
163: }
164: catch (BadLocationException ble)
165: {
166: throw new CannotRedoException();
167: }
168: }
169:
170: }
171:
172: class UndoRemove extends AbstractUndoableEdit
173: {
174: public int where;
175: String text;
176: public UndoRemove(int start, String removedText)
177: {
178: where = start;
179: text = removedText;
180: }
181:
182: public void undo () throws CannotUndoException
183: {
184: super.undo();
185: try
186: {
187: insertString(where, text);
188: }
189: catch (BadLocationException ble)
190: {
191: throw new CannotUndoException();
192: }
193: }
194:
195: public void redo () throws CannotUndoException
196: {
197: super.redo();
198: try
199: {
200: remove(where, text.length());
201: }
202: catch (BadLocationException ble)
203: {
204: throw new CannotRedoException();
205: }
206: }
207:
208: }
209:
210:
211: private static final long serialVersionUID = -6226052713477823730L;
212:
213:
217: static final int DEFAULT_BUFSIZE = 10;
218:
219:
222: char[] buffer;
223:
224:
227: int gapStart;
228:
229:
232: int gapEnd;
233:
234:
238: ArrayList positions;
239:
240:
243: public GapContent()
244: {
245: this(DEFAULT_BUFSIZE);
246: }
247:
248:
253: public GapContent(int size)
254: {
255: buffer = (char[]) allocateArray(size);
256: gapStart = 1;
257: gapEnd = size;
258: buffer[0] = '\n';
259: positions = new ArrayList();
260: }
261:
262:
270: protected Object allocateArray(int size)
271: {
272: return new char[size];
273: }
274:
275:
280: protected int getArrayLength()
281: {
282: return buffer.length;
283: }
284:
285:
290: public int length()
291: {
292: return buffer.length - (gapEnd - gapStart);
293: }
294:
295:
306: public UndoableEdit insertString(int where, String str)
307: throws BadLocationException
308: {
309:
310: int length = length();
311: int strLen = str.length();
312:
313: if (where >= length)
314: throw new BadLocationException("the where argument cannot be greater"
315: + " than the content length", where);
316:
317: replace(where, 0, str.toCharArray(), strLen);
318:
319: return new UndoInsertString(where, strLen);
320: }
321:
322:
333: public UndoableEdit remove(int where, int nitems) throws BadLocationException
334: {
335:
336: int length = length();
337:
338: if (where >= length)
339: throw new BadLocationException("the where argument cannot be greater"
340: + " than the content length", where);
341: if ((where + nitems) > length)
342: throw new BadLocationException("where + nitems cannot be greater"
343: + " than the content length", where + nitems);
344:
345: String removedText = getString(where, nitems);
346: replace(where, nitems, null, 0);
347:
348: return new UndoRemove(where, removedText);
349: }
350:
351:
360: public String getString(int where, int len) throws BadLocationException
361: {
362: Segment seg = new Segment();
363: try
364: {
365: getChars(where, len, seg);
366: return new String(seg.array, seg.offset, seg.count);
367: }
368: catch (StringIndexOutOfBoundsException ex)
369: {
370: int invalid = 0;
371: if (seg.offset < 0 || seg.offset >= seg.array.length)
372: invalid = seg.offset;
373: else
374: invalid = seg.offset + seg.count;
375: throw new BadLocationException("Illegal location: array.length = "
376: + seg.array.length + ", offset = "
377: + seg.offset + ", count = "
378: + seg.count, invalid);
379: }
380: }
381:
382:
396: public void getChars(int where, int len, Segment txt)
397: throws BadLocationException
398: {
399:
400: int length = length();
401: if (where >= length)
402: throw new BadLocationException("the where argument cannot be greater"
403: + " than the content length", where);
404: if ((where + len) > length)
405: throw new BadLocationException("len plus where cannot be greater"
406: + " than the content length", len + where);
407:
408:
409: if ((where < gapStart) && ((gapStart - where) < len))
410: {
411:
412: char[] copy = new char[len];
413: int lenFirst = gapStart - where;
414: System.arraycopy(buffer, where, copy, 0, lenFirst);
415: System.arraycopy(buffer, gapEnd, copy, lenFirst, len - lenFirst);
416: txt.array = copy;
417: txt.offset = 0;
418: txt.count = len;
419: }
420: else
421: {
422:
423:
424: txt.array = buffer;
425: if (where < gapStart)
426: txt.offset = where;
427: else
428: txt.offset = where + (gapEnd - gapStart);
429: txt.count = len;
430: }
431: }
432:
433:
443: public Position createPosition(final int offset) throws BadLocationException
444: {
445: if (offset < 0 || offset > length())
446: throw new BadLocationException("The offset was out of the bounds of this"
447: + " buffer", offset);
448:
449:
450:
451: int mark = offset;
452: if (offset > gapStart)
453: mark += gapEnd - gapStart;
454: GapContentPosition pos = new GapContentPosition(mark);
455:
456:
457: int index = Collections.binarySearch(positions, pos);
458: if (index < 0)
459: index = -(index + 1);
460: positions.add(index, pos);
461: return pos;
462: }
463:
464:
472: protected void shiftEnd(int newSize)
473: {
474: assert newSize > (gapEnd - gapStart) : "The new gap size must be greater "
475: + "than the old gap size";
476:
477: int delta = newSize - gapEnd + gapStart;
478:
479: adjustPositionsInRange(gapEnd, buffer.length - gapEnd, delta);
480:
481:
482: char[] newBuf = (char[]) allocateArray(length() + newSize);
483: System.arraycopy(buffer, 0, newBuf, 0, gapStart);
484: System.arraycopy(buffer, gapEnd, newBuf, gapStart + newSize, buffer.length
485: - gapEnd);
486: gapEnd = gapStart + newSize;
487: buffer = newBuf;
488:
489: }
490:
491:
496: protected void shiftGap(int newGapStart)
497: {
498: if (newGapStart == gapStart)
499: return;
500:
501: int newGapEnd = newGapStart + gapEnd - gapStart;
502: if (newGapStart < gapStart)
503: {
504:
505:
506: adjustPositionsInRange(newGapStart, gapStart - newGapStart, gapEnd - gapStart);
507: System.arraycopy(buffer, newGapStart, buffer, newGapEnd, gapStart
508: - newGapStart);
509: gapStart = newGapStart;
510: gapEnd = newGapEnd;
511: }
512: else
513: {
514:
515:
516: adjustPositionsInRange(gapEnd, newGapEnd - gapEnd, -(gapEnd - gapStart));
517: System.arraycopy(buffer, gapEnd, buffer, gapStart, newGapStart
518: - gapStart);
519: gapStart = newGapStart;
520: gapEnd = newGapEnd;
521: }
522: if (gapStart == 0)
523: resetMarksAtZero();
524: }
525:
526:
534: protected void shiftGapStartDown(int newGapStart)
535: {
536: if (newGapStart == gapStart)
537: return;
538:
539: assert newGapStart < gapStart : "The new gap start must be less than the "
540: + "old gap start.";
541: setPositionsInRange(newGapStart, gapStart - newGapStart, gapStart);
542: gapStart = newGapStart;
543: }
544:
545:
553: protected void shiftGapEndUp(int newGapEnd)
554: {
555: if (newGapEnd == gapEnd)
556: return;
557:
558: assert newGapEnd > gapEnd : "The new gap end must be greater than the "
559: + "old gap end.";
560: setPositionsInRange(gapEnd, newGapEnd - gapEnd, newGapEnd + 1);
561: gapEnd = newGapEnd;
562: }
563:
564:
569: protected Object getArray()
570: {
571: return buffer;
572: }
573:
574:
582: protected void replace(int position, int rmSize, Object addItems,
583: int addSize)
584: {
585: if (gapStart != position)
586: shiftGap(position);
587:
588: if (rmSize > 0)
589: shiftGapEndUp(gapEnd + rmSize);
590:
591:
592: if ((gapEnd - gapStart) <= addSize)
593: shiftEnd((addSize - gapEnd + gapStart + 1) * 2 + gapEnd + DEFAULT_BUFSIZE);
594:
595:
596: if (addItems != null)
597: {
598: System.arraycopy(addItems, 0, buffer, gapStart, addSize);
599: gapStart += addSize;
600: }
601: }
602:
603:
608: protected final int getGapStart()
609: {
610: return gapStart;
611: }
612:
613:
618: protected final int getGapEnd()
619: {
620: return gapEnd;
621: }
622:
623:
633: protected Vector getPositionsInRange(Vector v, int offset, int length)
634: {
635: Vector res = v;
636: if (res == null)
637: res = new Vector();
638: else
639: res.clear();
640:
641: int endOffset = offset + length;
642:
643: int index1 = Collections.binarySearch(positions,
644: new GapContentPosition(offset));
645: if (index1 < 0)
646: index1 = -(index1 + 1);
647: for (ListIterator i = positions.listIterator(index1); i.hasNext();)
648: {
649: GapContentPosition p = (GapContentPosition) i.next();
650: if (p.mark > endOffset)
651: break;
652: if (p.mark >= offset && p.mark <= endOffset)
653: res.add(p);
654: }
655: return res;
656: }
657:
658:
667: void setPositionsInRange(int offset, int length, int value)
668: {
669: int endOffset = offset + length;
670:
671: int index1 = Collections.binarySearch(positions,
672: new GapContentPosition(offset));
673: if (index1 < 0)
674: index1 = -(index1 + 1);
675: for (ListIterator i = positions.listIterator(index1); i.hasNext();)
676: {
677: GapContentPosition p = (GapContentPosition) i.next();
678: if (p.mark > endOffset)
679: break;
680:
681: if (p.mark >= offset && p.mark <= endOffset)
682: p.mark = value;
683: }
684: }
685:
686:
695: void adjustPositionsInRange(int offset, int length, int incr)
696: {
697: int endOffset = offset + length;
698:
699: int index1 = Collections.binarySearch(positions,
700: new GapContentPosition(offset));
701: if (index1 < 0)
702: index1 = -(index1 + 1);
703: for (ListIterator i = positions.listIterator(index1); i.hasNext();)
704: {
705: GapContentPosition p = (GapContentPosition) i.next();
706: if (p.mark > endOffset)
707: break;
708:
709: if (p.mark >= offset && p.mark <= endOffset)
710: p.mark += incr;
711: }
712: }
713:
714:
720: protected void resetMarksAtZero()
721: {
722: if (gapStart != 0)
723: return;
724:
725: setPositionsInRange(gapEnd, 0, 0);
726: }
727:
728:
733: private void dump()
734: {
735: System.err.println("GapContent debug information");
736: System.err.println("buffer length: " + buffer.length);
737: System.err.println("gap start: " + gapStart);
738: System.err.println("gap end: " + gapEnd);
739: for (int i = 0; i < buffer.length; i++)
740: {
741: if (i == gapStart)
742: System.err.print('<');
743: if (i == gapEnd)
744: System.err.print('>');
745:
746: if (!Character.isISOControl(buffer[i]))
747: System.err.print(buffer[i]);
748: else
749: System.err.print('.');
750: }
751: System.err.println();
752: }
753:
754: private void dumpPositions()
755: {
756: for (Iterator i = positions.iterator(); i.hasNext();)
757: {
758: GapContentPosition pos = (GapContentPosition) i.next();
759: System.err.println("position at: " + pos.mark);
760: }
761: }
762: }