1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45:
46: import ;
47:
48:
60: public class DefaultStyledDocument extends AbstractDocument
61: implements StyledDocument
62: {
63:
68: public static class ElementSpec
69: {
70:
74: public static final short StartTagType = 1;
75:
76:
80: public static final short EndTagType = 2;
81:
82:
86: public static final short ContentType = 3;
87:
88:
93: public static final short JoinPreviousDirection = 4;
94:
95:
100: public static final short JoinNextDirection = 5;
101:
102:
107: public static final short OriginateDirection = 6;
108:
109:
114: public static final short JoinFractureDirection = 7;
115:
116:
119: short type;
120:
121:
124: short direction;
125:
126:
129: int offset;
130:
131:
134: int length;
135:
136:
139: char[] content;
140:
141:
144: AttributeSet attributes;
145:
146:
153: public ElementSpec(AttributeSet a, short type)
154: {
155: this(a, type, 0);
156: }
157:
158:
167: public ElementSpec(AttributeSet a, short type, int len)
168: {
169: this(a, type, null, 0, len);
170: }
171:
172:
181: public ElementSpec(AttributeSet a, short type, char[] txt, int offs,
182: int len)
183: {
184: attributes = a;
185: this.type = type;
186: offset = offs;
187: length = len;
188: content = txt;
189: direction = OriginateDirection;
190: }
191:
192:
197: public void setType(short type)
198: {
199: this.type = type;
200: }
201:
202:
207: public short getType()
208: {
209: return type;
210: }
211:
212:
217: public void setDirection(short dir)
218: {
219: direction = dir;
220: }
221:
222:
227: public short getDirection()
228: {
229: return direction;
230: }
231:
232:
237: public AttributeSet getAttributes()
238: {
239: return attributes;
240: }
241:
242:
247: public char[] getArray()
248: {
249: return content;
250: }
251:
252:
257: public int getOffset()
258: {
259: return offset;
260: }
261:
262:
267: public int getLength()
268: {
269: return length;
270: }
271:
272:
279: public String toString()
280: {
281: StringBuilder b = new StringBuilder();
282: b.append('<');
283: switch (type)
284: {
285: case StartTagType:
286: b.append("StartTag");
287: break;
288: case EndTagType:
289: b.append("EndTag");
290: break;
291: case ContentType:
292: b.append("Content");
293: break;
294: default:
295: b.append("??");
296: break;
297: }
298:
299: b.append(':');
300:
301: switch (direction)
302: {
303: case JoinPreviousDirection:
304: b.append("JoinPrevious");
305: break;
306: case JoinNextDirection:
307: b.append("JoinNext");
308: break;
309: case OriginateDirection:
310: b.append("Originate");
311: break;
312: case JoinFractureDirection:
313: b.append("Fracture");
314: break;
315: default:
316: b.append("??");
317: break;
318: }
319:
320: b.append(':');
321: b.append(length);
322:
323: return b.toString();
324: }
325: }
326:
327:
331: public class ElementBuffer implements Serializable
332: {
333:
334: private static final long serialVersionUID = 1688745877691146623L;
335:
336:
337: private Element root;
338:
339:
340: private int offset;
341:
342:
343: private int length;
344:
345:
351: Element[] fracture;
352:
353:
356: DefaultDocumentEvent documentEvent;
357:
358:
364: public ElementBuffer(Element root)
365: {
366: this.root = root;
367: }
368:
369:
374: public Element getRootElement()
375: {
376: return root;
377: }
378:
379:
393: public void change(int offset, int length, DefaultDocumentEvent ev)
394: {
395: this.offset = offset;
396: this.length = length;
397: documentEvent = ev;
398: changeUpdate();
399: }
400:
401:
406: protected void changeUpdate()
407: {
408:
409: Element el = getCharacterElement(offset);
410: split(el, offset);
411:
412: int endOffset = offset + length;
413: el = getCharacterElement(endOffset);
414: split(el, endOffset);
415: }
416:
417:
423: void split(Element el, int offset)
424: {
425: if (el instanceof AbstractElement)
426: {
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)
432: {
433: Element paragraph = ael.getParentElement();
434: if (paragraph instanceof BranchElement)
435: {
436: BranchElement par = (BranchElement) paragraph;
437: Element child1 = createLeafElement(par, ael, startOffset,
438: offset);
439: Element child2 = createLeafElement(par, ael, offset,
440: endOffset);
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,
445: new Element[]{ el },
446: add));
447: }
448: else
449: throw new AssertionError("paragraph elements are expected to "
450: + "be instances of "
451: + "javax.swing.text.AbstractDocument.BranchElement");
452: }
453: }
454: else
455: throw new AssertionError("content elements are expected to be "
456: + "instances of "
457: + "javax.swing.text.AbstractDocument.AbstractElement");
458: }
459:
460:
474: public void insert(int offset, int length, ElementSpec[] data,
475: DefaultDocumentEvent ev)
476: {
477: this.offset = offset;
478: this.length = length;
479: documentEvent = ev;
480: insertUpdate(data);
481: }
482:
483:
491: protected void insertUpdate(ElementSpec[] data)
492: {
493: for (int i = 0; i < data.length; i++)
494: {
495: switch (data[i].getType())
496: {
497: case ElementSpec.StartTagType:
498: insertStartTag(data[i]);
499: break;
500: case ElementSpec.EndTagType:
501: insertEndTag(data[i]);
502: break;
503: default:
504: insertContentTag(data[i]);
505: break;
506: }
507: }
508: }
509:
510:
515: void insertStartTag(ElementSpec tag)
516: {
517: BranchElement root = (BranchElement) getDefaultRootElement();
518: int index = root.getElementIndex(offset);
519: if (index == -1)
520: index = 0;
521:
522: BranchElement newParagraph =
523: (BranchElement) createBranchElement(root, tag.getAttributes());
524: newParagraph.setResolveParent(getStyle(StyleContext.DEFAULT_STYLE));
525:
526:
527: Element[] added = new Element[]{newParagraph};
528: root.replace(index + 1, 0, added);
529: ElementEdit edit = new ElementEdit(root, index + 1, new Element[0],
530: added);
531: documentEvent.addEdit(edit);
532:
533:
534: if (tag.getDirection() == ElementSpec.JoinFractureDirection)
535: {
536: Element[] newFracture = new Element[fracture.length];
537: for (int i = 0; i < fracture.length; i++)
538: {
539: Element oldLeaf = fracture[i];
540: Element newLeaf = createLeafElement(newParagraph,
541: oldLeaf.getAttributes(),
542: oldLeaf.getStartOffset(),
543: oldLeaf.getEndOffset());
544: newFracture[i] = newLeaf;
545: }
546: newParagraph.replace(0, 0, newFracture);
547: edit = new ElementEdit(newParagraph, 0, new Element[0],
548: fracture);
549: documentEvent.addEdit(edit);
550: fracture = new Element[0];
551: }
552: }
553:
554:
560: void insertEndTag(ElementSpec tag)
561: {
562: BranchElement root = (BranchElement) getDefaultRootElement();
563: int parIndex = root.getElementIndex(offset);
564: BranchElement paragraph = (BranchElement) root.getElement(parIndex);
565:
566: int index = paragraph.getElementIndex(offset);
567: LeafElement content = (LeafElement) paragraph.getElement(index);
568:
569: split(content, offset);
570: index = paragraph.getElementIndex(offset);
571:
572: int count = paragraph.getElementCount();
573:
574: fracture = new Element[count - index];
575: for (int i = index; i < count; ++i)
576: fracture[i - index] = paragraph.getElement(i);
577:
578:
579: paragraph.replace(index, count - index, new Element[0]);
580:
581:
582: ElementEdit edit = new ElementEdit(paragraph, index, fracture,
583: new Element[0]);
584: documentEvent.addEdit(edit);
585: }
586:
587:
592: void insertContentTag(ElementSpec tag)
593: {
594: int len = tag.getLength();
595: int dir = tag.getDirection();
596: if (dir == ElementSpec.JoinPreviousDirection)
597: {
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(),
603: offset + len));
604: int ind = prevParent.getElementIndex(offset);
605: if (ind == -1)
606: ind = 0;
607: Element[] add = new Element[]{join};
608: prevParent.replace(ind, 1, add);
609:
610:
611: ElementEdit edit = new ElementEdit(prevParent, ind,
612: new Element[]{prev}, add);
613: documentEvent.addEdit(edit);
614: }
615: else if (dir == ElementSpec.JoinNextDirection)
616: {
617: Element next = getCharacterElement(offset + len);
618: BranchElement nextParent = (BranchElement) next.getParentElement();
619: Element join = createLeafElement(nextParent, tag.getAttributes(),
620: offset,
621: next.getEndOffset());
622: int ind = nextParent.getElementIndex(offset + len);
623: if (ind == -1)
624: ind = 0;
625: Element[] add = new Element[]{join};
626: nextParent.replace(ind, 1, add);
627:
628:
629: ElementEdit edit = new ElementEdit(nextParent, ind,
630: new Element[]{next}, add);
631: documentEvent.addEdit(edit);
632: }
633: else
634: {
635: BranchElement par = (BranchElement) getParagraphElement(offset);
636:
637: int ind = par.getElementIndex(offset);
638:
639:
640:
641: Element prev = par.getElement(ind);
642: if (prev != null && prev.getStartOffset() < offset)
643: {
644: Element cutPrev = createLeafElement(par, prev.getAttributes(),
645: prev.getStartOffset(),
646: offset);
647: Element[] remove = new Element[]{prev};
648: Element[] add = new Element[]{cutPrev};
649: if (prev.getEndOffset() > offset + len)
650: {
651: Element rem = createLeafElement(par, prev.getAttributes(),
652: offset + len,
653: prev.getEndOffset());
654: add = new Element[]{cutPrev, rem};
655: }
656:
657: par.replace(ind, 1, add);
658: documentEvent.addEdit(new ElementEdit(par, ind, remove, add));
659: ind++;
660: }
661:
662:
663:
664: Element next = par.getElement(ind);
665: if (next != null && next.getStartOffset() < offset + len)
666: {
667: Element cutNext = createLeafElement(par, next.getAttributes(),
668: offset + len,
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,
674: add));
675: }
676:
677:
678: Element newEl = createLeafElement(par, tag.getAttributes(),
679: offset, offset + len);
680: Element[] added = new Element[]{newEl};
681: par.replace(ind, 0, added);
682:
683: ElementEdit edit = new ElementEdit(par, ind, new Element[0],
684: added);
685: documentEvent.addEdit(edit);
686: }
687: offset += len;
688: }
689: }
690:
691:
695: protected class SectionElement extends BranchElement
696: {
697:
700: public SectionElement()
701: {
702: super(null, null);
703: }
704:
705:
711: public String getName()
712: {
713: return "section";
714: }
715: }
716:
717:
718: private static final long serialVersionUID = 940485415728614849L;
719:
720:
723: public static final int BUFFER_SIZE_DEFAULT = 4096;
724:
725:
729: protected DefaultStyledDocument.ElementBuffer buffer;
730:
731:
734: public DefaultStyledDocument()
735: {
736: this(new GapContent(BUFFER_SIZE_DEFAULT), new StyleContext());
737: }
738:
739:
745: public DefaultStyledDocument(StyleContext context)
746: {
747: this(new GapContent(BUFFER_SIZE_DEFAULT), context);
748: }
749:
750:
757: public DefaultStyledDocument(AbstractDocument.Content content,
758: StyleContext context)
759: {
760: super(content, context);
761: buffer = new ElementBuffer(createDefaultRoot());
762: setLogicalStyle(0, context.getStyle(StyleContext.DEFAULT_STYLE));
763: }
764:
765:
781: public Style addStyle(String nm, Style parent)
782: {
783: StyleContext context = (StyleContext) getAttributeContext();
784: return context.addStyle(nm, parent);
785: }
786:
787:
792: protected AbstractDocument.AbstractElement createDefaultRoot()
793: {
794: Element[] tmp;
795:
796:
797: SectionElement section = new SectionElement();
798:
799: BranchElement paragraph =
800: (BranchElement) createBranchElement(section, null);
801: paragraph.setResolveParent(getStyle(StyleContext.DEFAULT_STYLE));
802: tmp = new Element[1];
803: tmp[0] = paragraph;
804: section.replace(0, 0, tmp);
805:
806: LeafElement leaf = new LeafElement(paragraph, null, 0, 1);
807: tmp = new Element[1];
808: tmp[0] = leaf;
809: paragraph.replace(0, 0, tmp);
810:
811: return section;
812: }
813:
814:
824: public Element getCharacterElement(int position)
825: {
826: Element element = getDefaultRootElement();
827:
828: while (! element.isLeaf())
829: {
830: int index = element.getElementIndex(position);
831: element = element.getElement(index);
832: }
833:
834: return element;
835: }
836:
837:
844: public Color getBackground(AttributeSet attributes)
845: {
846: StyleContext context = (StyleContext) getAttributeContext();
847: return context.getBackground(attributes);
848: }
849:
850:
855: public Element getDefaultRootElement()
856: {
857: return buffer.getRootElement();
858: }
859:
860:
867: public Font getFont(AttributeSet attributes)
868: {
869: StyleContext context = (StyleContext) getAttributeContext();
870: return context.getFont(attributes);
871: }
872:
873:
880: public Color getForeground(AttributeSet attributes)
881: {
882: StyleContext context = (StyleContext) getAttributeContext();
883: return context.getForeground(attributes);
884: }
885:
886:
893: public Style getLogicalStyle(int position)
894: {
895: Element paragraph = getParagraphElement(position);
896: AttributeSet attributes = paragraph.getAttributes();
897: return (Style) attributes.getResolveParent();
898: }
899:
900:
911: public Element getParagraphElement(int position)
912: {
913: BranchElement root = (BranchElement) getDefaultRootElement();
914: int start = root.getStartOffset();
915: int end = root.getEndOffset();
916: if (position >= end)
917: position = end - 1;
918: else if (position < start)
919: position = start;
920:
921: Element par = root.positionToElement(position);
922:
923: assert par != null : "The paragraph element must not be null";
924: return par;
925: }
926:
927:
935: public Style getStyle(String nm)
936: {
937: StyleContext context = (StyleContext) getAttributeContext();
938: return context.getStyle(nm);
939: }
940:
941:
946: public void removeStyle(String nm)
947: {
948: StyleContext context = (StyleContext) getAttributeContext();
949: context.removeStyle(nm);
950: }
951:
952:
962: public void setCharacterAttributes(int offset, int length,
963: AttributeSet attributes,
964: boolean replace)
965: {
966: DefaultDocumentEvent ev =
967: new DefaultDocumentEvent(offset, length,
968: DocumentEvent.EventType.CHANGE);
969:
970:
971:
972: buffer.change(offset, length, ev);
973:
974: Element root = getDefaultRootElement();
975:
976: int paragraphCount = root.getElementCount();
977: for (int pindex = 0; pindex < paragraphCount; pindex++)
978: {
979: Element paragraph = root.getElement(pindex);
980:
981: if ((paragraph.getStartOffset() > offset + length)
982: || (paragraph.getEndOffset() < offset))
983: continue;
984:
985:
986: int contentCount = paragraph.getElementCount();
987: for (int cindex = 0; cindex < contentCount; cindex++)
988: {
989: Element content = paragraph.getElement(cindex);
990:
991: if ((content.getStartOffset() > offset + length)
992: || (content.getEndOffset() < offset))
993: continue;
994:
995: if (content instanceof AbstractElement)
996: {
997: AbstractElement el = (AbstractElement) content;
998: if (replace)
999: el.removeAttributes(el);
1000: el.addAttributes(attributes);
1001: }
1002: else
1003: throw new AssertionError("content elements are expected to be"
1004: + "instances of "
1005: + "javax.swing.text.AbstractDocument.AbstractElement");
1006: }
1007: }
1008:
1009: fireChangedUpdate(ev);
1010: }
1011:
1012:
1018: public void setLogicalStyle(int position, Style style)
1019: {
1020: Element el = getParagraphElement(position);
1021: if (el instanceof AbstractElement)
1022: {
1023: AbstractElement ael = (AbstractElement) el;
1024: ael.setResolveParent(style);
1025: }
1026: else
1027: throw new AssertionError("paragraph elements are expected to be"
1028: + "instances of javax.swing.text.AbstractDocument.AbstractElement");
1029: }
1030:
1031:
1040: public void setParagraphAttributes(int offset, int length,
1041: AttributeSet attributes,
1042: boolean replace)
1043: {
1044: int index = offset;
1045: while (index < offset + length)
1046: {
1047: AbstractElement par = (AbstractElement) getParagraphElement(index);
1048: AttributeContext ctx = getAttributeContext();
1049: if (replace)
1050: par.removeAttributes(par);
1051: par.addAttributes(attributes);
1052: index = par.getElementCount();
1053: }
1054: }
1055:
1056:
1063: protected void insertUpdate(DefaultDocumentEvent ev, AttributeSet attr)
1064: {
1065: super.insertUpdate(ev, attr);
1066: int offset = ev.getOffset();
1067: int length = ev.getLength();
1068: int endOffset = offset + length;
1069: Segment txt = new Segment();
1070: try
1071: {
1072: getText(offset, length, txt);
1073: }
1074: catch (BadLocationException ex)
1075: {
1076: AssertionError ae = new AssertionError("Unexpected bad location");
1077: ae.initCause(ex);
1078: throw ae;
1079: }
1080:
1081: int len = 0;
1082: Vector specs = new Vector();
1083:
1084: Element prev = getCharacterElement(offset);
1085: Element next = getCharacterElement(endOffset);
1086:
1087: for (int i = offset; i < endOffset; ++i)
1088: {
1089: len++;
1090: if (txt.array[i] == '\n')
1091: {
1092: ElementSpec spec = new ElementSpec(attr, ElementSpec.ContentType,
1093: len);
1094:
1095:
1096:
1097: if (i == endOffset - 1)
1098: {
1099: if (next.getAttributes().isEqual(attr))
1100: spec.setDirection(ElementSpec.JoinNextDirection);
1101: }
1102:
1103:
1104: else if (specs.size() == 0)
1105: {
1106: if (prev.getAttributes().isEqual(attr))
1107: spec.setDirection(ElementSpec.JoinPreviousDirection);
1108: }
1109:
1110: specs.add(spec);
1111:
1112:
1113: ElementSpec endTag = new ElementSpec(null, ElementSpec.EndTagType);
1114: specs.add(endTag);
1115: ElementSpec startTag = new ElementSpec(null,
1116: ElementSpec.StartTagType);
1117: startTag.setDirection(ElementSpec.JoinFractureDirection);
1118: specs.add(startTag);
1119:
1120: len = 0;
1121: offset += len;
1122: }
1123: }
1124:
1125:
1126: if (len > 0)
1127: {
1128: ElementSpec spec = new ElementSpec(attr, ElementSpec.ContentType, len);
1129:
1130:
1131: if (specs.size() == 0)
1132: {
1133: if (prev.getAttributes().isEqual(attr))
1134: spec.setDirection(ElementSpec.JoinPreviousDirection);
1135: }
1136:
1137: else if (next.getAttributes().isEqual(attr))
1138: spec.setDirection(ElementSpec.JoinNextDirection);
1139:
1140: specs.add(spec);
1141: }
1142:
1143: ElementSpec[] elSpecs =
1144: (ElementSpec[]) specs.toArray(new ElementSpec[specs.size()]);
1145:
1146: buffer.insert(offset, length, elSpecs, ev);
1147: }
1148: }