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: import ;
53: import ;
54:
55:
67: public class DefaultStyledDocument extends AbstractDocument
68: implements StyledDocument
69: {
70:
75: public static class AttributeUndoableEdit
76: extends AbstractUndoableEdit
77: {
78:
81: protected AttributeSet copy;
82:
83:
86: protected AttributeSet newAttributes;
87:
88:
92: protected boolean isReplacing;
93:
94:
97: protected Element element;
98:
99:
107: public AttributeUndoableEdit(Element el, AttributeSet newAtts,
108: boolean replacing)
109: {
110: element = el;
111: newAttributes = newAtts;
112: isReplacing = replacing;
113: copy = el.getAttributes().copyAttributes();
114: }
115:
116:
120: public void undo()
121: {
122: super.undo();
123: AttributeSet atts = element.getAttributes();
124: if (atts instanceof MutableAttributeSet)
125: {
126: MutableAttributeSet mutable = (MutableAttributeSet) atts;
127: mutable.removeAttributes(atts);
128: mutable.addAttributes(copy);
129: }
130: }
131:
132:
137: public void redo()
138: {
139: super.undo();
140: AttributeSet atts = element.getAttributes();
141: if (atts instanceof MutableAttributeSet)
142: {
143: MutableAttributeSet mutable = (MutableAttributeSet) atts;
144: if (isReplacing)
145: mutable.removeAttributes(atts);
146: mutable.addAttributes(newAttributes);
147: }
148: }
149: }
150:
151:
156: public static class ElementSpec
157: {
158:
162: public static final short StartTagType = 1;
163:
164:
168: public static final short EndTagType = 2;
169:
170:
174: public static final short ContentType = 3;
175:
176:
181: public static final short JoinPreviousDirection = 4;
182:
183:
188: public static final short JoinNextDirection = 5;
189:
190:
195: public static final short OriginateDirection = 6;
196:
197:
202: public static final short JoinFractureDirection = 7;
203:
204:
207: short type;
208:
209:
212: short direction;
213:
214:
217: int offset;
218:
219:
222: int length;
223:
224:
227: char[] content;
228:
229:
232: AttributeSet attributes;
233:
234:
241: public ElementSpec(AttributeSet a, short type)
242: {
243: this(a, type, 0);
244: }
245:
246:
255: public ElementSpec(AttributeSet a, short type, int len)
256: {
257: this(a, type, null, 0, len);
258: }
259:
260:
269: public ElementSpec(AttributeSet a, short type, char[] txt, int offs,
270: int len)
271: {
272: attributes = a;
273: this.type = type;
274: offset = offs;
275: length = len;
276: content = txt;
277: direction = OriginateDirection;
278: }
279:
280:
285: public void setType(short type)
286: {
287: this.type = type;
288: }
289:
290:
295: public short getType()
296: {
297: return type;
298: }
299:
300:
305: public void setDirection(short dir)
306: {
307: direction = dir;
308: }
309:
310:
315: public short getDirection()
316: {
317: return direction;
318: }
319:
320:
325: public AttributeSet getAttributes()
326: {
327: return attributes;
328: }
329:
330:
335: public char[] getArray()
336: {
337: return content;
338: }
339:
340:
345: public int getOffset()
346: {
347: return offset;
348: }
349:
350:
355: public int getLength()
356: {
357: return length;
358: }
359:
360:
367: public String toString()
368: {
369: StringBuilder b = new StringBuilder();
370: switch (type)
371: {
372: case StartTagType:
373: b.append("StartTag");
374: break;
375: case EndTagType:
376: b.append("EndTag");
377: break;
378: case ContentType:
379: b.append("Content");
380: break;
381: default:
382: b.append("??");
383: break;
384: }
385:
386: b.append(':');
387:
388: switch (direction)
389: {
390: case JoinPreviousDirection:
391: b.append("JoinPrevious");
392: break;
393: case JoinNextDirection:
394: b.append("JoinNext");
395: break;
396: case OriginateDirection:
397: b.append("Originate");
398: break;
399: case JoinFractureDirection:
400: b.append("Fracture");
401: break;
402: default:
403: b.append("??");
404: break;
405: }
406:
407: b.append(':');
408: b.append(length);
409:
410: return b.toString();
411: }
412: }
413:
414:
418: public class ElementBuffer implements Serializable
419: {
420:
421: private static final long serialVersionUID = 1688745877691146623L;
422:
423:
424: private Element root;
425:
426:
427: private int offset;
428:
429:
430: private int length;
431:
432:
433: private int endOffset;
434:
435:
440: private int numEndTags;
441:
442:
447: private int numStartTags;
448:
449:
453: private Stack elementStack;
454:
455:
461: Element[] fracture;
462:
463:
466: DefaultDocumentEvent documentEvent;
467:
468:
474: public ElementBuffer(Element root)
475: {
476: this.root = root;
477: elementStack = new Stack();
478: }
479:
480:
485: public Element getRootElement()
486: {
487: return root;
488: }
489:
490:
502: public void remove(int offs, int len, DefaultDocumentEvent ev)
503: {
504: offset = offs;
505: length = len;
506: documentEvent = ev;
507: removeUpdate();
508: }
509:
510:
515: protected void removeUpdate()
516: {
517: int startParagraph = root.getElementIndex(offset);
518: int endParagraph = root.getElementIndex(offset + length);
519: Element[] empty = new Element[0];
520: int removeStart = -1;
521: int removeEnd = -1;
522: for (int i = startParagraph; i < endParagraph; i++)
523: {
524: Element paragraph = root.getElement(i);
525: int contentStart = paragraph.getElementIndex(offset);
526: int contentEnd = paragraph.getElementIndex(offset + length);
527: if (contentStart == paragraph.getStartOffset()
528: && contentEnd == paragraph.getEndOffset())
529: {
530:
531:
532:
533: if (removeStart == -1)
534: {
535: removeStart = i;
536: removeEnd = i;
537: }
538: else
539: removeEnd = i;
540: }
541: else
542: {
543:
544:
545: int removeLen = contentEnd - contentStart;
546: Element[] removed = new Element[removeLen];
547: for (int j = contentStart; j < contentEnd; j++)
548: removed[j] = paragraph.getElement(j);
549: ((BranchElement) paragraph).replace(contentStart, removeLen,
550: empty);
551: documentEvent.addEdit(new ElementEdit(paragraph, contentStart,
552: removed, empty));
553: }
554: }
555:
556:
557: if (removeStart != -1)
558: {
559: int removeLen = removeEnd - removeStart;
560: Element[] removed = new Element[removeLen];
561: for (int i = removeStart; i < removeEnd; i++)
562: removed[i] = root.getElement(i);
563: ((BranchElement) root).replace(removeStart, removeLen, empty);
564: documentEvent.addEdit(new ElementEdit(root, removeStart, removed,
565: empty));
566: }
567: }
568:
569:
583: public void change(int offset, int length, DefaultDocumentEvent ev)
584: {
585: this.offset = offset;
586: this.length = length;
587: documentEvent = ev;
588: changeUpdate();
589: }
590:
591:
596: protected void changeUpdate()
597: {
598:
599: Element el = getCharacterElement(offset);
600: Element[] res = split(el, offset, 0);
601: BranchElement par = (BranchElement) el.getParentElement();
602: if (res[1] != null)
603: {
604: int index = par.getElementIndex(offset);
605: Element[] removed;
606: Element[] added;
607: if (res[0] == null)
608: {
609: removed = new Element[0];
610: added = new Element[]{ res[1] };
611: index++;
612: }
613: else
614: {
615: removed = new Element[]{ el };
616: added = new Element[]{ res[0], res[1] };
617: }
618: par.replace(index, removed.length, added);
619: addEdit(par, index, removed, added);
620: }
621:
622: int endOffset = offset + length;
623: el = getCharacterElement(endOffset);
624: res = split(el, endOffset, 0);
625: par = (BranchElement) el.getParentElement();
626: if (res[1] != null)
627: {
628: int index = par.getElementIndex(offset);
629: Element[] removed;
630: Element[] added;
631: if (res[1] == null)
632: {
633: removed = new Element[0];
634: added = new Element[]{ res[1] };
635: }
636: else
637: {
638: removed = new Element[]{ el };
639: added = new Element[]{ res[0], res[1] };
640: }
641: par.replace(index, removed.length, added);
642: addEdit(par, index, removed, added);
643: }
644: }
645:
646:
661: private Element[] split(Element el, int offset, int space)
662: {
663:
664: if ((offset == el.getStartOffset() || offset == el.getEndOffset())
665: && space == 0 && el.isLeaf())
666: return new Element[2];
667:
668:
669:
670: Element[] res = new Element[2];
671: if (el instanceof BranchElement)
672: {
673: int index = el.getElementIndex(offset);
674: Element child = el.getElement(index);
675: Element[] result = split(child, offset, space);
676: Element[] removed;
677: Element[] added;
678: Element[] newAdded;
679:
680: int count = el.getElementCount();
681: if (!(result[1] == null))
682: {
683:
684: if (result[0] == null)
685: {
686: removed = new Element[count - index - 1];
687: newAdded = new Element[count - index - 1];
688: added = new Element[]{};
689: }
690:
691: else
692: {
693: removed = new Element[count - index];
694: newAdded = new Element[count - index];
695: added = new Element[]{result[0]};
696: }
697: newAdded[0] = result[1];
698: for (int i = index; i < count; i++)
699: {
700: Element el2 = el.getElement(i);
701: int ind = i - count + removed.length;
702: removed[ind] = el2;
703: if (ind != 0)
704: newAdded[ind] = el2;
705: }
706:
707: ((BranchElement) el).replace(index, removed.length, added);
708: addEdit(el, index, removed, added);
709: BranchElement newPar =
710: (BranchElement) createBranchElement(el.getParentElement(),
711: el.getAttributes());
712: newPar.replace(0, 0, newAdded);
713: res = new Element[]{ null, newPar };
714: }
715: else
716: {
717: removed = new Element[count - index];
718: for (int i = index; i < count; ++i)
719: removed[i - index] = el.getElement(i);
720: added = new Element[0];
721: ((BranchElement) el).replace(index, removed.length,
722: added);
723: addEdit(el, index, removed, added);
724: BranchElement newPar =
725: (BranchElement) createBranchElement(el.getParentElement(),
726: el.getAttributes());
727: newPar.replace(0, 0, removed);
728: res = new Element[]{ null, newPar };
729: }
730: }
731: else if (el instanceof LeafElement)
732: {
733: BranchElement par = (BranchElement) el.getParentElement();
734: Element el1 = createLeafElement(par, el.getAttributes(),
735: el.getStartOffset(), offset);
736: Element el2 = createLeafElement(par, el.getAttributes(),
737: offset + space, el.getEndOffset());
738: res = new Element[]{ el1, el2 };
739: }
740: return res;
741: }
742:
743:
757: public void insert(int offset, int length, ElementSpec[] data,
758: DefaultDocumentEvent ev)
759: {
760: if (length == 0)
761: return;
762: this.offset = offset;
763: this.length = length;
764: this.endOffset = offset + length;
765: documentEvent = ev;
766:
767: elementStack.clear();
768: elementStack.push(root);
769: elementStack.push(root.getElement(root.getElementIndex(offset)));
770: numEndTags = 0;
771: numStartTags = 0;
772: insertUpdate(data);
773: }
774:
775:
783: protected void insertUpdate(ElementSpec[] data)
784: {
785: if (data[0].getType() == ElementSpec.EndTagType)
786: {
787:
788: BranchElement paragraph = (BranchElement) elementStack.peek();
789: Element curr = paragraph.getParentElement();
790: int index = curr.getElementIndex(offset);
791: while (!curr.isLeaf())
792: {
793: index = curr.getElementIndex(offset);
794: curr = curr.getElement(index);
795: }
796: Element parent = curr.getParentElement();
797: Element newEl1 = createLeafElement(parent,
798: curr.getAttributes(),
799: curr.getStartOffset(), offset);
800: Element grandParent = parent.getParentElement();
801: BranchElement nextBranch =
802: (BranchElement) grandParent.getElement
803: (grandParent.getElementIndex(parent.getEndOffset()));
804: Element firstLeaf = nextBranch.getElement(0);
805: while (!firstLeaf.isLeaf())
806: {
807: firstLeaf = firstLeaf.getElement(0);
808: }
809: BranchElement parent2 = (BranchElement) firstLeaf.getParentElement();
810: Element newEl2 =
811: createLeafElement(parent2,
812: firstLeaf.getAttributes(),
813: offset, firstLeaf.getEndOffset());
814: parent2.replace(0, 1, new Element[] { newEl2 });
815:
816:
817: ((BranchElement) parent).
818: replace(index, 1, new Element[] { newEl1 });
819: }
820:
821: for (int i = 0; i < data.length; i++)
822: {
823: BranchElement paragraph = (BranchElement) elementStack.peek();
824: switch (data[i].getType())
825: {
826: case ElementSpec.StartTagType:
827: switch (data[i].getDirection())
828: {
829: case ElementSpec.JoinFractureDirection:
830: insertFracture(data[i]);
831: break;
832: case ElementSpec.JoinNextDirection:
833: int index = paragraph.getElementIndex(offset);
834: elementStack.push(paragraph.getElement(index));
835: break;
836: case ElementSpec.OriginateDirection:
837: Element current = (Element) elementStack.peek();
838: Element newParagraph =
839: insertParagraph((BranchElement) current, offset);
840: elementStack.push(newParagraph);
841: break;
842: default:
843: break;
844: }
845: break;
846: case ElementSpec.EndTagType:
847: elementStack.pop();
848: break;
849: case ElementSpec.ContentType:
850: insertContentTag(data[i]);
851: break;
852: }
853: }
854: endEdit();
855: }
856:
857:
862: private void endEdit()
863: {
864: if (documentEvent.modified)
865: prepareContentInsertion();
866: }
867:
868:
872: private void prepareContentInsertion()
873: {
874: while (numEndTags > 0)
875: {
876: elementStack.pop();
877: numEndTags--;
878: }
879:
880: while (numStartTags > 0)
881: {
882: Element current = (Element) elementStack.peek();
883: Element newParagraph =
884: insertParagraph((BranchElement) current, offset);
885: elementStack.push(newParagraph);
886: numStartTags--;
887: }
888: }
889:
890: private Element insertParagraph(BranchElement par, int offset)
891: {
892: Element current = par.getElement(par.getElementIndex(offset));
893: Element[] res = split(current, offset, 0);
894: int index = par.getElementIndex(offset);
895: Element ret;
896: if (res[1] != null)
897: {
898: Element[] removed;
899: Element[] added;
900: if (res[0] == null)
901: {
902: removed = new Element[0];
903: if (res[1] instanceof BranchElement)
904: {
905: added = new Element[]{ res[1] };
906: ret = res[1];
907: }
908: else
909: {
910: ret = createBranchElement(par, null);
911: added = new Element[]{ ret, res[1] };
912: }
913: index++;
914: }
915: else
916: {
917: removed = new Element[]{ current };
918: if (res[1] instanceof BranchElement)
919: {
920: ret = res[1];
921: added = new Element[]{ res[0], res[1] };
922: }
923: else
924: {
925: ret = createBranchElement(par, null);
926: added = new Element[]{ res[0], ret, res[1] };
927: }
928: }
929: par.replace(index, removed.length, added);
930: addEdit(par, index, removed, added);
931: }
932: else
933: {
934: ret = createBranchElement(par, null);
935: Element[] added = new Element[]{ ret };
936: par.replace(index, 0, added);
937: addEdit(par, index, new Element[0], added);
938: }
939: return ret;
940: }
941:
942:
947: private void insertFracture(ElementSpec tag)
948: {
949:
950:
951: BranchElement parent = (BranchElement) elementStack.peek();
952: int parentIndex = parent.getElementIndex(offset);
953:
954:
955:
956:
957:
958:
959: BranchElement previous = (BranchElement) parent.getElement(parentIndex);
960:
961:
962: BranchElement newBranch =
963: (BranchElement) createBranchElement(parent, previous.getAttributes());
964:
965:
966:
967:
968:
969:
970:
971:
972:
973:
974:
975:
976:
977: int previousIndex = previous.getElementIndex(offset);
978: int numReplaced = previous.getElementCount() - previousIndex;
979: Element previousLeaf = previous.getElement(previousIndex);
980: AttributeSet prevLeafAtts = previous.getAttributes();
981:
982:
983:
984: Element newPreviousLeaf =
985: createLeafElement(previous,
986: prevLeafAtts, previousLeaf.getStartOffset(),
987: offset);
988:
989:
990:
991: Element firstLeafInNewBranch =
992: createLeafElement(newBranch, prevLeafAtts,
993: offset, previousLeaf.getEndOffset());
994:
995:
996:
997: Element[] newLeaves = new Element[numReplaced];
998: newLeaves[0] = firstLeafInNewBranch;
999: for (int i = 1; i < numReplaced; i++)
1000: newLeaves[i] = previous.getElement(previousIndex + i);
1001: newBranch.replace(0, 0, newLeaves);
1002: addEdit(newBranch, 0, null, newLeaves);
1003:
1004:
1005:
1006: int removeSize = previous.getElementCount() - previousIndex;
1007: Element[] add = new Element[] { newPreviousLeaf };
1008: Element[] remove = new Element[removeSize];
1009: for (int j = 0; j < removeSize; j++)
1010: remove[j] = previous.getElement(previousIndex + j);
1011: previous.replace(previousIndex, removeSize, add);
1012: addEdit(previous, previousIndex, remove, add);
1013:
1014:
1015: Element[] nb = new Element[] { newBranch };
1016: int index = parentIndex + 1;
1017: parent.replace(index, 0, nb);
1018: addEdit(parent, index, null, nb);
1019: }
1020:
1021:
1026: private void insertContentTag(ElementSpec tag)
1027: {
1028: prepareContentInsertion();
1029: int len = tag.getLength();
1030: int dir = tag.getDirection();
1031: AttributeSet tagAtts = tag.getAttributes();
1032: if (dir == ElementSpec.JoinPreviousDirection)
1033: {
1034:
1035:
1036:
1037:
1038: }
1039: else if (dir == ElementSpec.JoinNextDirection)
1040: {
1041:
1042:
1043:
1044:
1045:
1046:
1047:
1048:
1049:
1050:
1051:
1052:
1053:
1054:
1055: BranchElement paragraph = (BranchElement) elementStack.peek();
1056: int index = paragraph.getElementIndex(offset);
1057: Element target = paragraph.getElement(index);
1058: if (target.isLeaf() && paragraph.getElementCount() > (index + 1))
1059: {
1060: Element next = paragraph.getElement(index + 1);
1061: Element newEl1 = createLeafElement(paragraph,
1062: target.getAttributes(),
1063: target.getStartOffset(),
1064: offset);
1065: Element newEl2 = createLeafElement(paragraph,
1066: next.getAttributes(), offset,
1067: next.getEndOffset());
1068: Element[] add = new Element[] { newEl1, newEl2 };
1069: paragraph.replace (index, 2, add);
1070: addEdit(paragraph, index, new Element[] { target, next }, add);
1071: }
1072: }
1073: else if (dir == ElementSpec.OriginateDirection)
1074: {
1075: BranchElement paragraph = (BranchElement) elementStack.peek();
1076: int index = paragraph.getElementIndex(offset);
1077: Element current = paragraph.getElement(index);
1078:
1079: Element[] added;
1080: Element[] removed = new Element[] {current};
1081: Element[] splitRes = split(current, offset, length);
1082: if (splitRes[0] == null)
1083: {
1084: added = new Element[2];
1085: added[0] = createLeafElement(paragraph, tagAtts,
1086: offset, endOffset);
1087: added[1] = splitRes[1];
1088: removed = new Element[0];
1089: index++;
1090: }
1091: else if (current.getStartOffset() == offset)
1092: {
1093:
1094:
1095:
1096: added = new Element[2];
1097: added[0] = createLeafElement(paragraph, tagAtts, offset,
1098: endOffset);
1099: added[1] = splitRes[1];
1100: }
1101: else if (current.getEndOffset() == endOffset)
1102: {
1103:
1104:
1105:
1106: added = new Element[2];
1107: added[0] = splitRes[0];
1108: added[1] = createLeafElement(paragraph, tagAtts, offset,
1109: endOffset);
1110: }
1111: else
1112: {
1113:
1114:
1115:
1116: added = new Element[3];
1117: added[0] = splitRes[0];
1118: added[1] = createLeafElement(paragraph, tagAtts, offset,
1119: endOffset);
1120: added[2] = splitRes[1];
1121: }
1122: paragraph.replace(index, removed.length, added);
1123: addEdit(paragraph, index, removed, added);
1124: }
1125: offset += len;
1126: }
1127:
1128:
1135: public Element clone (Element parent, Element clonee)
1136: {
1137:
1138: if (clonee.isLeaf())
1139: return createLeafElement(parent, clonee.getAttributes(),
1140: clonee.getStartOffset(), clonee.getEndOffset());
1141:
1142:
1143:
1144: BranchElement result = (BranchElement) createBranchElement(parent, clonee.getAttributes());
1145:
1146:
1147: Element[] children = new Element[clonee.getElementCount()];
1148: for (int i = 0; i < children.length; i++)
1149: children[i] = clone(result, clonee.getElement(i));
1150:
1151:
1152: result.replace(0, 0, children);
1153: return result;
1154: }
1155:
1156:
1168: private void addEdit(Element e, int i, Element[] removed, Element[] added)
1169: {
1170:
1171: DocumentEvent.ElementChange ec = documentEvent.getChange(e);
1172:
1173:
1174: Element[] oldAdded = ec == null ? null: ec.getChildrenAdded();
1175: Element[] newAdded;
1176: if (oldAdded != null && added != null)
1177: {
1178: if (ec.getIndex() <= i)
1179: {
1180: int index = i - ec.getIndex();
1181:
1182: newAdded = new Element[oldAdded.length + added.length];
1183: System.arraycopy(oldAdded, 0, newAdded, 0, index);
1184: System.arraycopy(added, 0, newAdded, index, added.length);
1185: System.arraycopy(oldAdded, index, newAdded, index + added.length,
1186: oldAdded.length - index);
1187: i = ec.getIndex();
1188: }
1189: else
1190: throw new AssertionError("Not yet implemented case.");
1191: }
1192: else if (added != null)
1193: newAdded = added;
1194: else if (oldAdded != null)
1195: newAdded = oldAdded;
1196: else
1197: newAdded = new Element[0];
1198:
1199: Element[] oldRemoved = ec == null ? null: ec.getChildrenRemoved();
1200: Element[] newRemoved;
1201: if (oldRemoved != null && removed != null)
1202: {
1203: if (ec.getIndex() <= i)
1204: {
1205: int index = i - ec.getIndex();
1206:
1207: newRemoved = new Element[oldRemoved.length + removed.length];
1208: System.arraycopy(oldAdded, 0, newRemoved, 0, index);
1209: System.arraycopy(removed, 0, newRemoved, index, removed.length);
1210: System.arraycopy(oldRemoved, index, newRemoved,
1211: index + removed.length,
1212: oldRemoved.length - index);
1213: i = ec.getIndex();
1214: }
1215: else
1216: throw new AssertionError("Not yet implemented case.");
1217: }
1218: else if (removed != null)
1219: newRemoved = removed;
1220: else if (oldRemoved != null)
1221: newRemoved = oldRemoved;
1222: else
1223: newRemoved = new Element[0];
1224:
1225:
1226: documentEvent.addEdit(new ElementEdit(e, i, newRemoved, newAdded));
1227: }
1228: }
1229:
1230:
1234: protected class SectionElement extends BranchElement
1235: {
1236:
1239: public SectionElement()
1240: {
1241: super(null, null);
1242: }
1243:
1244:
1250: public String getName()
1251: {
1252: return SectionElementName;
1253: }
1254: }
1255:
1256:
1262: private class StyleChangeListener
1263: implements ChangeListener
1264: {
1265:
1266:
1272: public void stateChanged(ChangeEvent event)
1273: {
1274: Style style = (Style) event.getSource();
1275: styleChanged(style);
1276: }
1277: }
1278:
1279:
1280: private static final long serialVersionUID = 940485415728614849L;
1281:
1282:
1285: public static final int BUFFER_SIZE_DEFAULT = 4096;
1286:
1287:
1291: protected DefaultStyledDocument.ElementBuffer buffer;
1292:
1293:
1296: private StyleChangeListener styleChangeListener;
1297:
1298:
1301: public DefaultStyledDocument()
1302: {
1303: this(new GapContent(BUFFER_SIZE_DEFAULT), new StyleContext());
1304: }
1305:
1306:
1312: public DefaultStyledDocument(StyleContext context)
1313: {
1314: this(new GapContent(BUFFER_SIZE_DEFAULT), context);
1315: }
1316:
1317:
1324: public DefaultStyledDocument(AbstractDocument.Content content,
1325: StyleContext context)
1326: {
1327: super(content, context);
1328: buffer = new ElementBuffer(createDefaultRoot());
1329: setLogicalStyle(0, context.getStyle(StyleContext.DEFAULT_STYLE));
1330: }
1331:
1332:
1348: public Style addStyle(String nm, Style parent)
1349: {
1350: StyleContext context = (StyleContext) getAttributeContext();
1351: Style newStyle = context.addStyle(nm, parent);
1352:
1353:
1354: if (styleChangeListener == null)
1355: styleChangeListener = new StyleChangeListener();
1356: newStyle.addChangeListener(styleChangeListener);
1357:
1358: return newStyle;
1359: }
1360:
1361:
1366: protected AbstractDocument.AbstractElement createDefaultRoot()
1367: {
1368: Element[] tmp;
1369:
1370:
1371: SectionElement section = new SectionElement();
1372:
1373: BranchElement paragraph = new BranchElement(section, null);
1374: tmp = new Element[1];
1375: tmp[0] = paragraph;
1376: section.replace(0, 0, tmp);
1377:
1378: LeafElement leaf = new LeafElement(paragraph, null, 0, 1);
1379: tmp = new Element[1];
1380: tmp[0] = leaf;
1381: paragraph.replace(0, 0, tmp);
1382:
1383: return section;
1384: }
1385:
1386:
1396: public Element getCharacterElement(int position)
1397: {
1398: Element element = getDefaultRootElement();
1399:
1400: while (!element.isLeaf())
1401: {
1402: int index = element.getElementIndex(position);
1403: element = element.getElement(index);
1404: }
1405:
1406: return element;
1407: }
1408:
1409:
1416: public Color getBackground(AttributeSet attributes)
1417: {
1418: StyleContext context = (StyleContext) getAttributeContext();
1419: return context.getBackground(attributes);
1420: }
1421:
1422:
1427: public Element getDefaultRootElement()
1428: {
1429: return buffer.getRootElement();
1430: }
1431:
1432:
1439: public Font getFont(AttributeSet attributes)
1440: {
1441: StyleContext context = (StyleContext) getAttributeContext();
1442: return context.getFont(attributes);
1443: }
1444:
1445:
1452: public Color getForeground(AttributeSet attributes)
1453: {
1454: StyleContext context = (StyleContext) getAttributeContext();
1455: return context.getForeground(attributes);
1456: }
1457:
1458:
1465: public Style getLogicalStyle(int position)
1466: {
1467: Element paragraph = getParagraphElement(position);
1468: AttributeSet attributes = paragraph.getAttributes();
1469: AttributeSet a = attributes.getResolveParent();
1470:
1471: if (a instanceof Style)
1472: return (Style) a;
1473: return null;
1474: }
1475:
1476:
1487: public Element getParagraphElement(int position)
1488: {
1489: BranchElement root = (BranchElement) getDefaultRootElement();
1490: int start = root.getStartOffset();
1491: int end = root.getEndOffset();
1492: if (position >= end)
1493: position = end - 1;
1494: else if (position < start)
1495: position = start;
1496:
1497: Element par = root.positionToElement(position);
1498:
1499: assert par != null : "The paragraph element must not be null";
1500: return par;
1501: }
1502:
1503:
1511: public Style getStyle(String nm)
1512: {
1513: StyleContext context = (StyleContext) getAttributeContext();
1514: return context.getStyle(nm);
1515: }
1516:
1517:
1522: public void removeStyle(String nm)
1523: {
1524: StyleContext context = (StyleContext) getAttributeContext();
1525: context.removeStyle(nm);
1526: }
1527:
1528:
1538: public void setCharacterAttributes(int offset, int length,
1539: AttributeSet attributes,
1540: boolean replace)
1541: {
1542:
1543: if (length == 0)
1544: return;
1545: try
1546: {
1547:
1548:
1549:
1550: writeLock();
1551: DefaultDocumentEvent ev =
1552: new DefaultDocumentEvent(
1553: offset,
1554: length,
1555: DocumentEvent.EventType.CHANGE);
1556:
1557:
1558:
1559:
1560: buffer.change(offset, length, ev);
1561:
1562: Element root = getDefaultRootElement();
1563:
1564: int end = offset + length;
1565: Element curr;
1566: for (int pos = offset; pos < end; )
1567: {
1568:
1569: curr = getCharacterElement(pos);
1570: if (pos == curr.getEndOffset())
1571: break;
1572:
1573: MutableAttributeSet a = (MutableAttributeSet) curr.getAttributes();
1574: ev.addEdit(new AttributeUndoableEdit(curr, attributes, replace));
1575:
1576: if (replace)
1577: a.removeAttributes(a);
1578:
1579: a.addAttributes(attributes);
1580:
1581: pos = curr.getEndOffset();
1582: }
1583: fireChangedUpdate(ev);
1584: fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
1585: }
1586: finally
1587: {
1588: writeUnlock();
1589: }
1590: }
1591:
1592:
1598: public void setLogicalStyle(int position, Style style)
1599: {
1600: Element el = getParagraphElement(position);
1601:
1602:
1603: if (el == null)
1604: return;
1605: try
1606: {
1607: writeLock();
1608: if (el instanceof AbstractElement)
1609: {
1610: AbstractElement ael = (AbstractElement) el;
1611: ael.setResolveParent(style);
1612: int start = el.getStartOffset();
1613: int end = el.getEndOffset();
1614: DefaultDocumentEvent ev =
1615: new DefaultDocumentEvent (
1616: start,
1617: end - start,
1618: DocumentEvent.EventType.CHANGE);
1619:
1620: fireChangedUpdate(ev);
1621: }
1622: else
1623: throw new
1624: AssertionError("paragraph elements are expected to be"
1625: + "instances of AbstractDocument.AbstractElement");
1626: }
1627: finally
1628: {
1629: writeUnlock();
1630: }
1631: }
1632:
1633:
1642: public void setParagraphAttributes(int offset, int length,
1643: AttributeSet attributes,
1644: boolean replace)
1645: {
1646: try
1647: {
1648:
1649:
1650:
1651: writeLock();
1652:
1653:
1654: DefaultDocumentEvent ev =
1655: new DefaultDocumentEvent (
1656: offset,
1657: length,
1658: DocumentEvent.EventType.CHANGE);
1659:
1660:
1661:
1662:
1663: Element rootElement = getDefaultRootElement();
1664: int startElement = rootElement.getElementIndex(offset);
1665: int endElement = rootElement.getElementIndex(offset + length - 1);
1666: if (endElement < startElement)
1667: endElement = startElement;
1668:
1669: for (int i = startElement; i <= endElement; i++)
1670: {
1671: Element par = rootElement.getElement(i);
1672: MutableAttributeSet a = (MutableAttributeSet) par.getAttributes();
1673:
1674: ev.addEdit(new AttributeUndoableEdit(par, attributes, replace));
1675:
1676: if (replace)
1677: a.removeAttributes(a);
1678:
1679: a.addAttributes(attributes);
1680: }
1681: fireChangedUpdate(ev);
1682: fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
1683: }
1684: finally
1685: {
1686: writeUnlock();
1687: }
1688: }
1689:
1690:
1697: protected void insertUpdate(DefaultDocumentEvent ev, AttributeSet attr)
1698: {
1699: super.insertUpdate(ev, attr);
1700:
1701: if (attr == null)
1702: attr = SimpleAttributeSet.EMPTY;
1703: int offset = ev.getOffset();
1704: int length = ev.getLength();
1705: int endOffset = offset + length;
1706: AttributeSet paragraphAttributes =
1707: getParagraphElement(endOffset).getAttributes();
1708: Segment txt = new Segment();
1709: try
1710: {
1711: getText(offset, length, txt);
1712: }
1713: catch (BadLocationException ex)
1714: {
1715: AssertionError ae = new AssertionError("Unexpected bad location");
1716: ae.initCause(ex);
1717: throw ae;
1718: }
1719:
1720: int len = 0;
1721: Vector specs = new Vector();
1722: ElementSpec finalStartTag = null;
1723: short finalStartDirection = ElementSpec.OriginateDirection;
1724: boolean prevCharWasNewline = false;
1725: Element prev = getCharacterElement(offset);
1726: Element next = getCharacterElement(endOffset);
1727: Element prevParagraph = getParagraphElement(offset);
1728: Element paragraph = getParagraphElement(endOffset);
1729:
1730: int segmentEnd = txt.offset + txt.count;
1731:
1732:
1733: if (offset > 0)
1734: {
1735: try
1736: {
1737: String s = getText(offset - 1, 1);
1738: if (s.equals("\n"))
1739: {
1740: finalStartDirection =
1741: handleInsertAfterNewline(specs, offset, endOffset,
1742: prevParagraph,
1743: paragraph,
1744: paragraphAttributes);
1745:
1746: prevCharWasNewline = true;
1747:
1748: for (int i = 0; i < specs.size(); i++)
1749: if (((ElementSpec) specs.get(i)).getType()
1750: == ElementSpec.StartTagType)
1751: finalStartTag = (ElementSpec)specs.get(i);
1752: }
1753: }
1754: catch (BadLocationException ble)
1755: {
1756:
1757: AssertionError ae = new AssertionError();
1758: ae.initCause(ble);
1759: throw ae;
1760: }
1761: }
1762:
1763:
1764: for (int i = txt.offset; i < segmentEnd; ++i)
1765: {
1766: len++;
1767: if (txt.array[i] == '\n')
1768: {
1769:
1770: specs.add(new ElementSpec(attr, ElementSpec.ContentType, len));
1771:
1772:
1773: specs.add(new ElementSpec(null, ElementSpec.EndTagType));
1774: finalStartTag = new ElementSpec(paragraphAttributes,
1775: ElementSpec.StartTagType);
1776: specs.add(finalStartTag);
1777: len = 0;
1778: }
1779: }
1780:
1781:
1782: if (len > 0)
1783: specs.add(new ElementSpec(attr, ElementSpec.ContentType, len));
1784:
1785:
1786:
1787:
1788: if (finalStartTag != null)
1789: {
1790: if (prevCharWasNewline)
1791: finalStartTag.setDirection(finalStartDirection);
1792: else if (prevParagraph.getEndOffset() != endOffset)
1793: {
1794: try
1795: {
1796: String last = getText(endOffset - 1, 1);
1797: if (!last.equals("\n"))
1798: finalStartTag.setDirection(ElementSpec.JoinFractureDirection);
1799: }
1800: catch (BadLocationException ble)
1801: {
1802:
1803: AssertionError ae = new AssertionError();
1804: ae.initCause(ble);
1805: throw ae;
1806: }
1807: }
1808: else
1809: {
1810:
1811:
1812: Element parent = prevParagraph.getParentElement();
1813: int index = parent.getElementIndex(offset);
1814: if (index + 1 < parent.getElementCount()
1815: && !parent.getElement(index + 1).isLeaf())
1816: finalStartTag.setDirection(ElementSpec.JoinNextDirection);
1817: }
1818: }
1819:
1820:
1821:
1822:
1823:
1824:
1825:
1826:
1827: ElementSpec last = (ElementSpec) specs.lastElement();
1828: if (last.getType() == ElementSpec.ContentType)
1829: {
1830: Element currentRun =
1831: prevParagraph.getElement(prevParagraph.getElementIndex(offset));
1832: if (currentRun.getEndOffset() == endOffset)
1833: {
1834: if (endOffset < getLength() && next.getAttributes().isEqual(attr)
1835: && last.getType() == ElementSpec.ContentType)
1836: last.setDirection(ElementSpec.JoinNextDirection);
1837: }
1838: else
1839: {
1840: if (finalStartTag != null
1841: && finalStartTag.getDirection() ==
1842: ElementSpec.JoinFractureDirection
1843: && currentRun.getAttributes().isEqual(attr))
1844: {
1845: last.setDirection(ElementSpec.JoinNextDirection);
1846: }
1847: }
1848: }
1849:
1850:
1851:
1852: ElementSpec first = (ElementSpec) specs.firstElement();
1853: if (prev.getAttributes().isEqual(attr)
1854: && first.getType() == ElementSpec.ContentType)
1855: first.setDirection(ElementSpec.JoinPreviousDirection);
1856:
1857: ElementSpec[] elSpecs =
1858: (ElementSpec[]) specs.toArray(new ElementSpec[specs.size()]);
1859:
1860: buffer.insert(offset, length, elSpecs, ev);
1861: }
1862:
1863:
1868: short handleInsertAfterNewline(Vector specs, int offset, int endOffset,
1869: Element prevParagraph, Element paragraph,
1870: AttributeSet a)
1871: {
1872: if (prevParagraph.getParentElement() == paragraph.getParentElement())
1873: {
1874: specs.add(new ElementSpec(a, ElementSpec.EndTagType));
1875: specs.add(new ElementSpec(a, ElementSpec.StartTagType));
1876: if (prevParagraph.getEndOffset() != endOffset)
1877: return ElementSpec.JoinFractureDirection;
1878:
1879: Element parent = paragraph.getParentElement();
1880: if (parent.getElementCount() > parent.getElementIndex(offset) + 1)
1881: return ElementSpec.JoinNextDirection;
1882: }
1883: else
1884: {
1885:
1886: }
1887: return ElementSpec.OriginateDirection;
1888: }
1889:
1890:
1898: protected void removeUpdate(DefaultDocumentEvent ev)
1899: {
1900: super.removeUpdate(ev);
1901: buffer.remove(ev.getOffset(), ev.getLength(), ev);
1902: }
1903:
1904:
1909: public Enumeration getStyleNames()
1910: {
1911: StyleContext context = (StyleContext) getAttributeContext();
1912: return context.getStyleNames();
1913: }
1914:
1915:
1920: protected void styleChanged(Style style)
1921: {
1922:
1923: }
1924:
1925: void printElements (Element start, int pad)
1926: {
1927: for (int i = 0; i < pad; i++)
1928: System.out.print(" ");
1929: if (pad == 0)
1930: System.out.println ("ROOT ELEMENT ("+start.getStartOffset()+", "+start.getEndOffset()+")");
1931: else if (start instanceof AbstractDocument.BranchElement)
1932: System.out.println ("BranchElement ("+start.getStartOffset()+", "+start.getEndOffset()+")");
1933: else
1934: {
1935: {
1936: try
1937: {
1938: System.out.println ("LeafElement ("+start.getStartOffset()+", "
1939: + start.getEndOffset()+"): "+
1940: start.getDocument().
1941: getText(start.getStartOffset(),
1942: start.getEndOffset() -
1943: start.getStartOffset()));
1944: }
1945: catch (BadLocationException ble)
1946: {
1947: }
1948: }
1949: }
1950: for (int i = 0; i < start.getElementCount(); i ++)
1951: printElements (start.getElement(i), pad+3);
1952: }
1953:
1954:
1960: protected void insert(int offset, ElementSpec[] data)
1961: throws BadLocationException
1962: {
1963: if (data == null || data.length == 0)
1964: return;
1965: try
1966: {
1967:
1968:
1969:
1970: writeLock();
1971:
1972:
1973: StringBuffer contentBuffer = new StringBuffer();
1974: for (int i = 0; i < data.length; i++)
1975: {
1976:
1977:
1978: ElementSpec spec = data[i];
1979: if (spec.getArray() != null && spec.getLength() > 0)
1980: contentBuffer.append(spec.getArray(), spec.getOffset(),
1981: spec.getLength());
1982: }
1983:
1984: int length = contentBuffer.length();
1985:
1986:
1987: if (length == 0)
1988: return;
1989:
1990: UndoableEdit edit = content.insertString(offset,
1991: contentBuffer.toString());
1992:
1993:
1994: DefaultDocumentEvent ev =
1995: new DefaultDocumentEvent(offset,
1996: length,
1997: DocumentEvent.EventType.INSERT);
1998: ev.addEdit(edit);
1999:
2000:
2001:
2002: buffer.insert(offset, length, data, ev);
2003: fireInsertUpdate(ev);
2004: fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
2005: }
2006: finally
2007: {
2008: writeUnlock();
2009: }
2010: }
2011:
2012:
2019: protected void create(ElementSpec[] data)
2020: {
2021: try
2022: {
2023:
2024: content.remove(0, content.length());
2025:
2026: buffer = new ElementBuffer(createDefaultRoot());
2027:
2028: insert(0, data);
2029: }
2030: catch (BadLocationException ex)
2031: {
2032: AssertionError err = new AssertionError("Unexpected bad location");
2033: err.initCause(ex);
2034: throw err;
2035: }
2036: }
2037:
2038: static boolean attributeSetsAreSame (AttributeSet a, AttributeSet b)
2039: {
2040: return (a == null && b == null) || (a != null && a.isEqual(b));
2041: }
2042: }