380
* Modifies the element structure so that the specified interval starts
381
* and ends at an element boundary. Content and paragraph elements
382
* are split and created as necessary.
384
* This also updates the <code>DefaultDocumentEvent</code> to reflect the
385
* structural changes.
387
* The bulk work is delegated to {@link #changeUpdate()}.
389
* @param offset the start index of the interval to be changed
390
* @param length the length of the interval to be changed
391
* @param ev the <code>DefaultDocumentEvent</code> describing the change
486
* Removes the content. This method sets some internal parameters and
487
* delegates the work to {@link #removeUpdate}.
490
* the offset from which content is remove
492
* the length of the removed content
494
* the document event that records the changes
393
public void change(int offset, int length, DefaultDocumentEvent ev)
496
public void remove(int offs, int len, DefaultDocumentEvent ev)
395
this.offset = offset;
396
this.length = length;
397
503
documentEvent = ev;
402
* Performs the actual work for {@link #change}.
403
* The elements at the interval boundaries are split up (if necessary)
404
* so that the interval boundaries are located at element boundaries.
508
* Updates the element structure of the document in response to removal of
509
* content. It removes the affected {@link Element}s from the document
512
protected void removeUpdate()
514
int startParagraph = root.getElementIndex(offset);
515
int endParagraph = root.getElementIndex(offset + length);
516
Element[] empty = new Element[0];
517
int removeStart = -1;
519
for (int i = startParagraph; i < endParagraph; i++)
521
BranchElement paragraph = (BranchElement) root.getElement(i);
522
int contentStart = paragraph.getElementIndex(offset);
523
int contentEnd = paragraph.getElementIndex(offset + length);
524
if (contentStart == paragraph.getStartOffset()
525
&& contentEnd == paragraph.getEndOffset())
527
// In this case we only need to remove the whole paragraph. We
528
// do this in one go after this loop and only record the indices
530
if (removeStart == -1)
540
// In this case we remove a couple of child elements from this
542
int removeLen = contentEnd - contentStart;
543
Element[] removed = new Element[removeLen];
544
for (int j = contentStart; j < contentEnd; j++)
545
removed[j] = paragraph.getElement(j);
546
Edit edit = getEditForParagraphAndIndex(paragraph, contentStart);
547
edit.addRemovedElements(removed);
550
// Now we remove paragraphs from the root that have been tagged for
552
if (removeStart != -1)
554
int removeLen = removeEnd - removeStart;
555
Element[] removed = new Element[removeLen];
556
for (int i = removeStart; i < removeEnd; i++)
557
removed[i] = root.getElement(i);
558
Edit edit = getEditForParagraphAndIndex((BranchElement) root,
560
edit.addRemovedElements(removed);
565
* Performs the actual work for {@link #change}. The elements at the
566
* interval boundaries are split up (if necessary) so that the interval
567
* boundaries are located at element boundaries.
406
569
protected void changeUpdate()
408
571
// Split up the element at the start offset if necessary.
409
572
Element el = getCharacterElement(offset);
573
Element[] res = split(el, offset, 0, el.getElementIndex(offset));
574
BranchElement par = (BranchElement) el.getParentElement();
575
int index = par.getElementIndex(offset);
576
Edit edit = getEditForParagraphAndIndex(par, index);
583
removed = new Element[0];
584
added = new Element[] { res[1] };
589
removed = new Element[] { el };
590
added = new Element[] { res[0], res[1] };
592
edit.addRemovedElements(removed);
594
edit.addAddedElements(added);
412
597
int endOffset = offset + length;
413
598
el = getCharacterElement(endOffset);
414
split(el, endOffset);
418
* Splits an element if <code>offset</code> is not alread at its boundary.
420
* @param el the Element to possibly split
421
* @param offset the offset at which to possibly split
423
void split(Element el, int offset)
425
if (el instanceof AbstractElement)
427
AbstractElement ael = (AbstractElement) el;
428
int startOffset = ael.getStartOffset();
429
int endOffset = ael.getEndOffset();
430
int len = endOffset - startOffset;
431
if (startOffset != offset && endOffset != offset)
433
Element paragraph = ael.getParentElement();
434
if (paragraph instanceof BranchElement)
436
BranchElement par = (BranchElement) paragraph;
437
Element child1 = createLeafElement(par, ael, startOffset,
439
Element child2 = createLeafElement(par, ael, offset,
441
int index = par.getElementIndex(startOffset);
442
Element[] add = new Element[]{ child1, child2 };
443
par.replace(index, 1, add);
444
documentEvent.addEdit(new ElementEdit(par, index,
449
throw new AssertionError("paragraph elements are expected to "
451
+ "javax.swing.text.AbstractDocument.BranchElement");
455
throw new AssertionError("content elements are expected to be "
457
+ "javax.swing.text.AbstractDocument.AbstractElement");
599
res = split(el, endOffset, 0, el.getElementIndex(endOffset));
600
par = (BranchElement) el.getParentElement();
607
removed = new Element[0];
608
added = new Element[] { res[1] };
612
removed = new Element[] { el };
613
added = new Element[] { res[0], res[1] };
615
edit.addRemovedElements(removed);
616
edit.addAddedElements(added);
621
* Modifies the element structure so that the specified interval starts and
622
* ends at an element boundary. Content and paragraph elements are split and
623
* created as necessary. This also updates the
624
* <code>DefaultDocumentEvent</code> to reflect the structural changes.
625
* The bulk work is delegated to {@link #changeUpdate()}.
628
* the start index of the interval to be changed
630
* the length of the interval to be changed
632
* the <code>DefaultDocumentEvent</code> describing the change
634
public void change(int offset, int length, DefaultDocumentEvent ev)
638
this.offset = offset;
640
this.length = length;
646
* Creates and returns a deep clone of the specified <code>clonee</code>
647
* with the specified parent as new parent.
649
* This method can only clone direct instances of {@link BranchElement}
650
* or {@link LeafElement}.
652
* @param parent the new parent
653
* @param clonee the element to be cloned
655
* @return the cloned element with the new parent
657
public Element clone(Element parent, Element clonee)
659
Element clone = clonee;
660
// We can only handle AbstractElements here.
661
if (clonee instanceof BranchElement)
663
BranchElement branchEl = (BranchElement) clonee;
664
BranchElement branchClone =
665
new BranchElement(parent, branchEl.getAttributes());
666
// Also clone all of the children.
667
int numChildren = branchClone.getElementCount();
668
Element[] cloneChildren = new Element[numChildren];
669
for (int i = 0; i < numChildren; ++i)
671
cloneChildren[i] = clone(branchClone,
672
branchClone.getElement(i));
674
branchClone.replace(0, 0, cloneChildren);
677
else if (clonee instanceof LeafElement)
679
clone = new LeafElement(parent, clonee.getAttributes(),
680
clonee.getStartOffset(),
681
clonee.getEndOffset());
461
687
* Inserts new <code>Element</code> in the document at the specified
464
* Most of the work is done by {@link #insertUpdate}, after some fields
465
* have been prepared for it.
467
* @param offset the location in the document at which the content is
469
* @param length the length of the inserted content
470
* @param data the element specifications for the content to be inserted
471
* @param ev the document event that is updated to reflect the structural
688
* position. Most of the work is done by {@link #insertUpdate}, after some
689
* fields have been prepared for it.
692
* the location in the document at which the content is inserted
694
* the length of the inserted content
696
* the element specifications for the content to be inserted
698
* the document event that is updated to reflect the structural
474
701
public void insert(int offset, int length, ElementSpec[] data,
475
702
DefaultDocumentEvent ev)
477
707
this.offset = offset;
709
this.endOffset = offset + length;
478
710
this.length = length;
479
711
documentEvent = ev;
713
edits.removeAllElements();
714
elementStack.removeAllElements();
715
lastFractured = null;
716
fracNotCreated = false;
480
717
insertUpdate(data);
718
// This for loop applies all the changes that were made and updates the
720
int size = edits.size();
721
for (int i = 0; i < size; i++)
723
Edit curr = (Edit) edits.get(i);
724
BranchElement e = (BranchElement) curr.e;
725
Element[] removed = curr.getRemovedElements();
726
Element[] added = curr.getAddedElements();
727
// FIXME: We probably shouldn't create the empty Element[] in the
729
if (removed.length > 0 || added.length > 0)
731
if (curr.index + removed.length <= e.getElementCount())
733
e.replace(curr.index, removed.length, added);
734
ElementEdit ee = new ElementEdit(e, curr.index, removed, added);
739
System.err.println("WARNING: Tried to replace elements ");
740
System.err.print("beyond boundaries: elementCount: ");
741
System.err.println(e.getElementCount());
742
System.err.print("index: " + curr.index);
743
System.err.println(", removed.length: " + removed.length);
484
* Performs the actual structural change for {@link #insert}. This
485
* creates a bunch of {@link Element}s as specified by <code>data</code>
486
* and inserts it into the document as specified in the arguments to
489
* @param data the element specifications for the elements to be inserte
750
* Inserts new content
753
* the element specifications for the elements to be inserted
491
755
protected void insertUpdate(ElementSpec[] data)
493
for (int i = 0; i < data.length; i++)
757
// Push the root and the paragraph at offset onto the element stack.
758
Element current = root;
760
while (!current.isLeaf())
762
index = current.getElementIndex(offset);
763
elementStack.push(current);
764
current = current.getElement(index);
768
int type = data[0].getType();
769
if (type == ElementSpec.ContentType)
771
// If the first tag is content we must treat it separately to allow
772
// for joining properly to previous Elements and to ensure that
773
// no extra LeafElements are erroneously inserted.
774
insertFirstContentTag(data);
775
pos += data[0].length;
780
createFracture(data);
784
// Handle each ElementSpec individually.
785
for (; i < data.length; i++)
787
BranchElement paragraph = (BranchElement) elementStack.peek();
495
788
switch (data[i].getType())
497
790
case ElementSpec.StartTagType:
498
insertStartTag(data[i]);
791
switch (data[i].getDirection())
793
case ElementSpec.JoinFractureDirection:
794
// Fracture the tree and ensure the appropriate element
795
// is on top of the stack.
796
fracNotCreated = false;
797
insertFracture(data[i]);
800
if (lastFractured != null)
801
elementStack.push(lastFractured.getParentElement());
803
elementStack.push(paragraph.getElement(0));
806
case ElementSpec.JoinNextDirection:
807
// Push the next paragraph element onto the stack so
808
// future insertions are added to it.
809
int ix = paragraph.getElementIndex(pos) + 1;
810
elementStack.push(paragraph.getElement(ix));
814
if (data.length > i + 1)
816
// leaves will be added to paragraph later
818
if (paragraph.getElementCount() > 0)
819
x = paragraph.getElementIndex(pos) + 1;
820
Edit e = getEditForParagraphAndIndex(paragraph, x);
821
br = (BranchElement) createBranchElement(paragraph,
822
data[i].getAttributes());
824
elementStack.push(br);
827
// need to add leaves to paragraph now
828
br = insertParagraph(paragraph, pos);
500
832
case ElementSpec.EndTagType:
501
insertEndTag(data[i]);
835
case ElementSpec.ContentType:
504
836
insertContentTag(data[i]);
511
* Insert a new paragraph after the paragraph at the current position.
513
* @param tag the element spec that describes the element to be inserted
844
* Inserts a new paragraph.
850
* @return the new paragraph
515
void insertStartTag(ElementSpec tag)
852
private Element insertParagraph(BranchElement par, int offset)
517
BranchElement root = (BranchElement) getDefaultRootElement();
518
int index = root.getElementIndex(offset);
522
BranchElement newParagraph =
523
(BranchElement) createBranchElement(root, tag.getAttributes());
524
newParagraph.setResolveParent(getStyle(StyleContext.DEFAULT_STYLE));
526
// Add new paragraph into document structure.
527
Element[] added = new Element[]{newParagraph};
528
root.replace(index + 1, 0, added);
529
ElementEdit edit = new ElementEdit(root, index + 1, new Element[0],
531
documentEvent.addEdit(edit);
533
// Maybe add fractured elements.
534
if (tag.getDirection() == ElementSpec.JoinFractureDirection)
536
Element[] newFracture = new Element[fracture.length];
537
for (int i = 0; i < fracture.length; i++)
539
Element oldLeaf = fracture[i];
540
Element newLeaf = createLeafElement(newParagraph,
541
oldLeaf.getAttributes(),
542
oldLeaf.getStartOffset(),
543
oldLeaf.getEndOffset());
544
newFracture[i] = newLeaf;
546
newParagraph.replace(0, 0, newFracture);
547
edit = new ElementEdit(newParagraph, 0, new Element[0],
549
documentEvent.addEdit(edit);
550
fracture = new Element[0];
854
int index = par.getElementIndex(offset);
855
Element current = par.getElement(index);
856
Element[] res = split(current, offset, 0, 0);
857
Edit e = getEditForParagraphAndIndex(par, index + 1);
865
removed = new Element[0];
866
if (res[1] instanceof BranchElement)
868
added = new Element[] { res[1] };
873
ret = createBranchElement(par, null);
874
added = new Element[] { ret, res[1] };
880
removed = new Element[] { current };
881
if (res[1] instanceof BranchElement)
884
added = new Element[] { res[0], res[1] };
888
ret = createBranchElement(par, null);
889
added = new Element[] { res[0], ret, res[1] };
893
e.addAddedElements(added);
894
e.addRemovedElements(removed);
898
ret = createBranchElement(par, null);
899
e.addAddedElement(ret);
555
* Inserts an end tag into the document structure. This cuts of the
556
* current paragraph element, possibly fracturing it's child elements.
557
* The fractured elements are saved so that they can be joined later
558
* with a new paragraph element.
905
* Inserts the first tag into the document.
908
* the data to be inserted.
560
void insertEndTag(ElementSpec tag)
910
private void insertFirstContentTag(ElementSpec[] data)
562
BranchElement root = (BranchElement) getDefaultRootElement();
563
int parIndex = root.getElementIndex(offset);
564
BranchElement paragraph = (BranchElement) root.getElement(parIndex);
566
int index = paragraph.getElementIndex(offset);
567
LeafElement content = (LeafElement) paragraph.getElement(index);
568
// We might have to split the element at offset.
569
split(content, offset);
570
index = paragraph.getElementIndex(offset);
572
int count = paragraph.getElementCount();
573
// Store fractured elements.
574
fracture = new Element[count - index];
575
for (int i = index; i < count; ++i)
576
fracture[i - index] = paragraph.getElement(i);
578
// Delete fractured elements.
579
paragraph.replace(index, count - index, new Element[0]);
581
// Add this action to the document event.
582
ElementEdit edit = new ElementEdit(paragraph, index, fracture,
584
documentEvent.addEdit(edit);
912
ElementSpec first = data[0];
913
BranchElement paragraph = (BranchElement) elementStack.peek();
914
int index = paragraph.getElementIndex(pos);
915
Element current = paragraph.getElement(index);
916
int newEndOffset = pos + first.length;
917
boolean onlyContent = data.length == 1;
918
Edit edit = getEditForParagraphAndIndex(paragraph, index);
919
switch (first.getDirection())
921
case ElementSpec.JoinPreviousDirection:
922
if (current.getEndOffset() != newEndOffset && !onlyContent)
924
Element newEl1 = createLeafElement(paragraph,
925
current.getAttributes(),
926
current.getStartOffset(),
928
edit.addAddedElement(newEl1);
929
edit.addRemovedElement(current);
930
offset = newEndOffset;
933
case ElementSpec.JoinNextDirection:
936
Element newEl1 = createLeafElement(paragraph,
937
current.getAttributes(),
938
current.getStartOffset(),
940
edit.addAddedElement(newEl1);
941
Element next = paragraph.getElement(index + 1);
944
newEl1 = createLeafElement(paragraph, next.getAttributes(),
945
pos, next.getEndOffset());
948
newEl1 = createLeafElement(paragraph, next.getAttributes(),
952
edit.addAddedElement(newEl1);
953
edit.addRemovedElement(current);
954
edit.addRemovedElement(next);
958
if (current.getStartOffset() != pos)
960
Element newEl = createLeafElement(paragraph,
961
current.getAttributes(),
962
current.getStartOffset(),
964
edit.addAddedElement(newEl);
966
edit.addRemovedElement(current);
967
Element newEl1 = createLeafElement(paragraph, first.getAttributes(),
969
edit.addAddedElement(newEl1);
970
if (current.getEndOffset() != endOffset)
971
recreateLeaves(newEndOffset, paragraph, onlyContent);
973
offset = newEndOffset;
588
979
* Inserts a content element into the document structure.
590
* @param tag the element spec
592
void insertContentTag(ElementSpec tag)
984
private void insertContentTag(ElementSpec tag)
986
BranchElement paragraph = (BranchElement) elementStack.peek();
594
987
int len = tag.getLength();
595
988
int dir = tag.getDirection();
596
if (dir == ElementSpec.JoinPreviousDirection)
598
Element prev = getCharacterElement(offset);
599
BranchElement prevParent = (BranchElement) prev.getParentElement();
600
Element join = createLeafElement(prevParent, tag.getAttributes(),
601
prev.getStartOffset(),
602
Math.max(prev.getEndOffset(),
604
int ind = prevParent.getElementIndex(offset);
607
Element[] add = new Element[]{join};
608
prevParent.replace(ind, 1, add);
610
// Add this action to the document event.
611
ElementEdit edit = new ElementEdit(prevParent, ind,
612
new Element[]{prev}, add);
613
documentEvent.addEdit(edit);
615
else if (dir == ElementSpec.JoinNextDirection)
617
Element next = getCharacterElement(offset + len);
618
BranchElement nextParent = (BranchElement) next.getParentElement();
619
Element join = createLeafElement(nextParent, tag.getAttributes(),
621
next.getEndOffset());
622
int ind = nextParent.getElementIndex(offset + len);
625
Element[] add = new Element[]{join};
626
nextParent.replace(ind, 1, add);
628
// Add this action to the document event.
629
ElementEdit edit = new ElementEdit(nextParent, ind,
630
new Element[]{next}, add);
631
documentEvent.addEdit(edit);
635
BranchElement par = (BranchElement) getParagraphElement(offset);
637
int ind = par.getElementIndex(offset);
639
// Make room for the element.
640
// Cut previous element.
641
Element prev = par.getElement(ind);
642
if (prev != null && prev.getStartOffset() < offset)
644
Element cutPrev = createLeafElement(par, prev.getAttributes(),
645
prev.getStartOffset(),
647
Element[] remove = new Element[]{prev};
648
Element[] add = new Element[]{cutPrev};
649
if (prev.getEndOffset() > offset + len)
651
Element rem = createLeafElement(par, prev.getAttributes(),
653
prev.getEndOffset());
654
add = new Element[]{cutPrev, rem};
657
par.replace(ind, 1, add);
658
documentEvent.addEdit(new ElementEdit(par, ind, remove, add));
661
// ind now points to the next element.
663
// Cut next element if necessary.
664
Element next = par.getElement(ind);
665
if (next != null && next.getStartOffset() < offset + len)
667
Element cutNext = createLeafElement(par, next.getAttributes(),
669
next.getEndOffset());
670
Element[] remove = new Element[]{next};
671
Element[] add = new Element[]{cutNext};
672
par.replace(ind, 1, add);
673
documentEvent.addEdit(new ElementEdit(par, ind, remove,
677
// Insert new element.
678
Element newEl = createLeafElement(par, tag.getAttributes(),
679
offset, offset + len);
680
Element[] added = new Element[]{newEl};
681
par.replace(ind, 0, added);
682
// Add this action to the document event.
683
ElementEdit edit = new ElementEdit(par, ind, new Element[0],
685
documentEvent.addEdit(edit);
692
* An element type for sections. This is a simple BranchElement with
989
AttributeSet tagAtts = tag.getAttributes();
991
if (dir == ElementSpec.JoinNextDirection)
993
int index = paragraph.getElementIndex(pos);
994
Element target = paragraph.getElement(index);
995
Edit edit = getEditForParagraphAndIndex(paragraph, index);
997
if (paragraph.getStartOffset() > pos)
999
Element first = paragraph.getElement(0);
1000
Element newEl = createLeafElement(paragraph,
1001
first.getAttributes(), pos,
1002
first.getEndOffset());
1003
edit.addAddedElement(newEl);
1004
edit.addRemovedElement(first);
1006
else if (paragraph.getElementCount() > (index + 1)
1007
&& (pos == target.getStartOffset() && !target.equals(lastFractured)))
1009
Element next = paragraph.getElement(index + 1);
1010
Element newEl = createLeafElement(paragraph,
1011
next.getAttributes(), pos,
1012
next.getEndOffset());
1013
edit.addAddedElement(newEl);
1014
edit.addRemovedElement(next);
1015
edit.addRemovedElement(target);
1019
BranchElement parent = (BranchElement) paragraph.getParentElement();
1020
int i = parent.getElementIndex(pos);
1021
BranchElement next = (BranchElement) parent.getElement(i + 1);
1022
AttributeSet atts = tag.getAttributes();
1026
Element nextLeaf = next.getElement(0);
1027
Edit e = getEditForParagraphAndIndex(next, 0);
1028
Element newEl2 = createLeafElement(next, atts, pos, nextLeaf.getEndOffset());
1029
e.addAddedElement(newEl2);
1030
e.addRemovedElement(nextLeaf);
1036
int end = pos + len;
1037
Element leaf = createLeafElement(paragraph, tag.getAttributes(), pos, end);
1039
// Check for overlap with other leaves/branches
1040
if (paragraph.getElementCount() > 0)
1042
int index = paragraph.getElementIndex(pos);
1043
Element target = paragraph.getElement(index);
1044
boolean onlyContent = target.isLeaf();
1046
BranchElement toRec = paragraph;
1048
toRec = (BranchElement) target;
1050
// Check if we should place the leaf before or after target
1051
if (pos > target.getStartOffset())
1054
Edit edit = getEditForParagraphAndIndex(paragraph, index);
1055
edit.addAddedElement(leaf);
1057
if (end != toRec.getEndOffset())
1059
recreateLeaves(end, toRec, onlyContent);
1062
edit.addRemovedElement(target);
1066
paragraph.replace(0, 0, new Element[] { leaf });
1073
* This method fractures the child at offset.
1076
* the ElementSpecs used for the entire insertion
1078
private void createFracture(ElementSpec[] data)
1080
BranchElement paragraph = (BranchElement) elementStack.peek();
1081
int index = paragraph.getElementIndex(offset);
1082
Element child = paragraph.getElement(index);
1083
Edit edit = getEditForParagraphAndIndex(paragraph, index);
1084
AttributeSet atts = child.getAttributes();
1088
Element newEl1 = createLeafElement(paragraph, atts,
1089
child.getStartOffset(), offset);
1090
edit.addAddedElement(newEl1);
1091
edit.addRemovedElement(child);
1096
* Recreates a specified part of a the tree after a new leaf
1097
* has been inserted.
1099
* @param start - where to start recreating from
1100
* @param paragraph - the paragraph to recreate
1101
* @param onlyContent - true if this is the only content
1103
private void recreateLeaves(int start, BranchElement paragraph, boolean onlyContent)
1105
int index = paragraph.getElementIndex(start);
1106
Element child = paragraph.getElement(index);
1107
AttributeSet atts = child.getAttributes();
1111
BranchElement newBranch = (BranchElement) createBranchElement(paragraph,
1113
Element newLeaf = createLeafElement(newBranch, atts, start,
1114
child.getEndOffset());
1115
newBranch.replace(0, 0, new Element[] { newLeaf });
1117
BranchElement parent = (BranchElement) paragraph.getParentElement();
1118
int parSize = parent.getElementCount();
1119
Edit edit = getEditForParagraphAndIndex(parent, parSize);
1120
edit.addAddedElement(newBranch);
1122
int paragraphSize = paragraph.getElementCount();
1123
Element[] removed = new Element[paragraphSize - (index + 1)];
1125
for (int j = index + 1; j < paragraphSize; j++)
1126
removed[s++] = paragraph.getElement(j);
1128
edit = getEditForParagraphAndIndex(paragraph, index);
1129
edit.addRemovedElements(removed);
1130
Element[] added = recreateAfterFracture(removed, newBranch, 0, child.getEndOffset());
1131
newBranch.replace(1, 0, added);
1133
lastFractured = newLeaf;
1134
pos = newBranch.getEndOffset();
1138
Element newLeaf = createLeafElement(paragraph, atts, start,
1139
child.getEndOffset());
1140
Edit edit = getEditForParagraphAndIndex(paragraph, index);
1141
edit.addAddedElement(newLeaf);
1146
* Splits an element if <code>offset</code> is not already at its
1150
* the Element to possibly split
1152
* the offset at which to possibly split
1154
* the amount of space to create between the splitted parts
1156
* the index of the edit to use
1157
* @return An array of elements which represent the split result. This array
1158
* has two elements, the two parts of the split. The first element
1159
* might be null, which means that the element which should be
1160
* splitted can remain in place. The second element might also be
1161
* null, which means that the offset is already at an element
1162
* boundary and the element doesn't need to be splitted.
1164
private Element[] split(Element el, int offset, int space, int editIndex)
1166
// If we are at an element boundary, then return an empty array.
1167
if ((offset == el.getStartOffset() || offset == el.getEndOffset())
1168
&& space == 0 && el.isLeaf())
1169
return new Element[2];
1171
// If the element is an instance of BranchElement, then we
1173
// call this method to perform the split.
1174
Element[] res = new Element[2];
1175
if (el instanceof BranchElement)
1177
int index = el.getElementIndex(offset);
1178
Element child = el.getElement(index);
1179
Element[] result = split(child, offset, space, editIndex);
1184
int count = el.getElementCount();
1185
if (result[1] != null)
1187
// This is the case when we can keep the first element.
1188
if (result[0] == null)
1190
removed = new Element[count - index - 1];
1191
newAdded = new Element[count - index - 1];
1192
added = new Element[] {};
1195
// This is the case when we may not keep the first
1199
removed = new Element[count - index];
1200
newAdded = new Element[count - index];
1201
added = new Element[] { result[0] };
1203
newAdded[0] = result[1];
1204
for (int i = index; i < count; i++)
1206
Element el2 = el.getElement(i);
1207
int ind = i - count + removed.length;
1210
newAdded[ind] = el2;
1213
Edit edit = getEditForParagraphAndIndex((BranchElement) el, editIndex);
1214
edit.addRemovedElements(removed);
1215
edit.addAddedElements(added);
1217
BranchElement newPar =
1218
(BranchElement) createBranchElement(el.getParentElement(),
1219
el.getAttributes());
1220
newPar.replace(0, 0, newAdded);
1221
res = new Element[] { null, newPar };
1225
removed = new Element[count - index];
1226
for (int i = index; i < count; ++i)
1227
removed[i - index] = el.getElement(i);
1229
Edit edit = getEditForParagraphAndIndex((BranchElement) el, editIndex);
1230
edit.addRemovedElements(removed);
1232
BranchElement newPar = (BranchElement) createBranchElement(el.getParentElement(),
1233
el.getAttributes());
1234
newPar.replace(0, 0, removed);
1235
res = new Element[] { null, newPar };
1238
else if (el instanceof LeafElement)
1240
BranchElement par = (BranchElement) el.getParentElement();
1241
Element el1 = createLeafElement(par, el.getAttributes(),
1242
el.getStartOffset(), offset);
1244
Element el2 = createLeafElement(par, el.getAttributes(),
1247
res = new Element[] { el1, el2 };
1253
* Inserts a fracture into the document structure.
1258
private void insertFracture(ElementSpec tag)
1260
// insert the fracture at offset.
1261
BranchElement parent = (BranchElement) elementStack.peek();
1262
int parentIndex = parent.getElementIndex(pos);
1263
AttributeSet parentAtts = parent.getAttributes();
1264
Element toFracture = parent.getElement(parentIndex);
1265
int parSize = parent.getElementCount();
1266
Edit edit = getEditForParagraphAndIndex(parent, parentIndex);
1267
Element frac = toFracture;
1269
int indexOfFrac = toFracture.getElementIndex(pos);
1270
int size = toFracture.getElementCount();
1272
// gets the leaf that falls along the fracture
1273
frac = toFracture.getElement(indexOfFrac);
1274
while (!frac.isLeaf())
1275
frac = frac.getElement(frac.getElementIndex(pos));
1277
AttributeSet atts = frac.getAttributes();
1278
int fracStart = frac.getStartOffset();
1279
int fracEnd = frac.getEndOffset();
1280
if (pos >= fracStart && pos < fracEnd)
1282
// recreate left-side of branch and all its children before offset
1283
// add the fractured leaves to the right branch
1284
BranchElement rightBranch =
1285
(BranchElement) createBranchElement(parent, parentAtts);
1287
// Check if left branch has already been edited. If so, we only
1288
// need to create the right branch.
1289
BranchElement leftBranch = null;
1290
Element[] added = null;
1291
if (edit.added.size() > 0 || edit.removed.size() > 0)
1293
added = new Element[] { rightBranch };
1295
// don't try to remove left part of tree
1301
(BranchElement) createBranchElement(parent, parentAtts);
1302
added = new Element[] { leftBranch, rightBranch };
1304
// add fracture to leftBranch
1305
if (fracStart != pos)
1307
Element leftFracturedLeaf =
1308
createLeafElement(leftBranch, atts, fracStart, pos);
1309
leftBranch.replace(leftIns, 0,
1310
new Element[] { leftFracturedLeaf });
1314
if (!toFracture.isLeaf())
1316
// add all non-fracture elements to the branches
1317
if (indexOfFrac > 0 && leftBranch != null)
1319
Element[] add = new Element[indexOfFrac];
1320
for (int i = 0; i < indexOfFrac; i++)
1321
add[i] = toFracture.getElement(i);
1322
leftIns = add.length;
1323
leftBranch.replace(0, 0, add);
1326
int count = size - indexOfFrac - 1;
1329
Element[] add = new Element[count];
1331
int i = indexOfFrac + 1;
1333
add[j++] = toFracture.getElement(i++);
1334
rightBranch.replace(0, 0, add);
1338
// add to fracture to rightBranch
1339
// Check if we can join the right frac leaf with the next leaf
1342
Element next = rightBranch.getElement(0);
1343
if (next != null && next.isLeaf()
1344
&& next.getAttributes().isEqual(atts))
1346
end = next.getEndOffset();
1350
Element rightFracturedLeaf = createLeafElement(rightBranch, atts,
1352
rightBranch.replace(0, rm, new Element[] { rightFracturedLeaf });
1354
// recreate those elements after parentIndex and add/remove all
1355
// new/old elements to parent
1356
int remove = parSize - parentIndex;
1357
Element[] removed = new Element[0];
1358
Element[] added2 = new Element[0];
1361
removed = new Element[remove];
1363
for (int j = parentIndex; j < parSize; j++)
1364
removed[s++] = parent.getElement(j);
1365
edit.addRemovedElements(removed);
1366
added2 = recreateAfterFracture(removed, parent, 1,
1367
rightBranch.getEndOffset());
1370
edit.addAddedElements(added);
1371
edit.addAddedElements(added2);
1372
elementStack.push(rightBranch);
1373
lastFractured = rightFracturedLeaf;
1376
fracNotCreated = true;
1380
* Recreates all the elements from the parent to the element on the top of
1381
* the stack, starting from startFrom with the starting offset of
1385
* the elements to recreate
1387
* the element to add the new elements to
1388
* @param startFrom -
1389
* where to start recreating from
1390
* @param startOffset -
1391
* the offset of the first element
1392
* @return the array of added elements
1394
private Element[] recreateAfterFracture(Element[] recreate,
1395
BranchElement parent, int startFrom,
1398
Element[] added = new Element[recreate.length - startFrom];
1400
for (int i = startFrom; i < recreate.length; i++)
1402
Element curr = recreate[i];
1403
int len = curr.getEndOffset() - curr.getStartOffset();
1404
if (curr instanceof LeafElement)
1405
added[j] = createLeafElement(parent, curr.getAttributes(),
1406
startOffset, startOffset + len);
1410
(BranchElement) createBranchElement(parent,
1411
curr.getAttributes());
1412
int bSize = curr.getElementCount();
1413
for (int k = 0; k < bSize; k++)
1415
Element bCurr = curr.getElement(k);
1416
Element[] add = recreateAfterFracture(new Element[] { bCurr }, br, 0,
1418
br.replace(0, 0, add);
1432
* This method looks through the Vector of Edits to see if there is already an
1433
* Edit object associated with the given paragraph. If there is, then we
1434
* return it. Otherwise we create a new Edit object, add it to the vector, and
1435
* return it. Note: this method is package private to avoid accessors.
1438
* the index associated with the Edit we want to create
1440
* the paragraph associated with the Edit we want
1441
* @return the found or created Edit object
1443
Edit getEditForParagraphAndIndex(BranchElement para, int index)
1446
int size = edits.size();
1447
for (int i = 0; i < size; i++)
1449
curr = (Edit) edits.elementAt(i);
1450
if (curr.e.equals(para))
1453
curr = new Edit(para, index, null, null);
1459
* Instance of all editing information for an object in the Vector. This class
1460
* is used to add information to the DocumentEvent associated with an
1461
* insertion/removal/change as well as to store the changes that need to be
1462
* made so they can be made all at the same (appropriate) time.
1466
/** The element to edit . */
1469
/** The index of the change. */
1472
/** The removed elements. */
1473
Vector removed = new Vector();
1475
/** The added elements. */
1476
Vector added = new Vector();
1479
* Return an array containing the Elements that have been removed from the
1480
* paragraph associated with this Edit.
1482
* @return an array of removed Elements
1484
public Element[] getRemovedElements()
1486
int size = removed.size();
1487
Element[] removedElements = new Element[size];
1488
for (int i = 0; i < size; i++)
1489
removedElements[i] = (Element) removed.elementAt(i);
1490
return removedElements;
1494
* Return an array containing the Elements that have been added to the
1495
* paragraph associated with this Edit.
1497
* @return an array of added Elements
1499
public Element[] getAddedElements()
1501
int size = added.size();
1502
Element[] addedElements = new Element[size];
1503
for (int i = 0; i < size; i++)
1504
addedElements[i] = (Element) added.elementAt(i);
1505
return addedElements;
1509
* Checks if e is already in the vector.
1511
* @param e - the Element to look for
1512
* @param v - the vector to search
1513
* @return true if e is in v.
1515
private boolean contains(Vector v, Element e)
1521
for (int j = 0; j < i; j++)
1523
Element e1 = (Element) v.get(j);
1524
if ((e1 != null) && (e1.getAttributes().isEqual(e.getAttributes()))
1525
&& (e1.getName().equals(e.getName()))
1526
&& (e1.getStartOffset() == e.getStartOffset())
1527
&& (e1.getEndOffset() == e.getEndOffset())
1528
&& (e1.getParentElement().equals(e.getParentElement()))
1529
&& (e1.getElementCount() == e.getElementCount()))
1536
* Adds one Element to the vector of removed Elements.
1539
* the Element to add
1541
public void addRemovedElement(Element e)
1543
if (!contains(removed, e))
1548
* Adds each Element in the given array to the vector of removed Elements
1551
* the array containing the Elements to be added
1553
public void addRemovedElements(Element[] e)
1555
if (e == null || e.length == 0)
1557
for (int i = 0; i < e.length; i++)
1559
if (!contains(removed, e[i]))
1565
* Adds one Element to the vector of added Elements.
1568
* the Element to add
1570
public void addAddedElement(Element e)
1572
if (!contains(added, e))
1577
* Adds each Element in the given array to the vector of added Elements.
1580
* the array containing the Elements to be added
1582
public void addAddedElements(Element[] e)
1584
if (e == null || e.length == 0)
1586
for (int i = 0; i < e.length; i++)
1588
if (!contains(added, e[i]))
1594
* Creates a new Edit object with the given parameters
1597
* the paragraph Element associated with this Edit
1599
* the index within the paragraph where changes are started
1601
* an array containing Elements that should be removed from the
1604
* an array containing Elements that should be added to the
1607
public Edit(Element e, int i, Element[] removed, Element[] added)
1611
addRemovedElements(removed);
1612
addAddedElements(added);
1617
* An element type for sections. This is a simple BranchElement with a unique
695
1620
protected class SectionElement extends BranchElement
953
1916
* Sets text attributes for the fragment specified by <code>offset</code>
954
1917
* and <code>length</code>.
956
* @param offset the start offset of the fragment
957
* @param length the length of the fragment
958
* @param attributes the text attributes to set
959
* @param replace if <code>true</code>, the attributes of the current
960
* selection are overridden, otherwise they are merged
1920
* the start offset of the fragment
1922
* the length of the fragment
1924
* the text attributes to set
1926
* if <code>true</code>, the attributes of the current selection
1927
* are overridden, otherwise they are merged
962
1929
public void setCharacterAttributes(int offset, int length,
963
AttributeSet attributes,
1930
AttributeSet attributes, boolean replace)
966
DefaultDocumentEvent ev =
967
new DefaultDocumentEvent(offset, length,
968
DocumentEvent.EventType.CHANGE);
970
// Modify the element structure so that the interval begins at an element
971
// start and ends at an element end.
972
buffer.change(offset, length, ev);
974
Element root = getDefaultRootElement();
975
// Visit all paragraph elements within the specified interval
976
int paragraphCount = root.getElementCount();
977
for (int pindex = 0; pindex < paragraphCount; pindex++)
979
Element paragraph = root.getElement(pindex);
980
// Skip paragraphs that lie outside the interval.
981
if ((paragraph.getStartOffset() > offset + length)
982
|| (paragraph.getEndOffset() < offset))
985
// Visit content elements within this paragraph
986
int contentCount = paragraph.getElementCount();
987
for (int cindex = 0; cindex < contentCount; cindex++)
989
Element content = paragraph.getElement(cindex);
990
// Skip content that lies outside the interval.
991
if ((content.getStartOffset() > offset + length)
992
|| (content.getEndOffset() < offset))
995
if (content instanceof AbstractElement)
997
AbstractElement el = (AbstractElement) content;
999
el.removeAttributes(el);
1000
el.addAttributes(attributes);
1003
throw new AssertionError("content elements are expected to be"
1005
+ "javax.swing.text.AbstractDocument.AbstractElement");
1009
fireChangedUpdate(ev);
1932
// Exit early if length is 0, so no DocumentEvent is created or fired.
1937
// Must obtain a write lock for this method. writeLock() and
1938
// writeUnlock() should always be in try/finally block to make
1939
// sure that locking happens in a balanced manner.
1941
DefaultDocumentEvent ev = new DefaultDocumentEvent(offset,
1943
DocumentEvent.EventType.CHANGE);
1945
// Modify the element structure so that the interval begins at an
1947
// start and ends at an element end.
1948
buffer.change(offset, length, ev);
1950
Element root = getDefaultRootElement();
1951
// Visit all paragraph elements within the specified interval
1952
int end = offset + length;
1954
for (int pos = offset; pos < end;)
1956
// Get the CharacterElement at offset pos.
1957
curr = getCharacterElement(pos);
1958
if (pos == curr.getEndOffset())
1961
MutableAttributeSet a = (MutableAttributeSet) curr.getAttributes();
1962
ev.addEdit(new AttributeUndoableEdit(curr, attributes, replace));
1963
// If replace is true, remove all the old attributes.
1965
a.removeAttributes(a);
1966
// Add all the new attributes.
1967
a.addAttributes(attributes);
1968
// Increment pos so we can check the next CharacterElement.
1969
pos = curr.getEndOffset();
1971
fireChangedUpdate(ev);
1972
fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
1013
1981
* Sets the logical style for the paragraph at the specified position.
1015
* @param position the position at which the logical style is added
1016
* @param style the style to set for the current paragraph
1984
* the position at which the logical style is added
1986
* the style to set for the current paragraph
1018
1988
public void setLogicalStyle(int position, Style style)
1020
1990
Element el = getParagraphElement(position);
1021
if (el instanceof AbstractElement)
1023
AbstractElement ael = (AbstractElement) el;
1024
ael.setResolveParent(style);
1027
throw new AssertionError("paragraph elements are expected to be"
1028
+ "instances of javax.swing.text.AbstractDocument.AbstractElement");
1991
// getParagraphElement doesn't return null but subclasses might so
1992
// we check for null here.
1998
if (el instanceof AbstractElement)
2000
AbstractElement ael = (AbstractElement) el;
2001
ael.setResolveParent(style);
2002
int start = el.getStartOffset();
2003
int end = el.getEndOffset();
2004
DefaultDocumentEvent ev = new DefaultDocumentEvent(start,
2006
DocumentEvent.EventType.CHANGE);
2007
fireChangedUpdate(ev);
2008
fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
2011
throw new AssertionError(
2012
"paragraph elements are expected to be"
2013
+ "instances of AbstractDocument.AbstractElement");
1032
2022
* Sets text attributes for the paragraph at the specified fragment.
1034
* @param offset the beginning of the fragment
1035
* @param length the length of the fragment
1036
* @param attributes the text attributes to set
1037
* @param replace if <code>true</code>, the attributes of the current
1038
* selection are overridden, otherwise they are merged
2025
* the beginning of the fragment
2027
* the length of the fragment
2029
* the text attributes to set
2031
* if <code>true</code>, the attributes of the current selection
2032
* are overridden, otherwise they are merged
1040
2034
public void setParagraphAttributes(int offset, int length,
1041
AttributeSet attributes,
2035
AttributeSet attributes, boolean replace)
1045
while (index < offset + length)
1047
AbstractElement par = (AbstractElement) getParagraphElement(index);
1048
AttributeContext ctx = getAttributeContext();
1050
par.removeAttributes(par);
1051
par.addAttributes(attributes);
1052
index = par.getElementCount();
2039
// Must obtain a write lock for this method. writeLock() and
2040
// writeUnlock() should always be in try/finally blocks to make
2041
// sure that locking occurs in a balanced manner.
2044
// Create a DocumentEvent to use for changedUpdate().
2045
DefaultDocumentEvent ev = new DefaultDocumentEvent(offset,
2047
DocumentEvent.EventType.CHANGE);
2049
// Have to iterate through all the _paragraph_ elements that are
2050
// contained or partially contained in the interval
2051
// (offset, offset + length).
2052
Element rootElement = getDefaultRootElement();
2053
int startElement = rootElement.getElementIndex(offset);
2054
int endElement = rootElement.getElementIndex(offset + length - 1);
2055
if (endElement < startElement)
2056
endElement = startElement;
2058
for (int i = startElement; i <= endElement; i++)
2060
Element par = rootElement.getElement(i);
2061
MutableAttributeSet a = (MutableAttributeSet) par.getAttributes();
2062
// Add the change to the DocumentEvent.
2063
ev.addEdit(new AttributeUndoableEdit(par, attributes, replace));
2064
// If replace is true remove the old attributes.
2066
a.removeAttributes(a);
2067
// Add the new attributes.
2068
a.addAttributes(attributes);
2070
fireChangedUpdate(ev);
2071
fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
1057
* Called in response to content insert actions. This is used to
1058
* update the element structure.
1060
* @param ev the <code>DocumentEvent</code> describing the change
1061
* @param attr the attributes for the change
2080
* Called in response to content insert actions. This is used to update the
2081
* element structure.
2084
* the <code>DocumentEvent</code> describing the change
2086
* the attributes for the change
1063
2088
protected void insertUpdate(DefaultDocumentEvent ev, AttributeSet attr)
1065
2090
super.insertUpdate(ev, attr);
2091
// If the attribute set is null, use an empty attribute set.
2093
attr = SimpleAttributeSet.EMPTY;
1066
2094
int offset = ev.getOffset();
1067
2095
int length = ev.getLength();
1068
2096
int endOffset = offset + length;
2097
AttributeSet paragraphAttributes = getParagraphElement(endOffset).getAttributes();
1069
2098
Segment txt = new Segment();
1074
2103
catch (BadLocationException ex)
1076
2105
AssertionError ae = new AssertionError("Unexpected bad location");
1082
2111
Vector specs = new Vector();
2112
ElementSpec finalStartTag = null;
2113
short finalStartDirection = ElementSpec.OriginateDirection;
2114
boolean prevCharWasNewline = false;
1084
2115
Element prev = getCharacterElement(offset);
1085
2116
Element next = getCharacterElement(endOffset);
1087
for (int i = offset; i < endOffset; ++i)
2117
Element prevParagraph = getParagraphElement(offset);
2118
Element paragraph = getParagraphElement(endOffset);
2120
int segmentEnd = txt.offset + txt.count;
2122
// Check to see if we're inserting immediately after a newline.
2127
String s = getText(offset - 1, 1);
2130
finalStartDirection = handleInsertAfterNewline(specs, offset,
2134
paragraphAttributes);
2136
prevCharWasNewline = true;
2137
// Find the final start tag from the ones just created.
2138
for (int i = 0; i < specs.size(); i++)
2139
if (((ElementSpec) specs.get(i)).getType() == ElementSpec.StartTagType)
2140
finalStartTag = (ElementSpec) specs.get(i);
2143
catch (BadLocationException ble)
2145
// This shouldn't happen.
2146
AssertionError ae = new AssertionError();
2152
for (int i = txt.offset; i < segmentEnd; ++i)
1090
2155
if (txt.array[i] == '\n')
1092
ElementSpec spec = new ElementSpec(attr, ElementSpec.ContentType,
1095
// If we are at the last index, then check if we could probably be
1096
// joined with the next element.
1097
if (i == endOffset - 1)
1099
if (next.getAttributes().isEqual(attr))
1100
spec.setDirection(ElementSpec.JoinNextDirection);
1102
// If we are at the first new element, then check if it could be
1103
// joined with the previous element.
1104
else if (specs.size() == 0)
1106
if (prev.getAttributes().isEqual(attr))
1107
spec.setDirection(ElementSpec.JoinPreviousDirection);
2157
// Add the ElementSpec for the content.
2158
specs.add(new ElementSpec(attr, ElementSpec.ContentType, len));
1112
2160
// Add ElementSpecs for the newline.
1113
ElementSpec endTag = new ElementSpec(null, ElementSpec.EndTagType);
1115
ElementSpec startTag = new ElementSpec(null,
1116
ElementSpec.StartTagType);
1117
startTag.setDirection(ElementSpec.JoinFractureDirection);
1118
specs.add(startTag);
2161
specs.add(new ElementSpec(null, ElementSpec.EndTagType));
2162
finalStartTag = new ElementSpec(paragraphAttributes,
2163
ElementSpec.StartTagType);
2164
specs.add(finalStartTag);
1125
2169
// Create last element if last character hasn't been a newline.
1128
ElementSpec spec = new ElementSpec(attr, ElementSpec.ContentType, len);
1129
// If we are at the first new element, then check if it could be
1130
// joined with the previous element.
1131
if (specs.size() == 0)
1133
if (prev.getAttributes().isEqual(attr))
1134
spec.setDirection(ElementSpec.JoinPreviousDirection);
1136
// Check if we could probably be joined with the next element.
1137
else if (next.getAttributes().isEqual(attr))
1138
spec.setDirection(ElementSpec.JoinNextDirection);
1143
ElementSpec[] elSpecs =
1144
(ElementSpec[]) specs.toArray(new ElementSpec[specs.size()]);
2171
specs.add(new ElementSpec(attr, ElementSpec.ContentType, len));
2173
// Set the direction of the last spec of type StartTagType.
2174
// If we are inserting after a newline then this value comes from
2175
// handleInsertAfterNewline.
2176
if (finalStartTag != null)
2178
if (prevCharWasNewline)
2179
finalStartTag.setDirection(finalStartDirection);
2180
else if (prevParagraph.getEndOffset() != endOffset)
2181
finalStartTag.setDirection(ElementSpec.JoinFractureDirection);
2184
// If there is an element AFTER this one, then set the
2185
// direction to JoinNextDirection.
2186
Element parent = prevParagraph.getParentElement();
2187
int index = parent.getElementIndex(offset);
2188
if (index + 1 < parent.getElementCount()
2189
&& !parent.getElement(index + 1).isLeaf())
2190
finalStartTag.setDirection(ElementSpec.JoinNextDirection);
2194
// If we are at the last index, then check if we could probably be
2195
// joined with the next element.
2197
// - we must be a ContentTag
2198
// - if there is a next Element, we must have the same attributes
2199
// - if there is no next Element, but one will be created,
2200
// we must have the same attributes as the higher-level run.
2201
ElementSpec last = (ElementSpec) specs.lastElement();
2202
if (last.getType() == ElementSpec.ContentType)
2204
Element currentRun = prevParagraph.getElement(prevParagraph.getElementIndex(offset));
2205
if (currentRun.getEndOffset() == endOffset)
2207
if (endOffset < getLength() && next.getAttributes().isEqual(attr)
2208
&& last.getType() == ElementSpec.ContentType)
2209
last.setDirection(ElementSpec.JoinNextDirection);
2213
if (finalStartTag != null
2214
&& finalStartTag.getDirection() == ElementSpec.JoinFractureDirection
2215
&& currentRun.getAttributes().isEqual(attr))
2217
last.setDirection(ElementSpec.JoinNextDirection);
2222
// If we are at the first new element, then check if it could be
2223
// joined with the previous element.
2224
ElementSpec first = (ElementSpec) specs.firstElement();
2225
if (prev.getAttributes().isEqual(attr)
2226
&& first.getType() == ElementSpec.ContentType)
2227
first.setDirection(ElementSpec.JoinPreviousDirection);
2229
ElementSpec[] elSpecs = (ElementSpec[]) specs.toArray(new ElementSpec[specs.size()]);
1146
2230
buffer.insert(offset, length, elSpecs, ev);
2234
* A helper method to set up the ElementSpec buffer for the special case of an
2235
* insertion occurring immediately after a newline.
2238
* the ElementSpec buffer to initialize.
2240
short handleInsertAfterNewline(Vector specs, int offset, int endOffset,
2241
Element prevParagraph, Element paragraph,
2244
if (prevParagraph.getParentElement() == paragraph.getParentElement())
2246
specs.add(new ElementSpec(a, ElementSpec.EndTagType));
2247
specs.add(new ElementSpec(a, ElementSpec.StartTagType));
2248
if (paragraph.getStartOffset() != endOffset)
2249
return ElementSpec.JoinFractureDirection;
2250
// If there is an Element after this one, use JoinNextDirection.
2251
Element parent = paragraph.getParentElement();
2252
if (parent.getElementCount() > (parent.getElementIndex(offset) + 1))
2253
return ElementSpec.JoinNextDirection;
2255
return ElementSpec.OriginateDirection;
2259
* Updates the document structure in response to text removal. This is
2260
* forwarded to the {@link ElementBuffer} of this document. Any changes to the
2261
* document structure are added to the specified document event and sent to
2262
* registered listeners.
2265
* the document event that records the changes to the document
2267
protected void removeUpdate(DefaultDocumentEvent ev)
2269
super.removeUpdate(ev);
2270
buffer.remove(ev.getOffset(), ev.getLength(), ev);
2274
* Returns an enumeration of all style names.
2276
* @return an enumeration of all style names
2278
public Enumeration getStyleNames()
2280
StyleContext context = (StyleContext) getAttributeContext();
2281
return context.getStyleNames();
2285
* Called when any of this document's styles changes.
2288
* the style that changed
2290
protected void styleChanged(Style style)
2292
// Nothing to do here. This is intended to be overridden by subclasses.
2296
* Inserts a bulk of structured content at once.
2299
* the offset at which the content should be inserted
2301
* the actual content spec to be inserted
2303
protected void insert(int offset, ElementSpec[] data)
2304
throws BadLocationException
2306
if (data == null || data.length == 0)
2310
// writeLock() and writeUnlock() should always be in a try/finally
2311
// block so that locking balance is guaranteed even if some
2312
// exception is thrown.
2315
// First we collect the content to be inserted.
2316
StringBuffer contentBuffer = new StringBuffer();
2317
for (int i = 0; i < data.length; i++)
2319
// Collect all inserts into one so we can get the correct
2321
ElementSpec spec = data[i];
2322
if (spec.getArray() != null && spec.getLength() > 0)
2323
contentBuffer.append(spec.getArray(), spec.getOffset(),
2327
int length = contentBuffer.length();
2329
// If there was no content inserted then exit early.
2333
UndoableEdit edit = content.insertString(offset,
2334
contentBuffer.toString());
2336
// Create the DocumentEvent with the ElementEdit added
2337
DefaultDocumentEvent ev = new DefaultDocumentEvent(offset,
2339
DocumentEvent.EventType.INSERT);
2342
// Finally we must update the document structure and fire the insert
2344
buffer.insert(offset, length, data, ev);
2345
fireInsertUpdate(ev);
2346
fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
2355
* Initializes the <code>DefaultStyledDocument</code> with the specified
2359
* the specification of the content with which the document is
2362
protected void create(ElementSpec[] data)
2367
// Clear content if there is some.
2368
int len = getLength();
2372
// Now we insert the content.
2373
StringBuilder b = new StringBuilder();
2374
for (int i = 0; i < data.length; ++i)
2376
ElementSpec el = data[i];
2377
if (el.getArray() != null && el.getLength() > 0)
2378
b.append(el.getArray(), el.getOffset(), el.getLength());
2380
Content content = getContent();
2381
UndoableEdit cEdit = content.insertString(0, b.toString());
2383
DefaultDocumentEvent ev =
2384
new DefaultDocumentEvent(0, b.length(),
2385
DocumentEvent.EventType.INSERT);
2388
// We do a little trick here to get the new structure: We instantiate
2389
// a new ElementBuffer with a new root element, insert into that root
2390
// and then reparent the newly created elements to the old root
2392
BranchElement createRoot =
2393
(BranchElement) createBranchElement(null, null);
2394
Element dummyLeaf = createLeafElement(createRoot, null, 0, 1);
2395
createRoot.replace(0, 0, new Element[]{ dummyLeaf });
2396
ElementBuffer createBuffer = new ElementBuffer(createRoot);
2397
createBuffer.insert(0, b.length(), data, new DefaultDocumentEvent(0, b.length(), DocumentEvent.EventType.INSERT));
2398
// Now the new root is the first child of the createRoot.
2399
Element newRoot = createRoot.getElement(0);
2400
BranchElement root = (BranchElement) getDefaultRootElement();
2401
Element[] added = new Element[newRoot.getElementCount()];
2402
for (int i = 0; i < added.length; ++i)
2404
added[i] = newRoot.getElement(i);
2405
((AbstractElement) added[i]).element_parent = root;
2407
Element[] removed = new Element[root.getElementCount()];
2408
for (int i = 0; i < removed.length; ++i)
2409
removed[i] = root.getElement(i);
2411
// Replace the old elements in root with the new and update the event.
2412
root.replace(0, removed.length, added);
2413
ev.addEdit(new ElementEdit(root, 0, removed, added));
2415
fireInsertUpdate(ev);
2416
fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
2418
catch (BadLocationException ex)
2420
AssertionError err = new AssertionError("Unexpected bad location");