41 |
import java.io.Serializable; |
import java.io.Serializable; |
42 |
import java.util.ArrayList; |
import java.util.ArrayList; |
43 |
import java.util.Collections; |
import java.util.Collections; |
44 |
|
import java.util.Iterator; |
45 |
import java.util.ListIterator; |
import java.util.ListIterator; |
46 |
|
import java.util.Vector; |
47 |
|
|
48 |
import javax.swing.undo.UndoableEdit; |
import javax.swing.undo.UndoableEdit; |
49 |
|
|
116 |
public int getOffset() |
public int getOffset() |
117 |
{ |
{ |
118 |
// Check precondition. |
// Check precondition. |
119 |
assert(mark <= gapStart || mark > gapEnd); |
assert mark <= gapStart || mark > gapEnd : "mark: " + mark |
120 |
|
+ ", gapStart: " + gapStart |
121 |
|
+ ", gapEnd: " + gapEnd; |
122 |
|
|
123 |
if (mark <= gapStart) |
if (mark <= gapStart) |
124 |
return mark; |
return mark; |
134 |
* This is the default buffer size and the amount of bytes that a buffer is |
* This is the default buffer size and the amount of bytes that a buffer is |
135 |
* extended if it is full. |
* extended if it is full. |
136 |
*/ |
*/ |
137 |
static final int DEFAULT_BUFSIZE = 64; |
static final int DEFAULT_BUFSIZE = 10; |
138 |
|
|
139 |
/** |
/** |
140 |
* The text buffer. |
* The text buffer. |
173 |
public GapContent(int size) |
public GapContent(int size) |
174 |
{ |
{ |
175 |
buffer = (char[]) allocateArray(size); |
buffer = (char[]) allocateArray(size); |
176 |
gapStart = 0; |
gapStart = 1; |
177 |
gapEnd = size - 1; |
gapEnd = size; |
178 |
buffer[size - 1] = '\n'; |
buffer[0] = '\n'; |
179 |
positions = new ArrayList(); |
positions = new ArrayList(); |
180 |
} |
} |
181 |
|
|
393 |
*/ |
*/ |
394 |
protected void shiftEnd(int newSize) |
protected void shiftEnd(int newSize) |
395 |
{ |
{ |
396 |
int delta = (gapEnd - gapStart) - newSize; |
assert newSize > (gapEnd - gapStart) : "The new gap size must be greater " |
397 |
|
+ "than the old gap size"; |
398 |
|
|
399 |
|
int delta = newSize - gapEnd + gapStart; |
400 |
|
// Update the marks after the gapEnd. |
401 |
|
Vector v = getPositionsInRange(null, gapEnd, buffer.length - gapEnd); |
402 |
|
for (Iterator i = v.iterator(); i.hasNext();) |
403 |
|
{ |
404 |
|
GapContentPosition p = (GapContentPosition) i.next(); |
405 |
|
p.mark += delta; |
406 |
|
} |
407 |
|
|
408 |
|
// Copy the data around. |
409 |
char[] newBuf = (char[]) allocateArray(length() + newSize); |
char[] newBuf = (char[]) allocateArray(length() + newSize); |
410 |
System.arraycopy(buffer, 0, newBuf, 0, gapStart); |
System.arraycopy(buffer, 0, newBuf, 0, gapStart); |
411 |
System.arraycopy(buffer, gapEnd, newBuf, gapStart + newSize, buffer.length |
System.arraycopy(buffer, gapEnd, newBuf, gapStart + newSize, buffer.length |
413 |
gapEnd = gapStart + newSize; |
gapEnd = gapStart + newSize; |
414 |
buffer = newBuf; |
buffer = newBuf; |
415 |
|
|
|
// Update the marks after the gapEnd. |
|
|
int index = Collections.binarySearch(positions, new GapContentPosition( |
|
|
gapEnd)); |
|
|
if (index < 0) |
|
|
{ |
|
|
index = -(index + 1); |
|
|
} |
|
|
for (ListIterator i = positions.listIterator(index); i.hasNext();) |
|
|
{ |
|
|
GapContentPosition p = (GapContentPosition) i.next(); |
|
|
p.mark += delta; |
|
|
} |
|
416 |
} |
} |
417 |
|
|
418 |
/** |
/** |
425 |
if (newGapStart == gapStart) |
if (newGapStart == gapStart) |
426 |
return; |
return; |
427 |
|
|
428 |
int newGapEnd = newGapStart + (gapEnd - gapStart); |
int newGapEnd = newGapStart + gapEnd - gapStart; |
429 |
|
|
430 |
// Update the positions between newGapEnd and (old) gapEnd. The marks |
if (newGapStart < gapStart) |
|
// must be shifted by (gapEnd - newGapEnd). |
|
|
int index1 = Collections.binarySearch(positions, |
|
|
new GapContentPosition(gapEnd)); |
|
|
int index2 = Collections.binarySearch(positions, |
|
|
new GapContentPosition(newGapEnd)); |
|
|
if (index1 > 0 && index2 > 0) |
|
431 |
{ |
{ |
432 |
int i1 = Math.min(index1, index2); |
// Update the positions between newGapStart and (old) gapStart. The marks |
433 |
int i2 = Math.max(index1, index2); |
// must be shifted by (gapEnd - gapStart). |
434 |
for (ListIterator i = positions.listIterator(i1); i.hasNext();) |
Vector v = getPositionsInRange(null, newGapStart + 1, |
435 |
|
gapStart - newGapStart + 1); |
436 |
|
for (Iterator i = v.iterator(); i.hasNext();) |
437 |
{ |
{ |
|
if (i.nextIndex() > i2) |
|
|
break; |
|
|
|
|
438 |
GapContentPosition p = (GapContentPosition) i.next(); |
GapContentPosition p = (GapContentPosition) i.next(); |
439 |
p.mark += gapEnd - newGapEnd; |
p.mark += gapEnd - gapStart; |
440 |
} |
} |
|
} |
|
|
|
|
|
if (newGapStart < gapStart) |
|
|
{ |
|
441 |
System.arraycopy(buffer, newGapStart, buffer, newGapEnd, gapStart |
System.arraycopy(buffer, newGapStart, buffer, newGapEnd, gapStart |
442 |
- newGapStart); |
- newGapStart); |
443 |
gapStart = newGapStart; |
gapStart = newGapStart; |
445 |
} |
} |
446 |
else |
else |
447 |
{ |
{ |
448 |
|
// Update the positions between newGapEnd and (old) gapEnd. The marks |
449 |
|
// must be shifted by (gapEnd - gapStart). |
450 |
|
Vector v = getPositionsInRange(null, gapEnd, |
451 |
|
newGapEnd - gapEnd); |
452 |
|
for (Iterator i = v.iterator(); i.hasNext();) |
453 |
|
{ |
454 |
|
GapContentPosition p = (GapContentPosition) i.next(); |
455 |
|
p.mark -= gapEnd - gapStart; |
456 |
|
} |
457 |
System.arraycopy(buffer, gapEnd, buffer, gapStart, newGapStart |
System.arraycopy(buffer, gapEnd, buffer, gapStart, newGapStart |
458 |
- gapStart); |
- gapStart); |
459 |
gapStart = newGapStart; |
gapStart = newGapStart; |
462 |
} |
} |
463 |
|
|
464 |
/** |
/** |
465 |
|
* Shifts the gap start downwards. This does not affect the content of the |
466 |
|
* buffer. This only updates the gap start and all the marks that are between |
467 |
|
* the old gap start and the new gap start. They all are squeezed to the start |
468 |
|
* of the gap, because their location has been removed. |
469 |
|
* |
470 |
|
* @param newGapStart the new gap start |
471 |
|
*/ |
472 |
|
protected void shiftGapStartDown(int newGapStart) |
473 |
|
{ |
474 |
|
if (newGapStart == gapStart) |
475 |
|
return; |
476 |
|
|
477 |
|
assert newGapStart < gapStart : "The new gap start must be less than the " |
478 |
|
+ "old gap start."; |
479 |
|
Vector v = getPositionsInRange(null, newGapStart, gapStart - newGapStart); |
480 |
|
for (Iterator i = v.iterator(); i.hasNext();) |
481 |
|
{ |
482 |
|
GapContentPosition p = (GapContentPosition) i.next(); |
483 |
|
p.mark = gapStart; |
484 |
|
} |
485 |
|
gapStart = newGapStart; |
486 |
|
} |
487 |
|
|
488 |
|
/** |
489 |
|
* Shifts the gap end upwards. This does not affect the content of the |
490 |
|
* buffer. This only updates the gap end and all the marks that are between |
491 |
|
* the old gap end and the new end start. They all are squeezed to the end |
492 |
|
* of the gap, because their location has been removed. |
493 |
|
* |
494 |
|
* @param newGapEnd the new gap start |
495 |
|
*/ |
496 |
|
protected void shiftGapEndUp(int newGapEnd) |
497 |
|
{ |
498 |
|
if (newGapEnd == gapEnd) |
499 |
|
return; |
500 |
|
|
501 |
|
assert newGapEnd > gapEnd : "The new gap end must be greater than the " |
502 |
|
+ "old gap end."; |
503 |
|
Vector v = getPositionsInRange(null, gapEnd, newGapEnd - gapEnd); |
504 |
|
for (Iterator i = v.iterator(); i.hasNext();) |
505 |
|
{ |
506 |
|
GapContentPosition p = (GapContentPosition) i.next(); |
507 |
|
p.mark = newGapEnd + 1; |
508 |
|
} |
509 |
|
gapEnd = newGapEnd; |
510 |
|
} |
511 |
|
|
512 |
|
/** |
513 |
* Returns the allocated buffer array. |
* Returns the allocated buffer array. |
514 |
* |
* |
515 |
* @return the allocated buffer array |
* @return the allocated buffer array |
532 |
{ |
{ |
533 |
// Remove content |
// Remove content |
534 |
shiftGap(position); |
shiftGap(position); |
535 |
gapEnd += rmSize; |
shiftGapEndUp(gapEnd + rmSize); |
536 |
|
|
537 |
// If gap is too small, enlarge the gap. |
// If gap is too small, enlarge the gap. |
538 |
if ((gapEnd - gapStart) < addSize) |
if ((gapEnd - gapStart) <= addSize) |
539 |
shiftEnd(addSize); |
shiftEnd((addSize - gapEnd + gapStart + 1) * 2 + gapEnd + DEFAULT_BUFSIZE); |
540 |
|
|
541 |
// Add new items to the buffer. |
// Add new items to the buffer. |
542 |
if (addItems != null) |
if (addItems != null) |
545 |
gapStart += addSize; |
gapStart += addSize; |
546 |
} |
} |
547 |
} |
} |
548 |
|
|
549 |
|
/** |
550 |
|
* Returns the start index of the gap within the buffer array. |
551 |
|
* |
552 |
|
* @return the start index of the gap within the buffer array |
553 |
|
*/ |
554 |
|
protected final int getGapStart() |
555 |
|
{ |
556 |
|
return gapStart; |
557 |
|
} |
558 |
|
|
559 |
|
/** |
560 |
|
* Returns the end index of the gap within the buffer array. |
561 |
|
* |
562 |
|
* @return the end index of the gap within the buffer array |
563 |
|
*/ |
564 |
|
protected final int getGapEnd() |
565 |
|
{ |
566 |
|
return gapEnd; |
567 |
|
} |
568 |
|
|
569 |
|
/** |
570 |
|
* Returns all <code>Position</code>s that are in the range specified by |
571 |
|
* <code>offset</code> and </code>length</code> within the buffer array. |
572 |
|
* |
573 |
|
* @param v the vector to use; if <code>null</code>, a new Vector is allocated |
574 |
|
* @param offset the start offset of the range to search |
575 |
|
* @param length the length of the range to search |
576 |
|
* |
577 |
|
* @return the positions within the specified range |
578 |
|
*/ |
579 |
|
protected Vector getPositionsInRange(Vector v, int offset, int length) |
580 |
|
{ |
581 |
|
Vector res = v; |
582 |
|
if (res == null) |
583 |
|
res = new Vector(); |
584 |
|
else |
585 |
|
res.clear(); |
586 |
|
|
587 |
|
int endOffset = offset + length; |
588 |
|
|
589 |
|
int index1 = Collections.binarySearch(positions, |
590 |
|
new GapContentPosition(offset)); |
591 |
|
int index2 = Collections.binarySearch(positions, |
592 |
|
new GapContentPosition(endOffset)); |
593 |
|
if (index1 < 0) |
594 |
|
index1 = -(index1 + 1); |
595 |
|
if (index2 < 0) |
596 |
|
index2 = -(index2 + 1); |
597 |
|
for (ListIterator i = positions.listIterator(index1); i.hasNext();) |
598 |
|
{ |
599 |
|
if (i.nextIndex() > index2) |
600 |
|
break; |
601 |
|
|
602 |
|
GapContentPosition p = (GapContentPosition) i.next(); |
603 |
|
if (p.mark >= offset && p.mark <= endOffset) |
604 |
|
res.add(p); |
605 |
|
} |
606 |
|
return res; |
607 |
|
} |
608 |
} |
} |