1 7 package javax.swing.text; 8 9 import java.awt.Color ; 10 import java.awt.Component ; 11 import java.awt.Font ; 12 import java.awt.FontMetrics ; 13 import java.awt.font.TextAttribute ; 14 import java.util.Enumeration ; 15 import java.util.Hashtable ; 16 import java.util.Stack ; 17 import java.util.Vector ; 18 import java.util.ArrayList ; 19 import java.io.IOException ; 20 import java.io.ObjectInputStream ; 21 import java.io.ObjectOutputStream ; 22 import java.io.Serializable ; 23 import javax.swing.Icon ; 24 import javax.swing.event.*; 25 import javax.swing.undo.AbstractUndoableEdit ; 26 import javax.swing.undo.CannotRedoException ; 27 import javax.swing.undo.CannotUndoException ; 28 import javax.swing.undo.UndoableEdit ; 29 import javax.swing.SwingUtilities ; 30 31 54 public class DefaultStyledDocument extends AbstractDocument implements StyledDocument { 55 56 63 public DefaultStyledDocument(Content c, StyleContext styles) { 64 super(c, styles); 65 listeningStyles = new Vector (); 66 buffer = new ElementBuffer(createDefaultRoot()); 67 Style defaultStyle = styles.getStyle(StyleContext.DEFAULT_STYLE); 68 setLogicalStyle(0, defaultStyle); 69 } 70 71 77 public DefaultStyledDocument(StyleContext styles) { 78 this(new GapContent (BUFFER_SIZE_DEFAULT), styles); 79 } 80 81 87 public DefaultStyledDocument() { 88 this(new GapContent (BUFFER_SIZE_DEFAULT), new StyleContext ()); 89 } 90 91 97 public Element getDefaultRootElement() { 98 return buffer.getRootElement(); 99 } 100 101 107 protected void create(ElementSpec[] data) { 108 try { 109 if (getLength() != 0) { 110 remove(0, getLength()); 111 } 112 writeLock(); 113 114 Content c = getContent(); 116 int n = data.length; 117 StringBuffer sb = new StringBuffer (); 118 for (int i = 0; i < n; i++) { 119 ElementSpec es = data[i]; 120 if (es.getLength() > 0) { 121 sb.append(es.getArray(), es.getOffset(), es.getLength()); 122 } 123 } 124 UndoableEdit cEdit = c.insertString(0, sb.toString()); 125 126 int length = sb.length(); 128 DefaultDocumentEvent evnt = 129 new DefaultDocumentEvent(0, length, DocumentEvent.EventType.INSERT); 130 evnt.addEdit(cEdit); 131 buffer.create(length, data, evnt); 132 133 super.insertUpdate(evnt, null); 135 136 evnt.end(); 138 fireInsertUpdate(evnt); 139 fireUndoableEditUpdate(new UndoableEditEvent(this, evnt)); 140 } catch (BadLocationException ble) { 141 throw new StateInvariantError ("problem initializing"); 142 } finally { 143 writeUnlock(); 144 } 145 146 } 147 148 165 protected void insert(int offset, ElementSpec[] data) throws BadLocationException { 166 if (data == null || data.length == 0) { 167 return; 168 } 169 170 try { 171 writeLock(); 172 173 Content c = getContent(); 175 int n = data.length; 176 StringBuffer sb = new StringBuffer (); 177 for (int i = 0; i < n; i++) { 178 ElementSpec es = data[i]; 179 if (es.getLength() > 0) { 180 sb.append(es.getArray(), es.getOffset(), es.getLength()); 181 } 182 } 183 if (sb.length() == 0) { 184 return; 186 } 187 UndoableEdit cEdit = c.insertString(offset, sb.toString()); 188 189 int length = sb.length(); 191 DefaultDocumentEvent evnt = 192 new DefaultDocumentEvent(offset, length, DocumentEvent.EventType.INSERT); 193 evnt.addEdit(cEdit); 194 buffer.insert(offset, length, data, evnt); 195 196 super.insertUpdate(evnt, null); 198 199 evnt.end(); 201 fireInsertUpdate(evnt); 202 fireUndoableEditUpdate(new UndoableEditEvent(this, evnt)); 203 } finally { 204 writeUnlock(); 205 } 206 } 207 208 224 public Style addStyle(String nm, Style parent) { 225 StyleContext styles = (StyleContext ) getAttributeContext(); 226 return styles.addStyle(nm, parent); 227 } 228 229 234 public void removeStyle(String nm) { 235 StyleContext styles = (StyleContext ) getAttributeContext(); 236 styles.removeStyle(nm); 237 } 238 239 245 public Style getStyle(String nm) { 246 StyleContext styles = (StyleContext ) getAttributeContext(); 247 return styles.getStyle(nm); 248 } 249 250 251 256 public Enumeration <?> getStyleNames() { 257 return ((StyleContext ) getAttributeContext()).getStyleNames(); 258 } 259 260 276 public void setLogicalStyle(int pos, Style s) { 277 Element paragraph = getParagraphElement(pos); 278 if ((paragraph != null) && (paragraph instanceof AbstractElement)) { 279 try { 280 writeLock(); 281 StyleChangeUndoableEdit edit = new StyleChangeUndoableEdit((AbstractElement)paragraph, s); 282 ((AbstractElement)paragraph).setResolveParent(s); 283 int p0 = paragraph.getStartOffset(); 284 int p1 = paragraph.getEndOffset(); 285 DefaultDocumentEvent e = 286 new DefaultDocumentEvent(p0, p1 - p0, DocumentEvent.EventType.CHANGE); 287 e.addEdit(edit); 288 e.end(); 289 fireChangedUpdate(e); 290 fireUndoableEditUpdate(new UndoableEditEvent(this, e)); 291 } finally { 292 writeUnlock(); 293 } 294 } 295 } 296 297 306 public Style getLogicalStyle(int p) { 307 Style s = null; 308 Element paragraph = getParagraphElement(p); 309 if (paragraph != null) { 310 AttributeSet a = paragraph.getAttributes(); 311 AttributeSet parent = a.getResolveParent(); 312 if (parent instanceof Style ) { 313 s = (Style ) parent; 314 } 315 } 316 return s; 317 } 318 319 336 public void setCharacterAttributes(int offset, int length, AttributeSet s, boolean replace) { 337 if (length == 0) { 338 return; 339 } 340 try { 341 writeLock(); 342 DefaultDocumentEvent changes = 343 new DefaultDocumentEvent(offset, length, DocumentEvent.EventType.CHANGE); 344 345 buffer.change(offset, length, changes); 347 348 AttributeSet sCopy = s.copyAttributes(); 349 350 int lastEnd = Integer.MAX_VALUE; 352 for (int pos = offset; pos < (offset + length); pos = lastEnd) { 353 Element run = getCharacterElement(pos); 354 lastEnd = run.getEndOffset(); 355 if (pos == lastEnd) { 356 break; 358 } 359 MutableAttributeSet attr = (MutableAttributeSet ) run.getAttributes(); 360 changes.addEdit(new AttributeUndoableEdit(run, sCopy, replace)); 361 if (replace) { 362 attr.removeAttributes(attr); 363 } 364 attr.addAttributes(s); 365 } 366 changes.end(); 367 fireChangedUpdate(changes); 368 fireUndoableEditUpdate(new UndoableEditEvent(this, changes)); 369 } finally { 370 writeUnlock(); 371 } 372 373 } 374 375 388 public void setParagraphAttributes(int offset, int length, AttributeSet s, 389 boolean replace) { 390 try { 391 writeLock(); 392 DefaultDocumentEvent changes = 393 new DefaultDocumentEvent(offset, length, DocumentEvent.EventType.CHANGE); 394 395 AttributeSet sCopy = s.copyAttributes(); 396 397 Element section = getDefaultRootElement(); 399 int index0 = section.getElementIndex(offset); 400 int index1 = section.getElementIndex(offset + ((length > 0) ? length - 1 : 0)); 401 boolean isI18N = Boolean.TRUE.equals(getProperty(I18NProperty)); 402 boolean hasRuns = false; 403 for (int i = index0; i <= index1; i++) { 404 Element paragraph = section.getElement(i); 405 MutableAttributeSet attr = (MutableAttributeSet ) paragraph.getAttributes(); 406 changes.addEdit(new AttributeUndoableEdit(paragraph, sCopy, replace)); 407 if (replace) { 408 attr.removeAttributes(attr); 409 } 410 attr.addAttributes(s); 411 if (isI18N && !hasRuns) { 412 hasRuns = (attr.getAttribute(TextAttribute.RUN_DIRECTION) != null); 413 } 414 } 415 416 if (hasRuns) { 417 updateBidi( changes ); 418 } 419 420 changes.end(); 421 fireChangedUpdate(changes); 422 fireUndoableEditUpdate(new UndoableEditEvent(this, changes)); 423 } finally { 424 writeUnlock(); 425 } 426 } 427 428 436 public Element getParagraphElement(int pos) { 437 Element e = null; 438 for (e = getDefaultRootElement(); ! e.isLeaf(); ) { 439 int index = e.getElementIndex(pos); 440 e = e.getElement(index); 441 } 442 if(e != null) 443 return e.getParentElement(); 444 return e; 445 } 446 447 453 public Element getCharacterElement(int pos) { 454 Element e = null; 455 for (e = getDefaultRootElement(); ! e.isLeaf(); ) { 456 int index = e.getElementIndex(pos); 457 e = e.getElement(index); 458 } 459 return e; 460 } 461 462 464 473 protected void insertUpdate(DefaultDocumentEvent chng, AttributeSet attr) { 474 int offset = chng.getOffset(); 475 int length = chng.getLength(); 476 if (attr == null) { 477 attr = SimpleAttributeSet.EMPTY; 478 } 479 480 Element paragraph = getParagraphElement(offset + length); 484 AttributeSet pattr = paragraph.getAttributes(); 485 Element pParagraph = getParagraphElement(offset); 487 Element run = pParagraph.getElement(pParagraph.getElementIndex 488 (offset)); 489 int endOffset = offset + length; 490 boolean insertingAtBoundry = (run.getEndOffset() == endOffset); 491 AttributeSet cattr = run.getAttributes(); 492 493 try { 494 Segment s = new Segment (); 495 Vector parseBuffer = new Vector (); 496 ElementSpec lastStartSpec = null; 497 boolean insertingAfterNewline = false; 498 short lastStartDirection = ElementSpec.OriginateDirection; 499 if (offset > 0) { 501 getText(offset - 1, 1, s); 502 if (s.array[s.offset] == '\n') { 503 insertingAfterNewline = true; 505 lastStartDirection = createSpecsForInsertAfterNewline 506 (paragraph, pParagraph, pattr, parseBuffer, 507 offset, endOffset); 508 for(int counter = parseBuffer.size() - 1; counter >= 0; 509 counter--) { 510 ElementSpec spec = (ElementSpec)parseBuffer. 511 elementAt(counter); 512 if(spec.getType() == ElementSpec.StartTagType) { 513 lastStartSpec = spec; 514 break; 515 } 516 } 517 } 518 } 519 if(!insertingAfterNewline) 522 pattr = pParagraph.getAttributes(); 523 524 getText(offset, length, s); 525 char[] txt = s.array; 526 int n = s.offset + s.count; 527 int lastOffset = s.offset; 528 529 for (int i = s.offset; i < n; i++) { 530 if (txt[i] == '\n') { 531 int breakOffset = i + 1; 532 parseBuffer.addElement( 533 new ElementSpec(attr, ElementSpec.ContentType, 534 breakOffset - lastOffset)); 535 parseBuffer.addElement( 536 new ElementSpec(null, ElementSpec.EndTagType)); 537 lastStartSpec = new ElementSpec(pattr, ElementSpec. 538 StartTagType); 539 parseBuffer.addElement(lastStartSpec); 540 lastOffset = breakOffset; 541 } 542 } 543 if (lastOffset < n) { 544 parseBuffer.addElement( 545 new ElementSpec(attr, ElementSpec.ContentType, 546 n - lastOffset)); 547 } 548 549 ElementSpec first = (ElementSpec) parseBuffer.firstElement(); 550 551 int docLength = getLength(); 552 553 if(first.getType() == ElementSpec.ContentType && 555 cattr.isEqual(attr)) { 556 first.setDirection(ElementSpec.JoinPreviousDirection); 557 } 558 559 if(lastStartSpec != null) { 561 if(insertingAfterNewline) { 562 lastStartSpec.setDirection(lastStartDirection); 563 } 564 else if(pParagraph.getEndOffset() != endOffset) { 568 lastStartSpec.setDirection(ElementSpec. 569 JoinFractureDirection); 570 } 571 else { 574 Element parent = pParagraph.getParentElement(); 575 int pParagraphIndex = parent.getElementIndex(offset); 576 if((pParagraphIndex + 1) < parent.getElementCount() && 577 !parent.getElement(pParagraphIndex + 1).isLeaf()) { 578 lastStartSpec.setDirection(ElementSpec. 579 JoinNextDirection); 580 } 581 } 582 } 583 584 if(insertingAtBoundry && endOffset < docLength) { 590 ElementSpec last = (ElementSpec) parseBuffer.lastElement(); 591 if(last.getType() == ElementSpec.ContentType && 592 last.getDirection() != ElementSpec.JoinPreviousDirection && 593 ((lastStartSpec == null && (paragraph == pParagraph || 594 insertingAfterNewline)) || 595 (lastStartSpec != null && lastStartSpec.getDirection() != 596 ElementSpec.OriginateDirection))) { 597 Element nextRun = paragraph.getElement(paragraph. 598 getElementIndex(endOffset)); 599 if(nextRun.isLeaf() && 601 attr.isEqual(nextRun.getAttributes())) { 602 last.setDirection(ElementSpec.JoinNextDirection); 603 } 604 } 605 } 606 else if(!insertingAtBoundry && lastStartSpec != null && 610 lastStartSpec.getDirection() == 611 ElementSpec.JoinFractureDirection) { 612 ElementSpec last = (ElementSpec) parseBuffer.lastElement(); 613 if(last.getType() == ElementSpec.ContentType && 614 last.getDirection() != ElementSpec.JoinPreviousDirection && 615 attr.isEqual(cattr)) { 616 last.setDirection(ElementSpec.JoinNextDirection); 617 } 618 } 619 620 if (Utilities.isComposedTextAttributeDefined(attr)) { 623 ((MutableAttributeSet )attr).addAttributes(cattr); 624 ((MutableAttributeSet )attr).addAttribute(AbstractDocument.ElementNameAttribute, 625 AbstractDocument.ContentElementName); 626 } 627 628 ElementSpec[] spec = new ElementSpec[parseBuffer.size()]; 629 parseBuffer.copyInto(spec); 630 buffer.insert(offset, length, spec, chng); 631 } catch (BadLocationException bl) { 632 } 633 634 super.insertUpdate( chng, attr ); 635 } 636 637 644 short createSpecsForInsertAfterNewline(Element paragraph, 645 Element pParagraph, AttributeSet pattr, Vector parseBuffer, 646 int offset, int endOffset) { 647 if(paragraph.getParentElement() == pParagraph.getParentElement()) { 649 ElementSpec spec = new ElementSpec(pattr, ElementSpec.EndTagType); 652 parseBuffer.addElement(spec); 653 spec = new ElementSpec(pattr, ElementSpec.StartTagType); 654 parseBuffer.addElement(spec); 655 if(pParagraph.getEndOffset() != endOffset) 656 return ElementSpec.JoinFractureDirection; 657 658 Element parent = pParagraph.getParentElement(); 659 if((parent.getElementIndex(offset) + 1) < parent.getElementCount()) 660 return ElementSpec.JoinNextDirection; 661 } 662 else { 663 Vector leftParents = new Vector (); 666 Vector rightParents = new Vector (); 667 Element e = pParagraph; 668 while(e != null) { 669 leftParents.addElement(e); 670 e = e.getParentElement(); 671 } 672 e = paragraph; 673 int leftIndex = -1; 674 while(e != null && (leftIndex = leftParents.indexOf(e)) == -1) { 675 rightParents.addElement(e); 676 e = e.getParentElement(); 677 } 678 if(e != null) { 679 for(int counter = 0; counter < leftIndex; 682 counter++) { 683 parseBuffer.addElement(new ElementSpec 684 (null, ElementSpec.EndTagType)); 685 } 686 ElementSpec spec = null; 688 for(int counter = rightParents.size() - 1; 689 counter >= 0; counter--) { 690 spec = new ElementSpec(((Element )rightParents. 691 elementAt(counter)).getAttributes(), 692 ElementSpec.StartTagType); 693 if(counter > 0) 694 spec.setDirection(ElementSpec.JoinNextDirection); 695 parseBuffer.addElement(spec); 696 } 697 if(rightParents.size() > 0) 701 return ElementSpec.JoinNextDirection; 702 return ElementSpec.JoinFractureDirection; 705 } 706 } 708 return ElementSpec.OriginateDirection; 709 } 710 711 716 protected void removeUpdate(DefaultDocumentEvent chng) { 717 super.removeUpdate(chng); 718 buffer.remove(chng.getOffset(), chng.getLength(), chng); 719 } 720 721 727 protected AbstractElement createDefaultRoot() { 728 writeLock(); 733 BranchElement section = new SectionElement(); 734 BranchElement paragraph = new BranchElement(section, null); 735 736 LeafElement brk = new LeafElement(paragraph, null, 0, 1); 737 Element [] buff = new Element [1]; 738 buff[0] = brk; 739 paragraph.replace(0, 0, buff); 740 741 buff[0] = paragraph; 742 section.replace(0, 0, buff); 743 writeUnlock(); 744 return section; 745 } 746 747 753 public Color getForeground(AttributeSet attr) { 754 StyleContext styles = (StyleContext ) getAttributeContext(); 755 return styles.getForeground(attr); 756 } 757 758 764 public Color getBackground(AttributeSet attr) { 765 StyleContext styles = (StyleContext ) getAttributeContext(); 766 return styles.getBackground(attr); 767 } 768 769 775 public Font getFont(AttributeSet attr) { 776 StyleContext styles = (StyleContext ) getAttributeContext(); 777 return styles.getFont(attr); 778 } 779 780 786 protected void styleChanged(Style style) { 787 if (getLength() != 0) { 789 if (updateRunnable == null) { 791 updateRunnable = new ChangeUpdateRunnable(); 792 } 793 794 synchronized(updateRunnable) { 797 if (!updateRunnable.isPending) { 798 SwingUtilities.invokeLater(updateRunnable); 799 updateRunnable.isPending = true; 800 } 801 } 802 } 803 } 804 805 811 public void addDocumentListener(DocumentListener listener) { 812 synchronized(listeningStyles) { 813 int oldDLCount = listenerList.getListenerCount 814 (DocumentListener.class); 815 super.addDocumentListener(listener); 816 if (oldDLCount == 0) { 817 if (styleContextChangeListener == null) { 818 styleContextChangeListener = 819 createStyleContextChangeListener(); 820 } 821 if (styleContextChangeListener != null) { 822 StyleContext styles = (StyleContext )getAttributeContext(); 823 styles.addChangeListener(styleContextChangeListener); 824 } 825 updateStylesListeningTo(); 826 } 827 } 828 } 829 830 836 public void removeDocumentListener(DocumentListener listener) { 837 synchronized(listeningStyles) { 838 super.removeDocumentListener(listener); 839 if (listenerList.getListenerCount(DocumentListener.class) == 0) { 840 for (int counter = listeningStyles.size() - 1; counter >= 0; 841 counter--) { 842 ((Style )listeningStyles.elementAt(counter)). 843 removeChangeListener(styleChangeListener); 844 } 845 listeningStyles.removeAllElements(); 846 if (styleContextChangeListener != null) { 847 StyleContext styles = (StyleContext )getAttributeContext(); 848 styles.removeChangeListener(styleContextChangeListener); 849 } 850 } 851 } 852 } 853 854 857 ChangeListener createStyleChangeListener() { 858 return new StyleChangeHandler(); 859 } 860 861 864 ChangeListener createStyleContextChangeListener() { 865 return new StyleContextChangeHandler(); 866 } 867 868 872 void updateStylesListeningTo() { 873 synchronized(listeningStyles) { 874 StyleContext styles = (StyleContext )getAttributeContext(); 875 if (styleChangeListener == null) { 876 styleChangeListener = createStyleChangeListener(); 877 } 878 if (styleChangeListener != null && styles != null) { 879 Enumeration styleNames = styles.getStyleNames(); 880 Vector v = (Vector )listeningStyles.clone(); 881 listeningStyles.removeAllElements(); 882 while (styleNames.hasMoreElements()) { 883 String name = (String )styleNames.nextElement(); 884 Style aStyle = styles.getStyle(name); 885 int index = v.indexOf(aStyle); 886 listeningStyles.addElement(aStyle); 887 if (index == -1) { 888 aStyle.addChangeListener(styleChangeListener); 889 } 890 else { 891 v.removeElementAt(index); 892 } 893 } 894 for (int counter = v.size() - 1; counter >= 0; counter--) { 895 Style aStyle = (Style )v.elementAt(counter); 896 aStyle.removeChangeListener(styleChangeListener); 897 } 898 if (listeningStyles.size() == 0) { 899 styleChangeListener = null; 900 } 901 } 902 } 903 } 904 905 private void readObject(ObjectInputStream s) 906 throws ClassNotFoundException , IOException { 907 listeningStyles = new Vector (); 908 s.defaultReadObject(); 909 if (styleContextChangeListener == null && 911 listenerList.getListenerCount(DocumentListener.class) > 0) { 912 styleContextChangeListener = createStyleContextChangeListener(); 913 if (styleContextChangeListener != null) { 914 StyleContext styles = (StyleContext )getAttributeContext(); 915 styles.addChangeListener(styleContextChangeListener); 916 } 917 updateStylesListeningTo(); 918 } 919 } 920 921 923 926 public static final int BUFFER_SIZE_DEFAULT = 4096; 927 928 protected ElementBuffer buffer; 929 930 931 private transient Vector listeningStyles; 932 933 934 private transient ChangeListener styleChangeListener; 935 936 937 private transient ChangeListener styleContextChangeListener; 938 939 940 private transient ChangeUpdateRunnable updateRunnable; 941 942 955 protected class SectionElement extends BranchElement { 956 957 960 public SectionElement() { 961 super(null, null); 962 } 963 964 969 public String getName() { 970 return SectionElementName; 971 } 972 } 973 974 986 public static class ElementSpec { 987 988 994 public static final short StartTagType = 1; 995 996 1002 public static final short EndTagType = 2; 1003 1004 1008 public static final short ContentType = 3; 1009 1010 1015 public static final short JoinPreviousDirection = 4; 1016 1017 1022 public static final short JoinNextDirection = 5; 1023 1024 1030 public static final short OriginateDirection = 6; 1031 1032 1037 public static final short JoinFractureDirection = 7; 1038 1039 1040 1048 public ElementSpec(AttributeSet a, short type) { 1049 this(a, type, null, 0, 0); 1050 } 1051 1052 1062 public ElementSpec(AttributeSet a, short type, int len) { 1063 this(a, type, null, 0, len); 1064 } 1065 1066 1077 public ElementSpec(AttributeSet a, short type, char[] txt, 1078 int offs, int len) { 1079 attr = a; 1080 this.type = type; 1081 this.data = txt; 1082 this.offs = offs; 1083 this.len = len; 1084 this.direction = OriginateDirection; 1085 } 1086 1087 1093 public void setType(short type) { 1094 this.type = type; 1095 } 1096 1097 1103 public short getType() { 1104 return type; 1105 } 1106 1107 1113 public void setDirection(short direction) { 1114 this.direction = direction; 1115 } 1116 1117 1122 public short getDirection() { 1123 return direction; 1124 } 1125 1126 1131 public AttributeSet getAttributes() { 1132 return attr; 1133 } 1134 1135 1140 public char[] getArray() { 1141 return data; 1142 } 1143 1144 1145 1150 public int getOffset() { 1151 return offs; 1152 } 1153 1154 1159 public int getLength() { 1160 return len; 1161 } 1162 1163 1168 public String toString() { 1169 String tlbl = "??"; 1170 String plbl = "??"; 1171 switch(type) { 1172 case StartTagType: 1173 tlbl = "StartTag"; 1174 break; 1175 case ContentType: 1176 tlbl = "Content"; 1177 break; 1178 case EndTagType: 1179 tlbl = "EndTag"; 1180 break; 1181 } 1182 switch(direction) { 1183 case JoinPreviousDirection: 1184 plbl = "JoinPrevious"; 1185 break; 1186 case JoinNextDirection: 1187 plbl = "JoinNext"; 1188 break; 1189 case OriginateDirection: 1190 plbl = "Originate"; 1191 break; 1192 case JoinFractureDirection: 1193 plbl = "Fracture"; 1194 break; 1195 } 1196 return tlbl + ":" + plbl + ":" + getLength(); 1197 } 1198 1199 private AttributeSet attr; 1200 private int len; 1201 private short type; 1202 private short direction; 1203 1204 private int offs; 1205 private char[] data; 1206 } 1207 1208 1221 public class ElementBuffer implements Serializable { 1222 1223 1228 public ElementBuffer(Element root) { 1229 this.root = root; 1230 changes = new Vector (); 1231 path = new Stack (); 1232 } 1233 1234 1239 public Element getRootElement() { 1240 return root; 1241 } 1242 1243 1251 public void insert(int offset, int length, ElementSpec[] data, 1252 DefaultDocumentEvent de) { 1253 if (length == 0) { 1254 return; 1256 } 1257 insertOp = true; 1258 beginEdits(offset, length); 1259 insertUpdate(data); 1260 endEdits(de); 1261 1262 insertOp = false; 1263 } 1264 1265 void create(int length, ElementSpec[] data, DefaultDocumentEvent de) { 1266 insertOp = true; 1267 beginEdits(offset, length); 1268 1269 1274 Element elem = root; 1276 int index = elem.getElementIndex(0); 1277 while (! elem.isLeaf()) { 1278 Element child = elem.getElement(index); 1279 push(elem, index); 1280 elem = child; 1281 index = elem.getElementIndex(0); 1282 } 1283 ElemChanges ec = (ElemChanges) path.peek(); 1284 Element child = ec.parent.getElement(ec.index); 1285 ec.added.addElement(createLeafElement(ec.parent, 1286 child.getAttributes(), getLength(), 1287 child.getEndOffset())); 1288 ec.removed.addElement(child); 1289 while (path.size() > 1) { 1290 pop(); 1291 } 1292 1293 int n = data.length; 1294 1295 AttributeSet newAttrs = null; 1297 if (n > 0 && data[0].getType() == ElementSpec.StartTagType) { 1298 newAttrs = data[0].getAttributes(); 1299 } 1300 if (newAttrs == null) { 1301 newAttrs = SimpleAttributeSet.EMPTY; 1302 } 1303 MutableAttributeSet attr = (MutableAttributeSet )root. 1304 getAttributes(); 1305 de.addEdit(new AttributeUndoableEdit(root, newAttrs, true)); 1306 attr.removeAttributes(attr); 1307 attr.addAttributes(newAttrs); 1308 1309 for (int i = 1; i < n; i++) { 1311 insertElement(data[i]); 1312 } 1313 1314 while (path.size() != 0) { 1316 pop(); 1317 } 1318 1319 endEdits(de); 1320 insertOp = false; 1321 } 1322 1323 1330 public void remove(int offset, int length, DefaultDocumentEvent de) { 1331 beginEdits(offset, length); 1332 removeUpdate(); 1333 endEdits(de); 1334 } 1335 1336 1343 public void change(int offset, int length, DefaultDocumentEvent de) { 1344 beginEdits(offset, length); 1345 changeUpdate(); 1346 endEdits(de); 1347 } 1348 1349 1354 protected void insertUpdate(ElementSpec[] data) { 1355 Element elem = root; 1357 int index = elem.getElementIndex(offset); 1358 while (! elem.isLeaf()) { 1359 Element child = elem.getElement(index); 1360 push(elem, (child.isLeaf() ? index : index+1)); 1361 elem = child; 1362 index = elem.getElementIndex(offset); 1363 } 1364 1365 insertPath = new ElemChanges[path.size()]; 1367 path.copyInto(insertPath); 1368 1369 createdFracture = false; 1371 1372 int i; 1374 1375 recreateLeafs = false; 1376 if(data[0].getType() == ElementSpec.ContentType) { 1377 insertFirstContent(data); 1378 pos += data[0].getLength(); 1379 i = 1; 1380 } 1381 else { 1382 fractureDeepestLeaf(data); 1383 i = 0; 1384 } 1385 1386 int n = data.length; 1388 for (; i < n; i++) { 1389 insertElement(data[i]); 1390 } 1391 1392 if(!createdFracture) 1394 fracture(-1); 1395 1396 while (path.size() != 0) { 1398 pop(); 1399 } 1400 1401 if(offsetLastIndex && offsetLastIndexOnReplace) { 1403 insertPath[insertPath.length - 1].index++; 1404 } 1405 1406 for(int counter = insertPath.length - 1; counter >= 0; 1409 counter--) { 1410 ElemChanges change = insertPath[counter]; 1411 if(change.parent == fracturedParent) 1412 change.added.addElement(fracturedChild); 1413 if((change.added.size() > 0 || 1414 change.removed.size() > 0) && !changes.contains(change)) { 1415 changes.addElement(change); 1417 } 1418 } 1419 1420 if (offset == 0 && fracturedParent != null && 1424 data[0].getType() == ElementSpec.EndTagType) { 1425 int counter = 0; 1426 while (counter < data.length && 1427 data[counter].getType() == ElementSpec.EndTagType) { 1428 counter++; 1429 } 1430 ElemChanges change = insertPath[insertPath.length - 1431 counter - 1]; 1432 change.removed.insertElementAt(change.parent.getElement 1433 (--change.index), 0); 1434 } 1435 } 1436 1437 1442 protected void removeUpdate() { 1443 removeElements(root, offset, offset + length); 1444 } 1445 1446 1450 protected void changeUpdate() { 1451 boolean didEnd = split(offset, length); 1452 if (! didEnd) { 1453 while (path.size() != 0) { 1455 pop(); 1456 } 1457 split(offset + length, 0); 1458 } 1459 while (path.size() != 0) { 1460 pop(); 1461 } 1462 } 1463 1464 boolean split(int offs, int len) { 1465 boolean splitEnd = false; 1466 Element e = root; 1468 int index = e.getElementIndex(offs); 1469 while (! e.isLeaf()) { 1470 push(e, index); 1471 e = e.getElement(index); 1472 index = e.getElementIndex(offs); 1473 } 1474 1475 ElemChanges ec = (ElemChanges) path.peek(); 1476 Element child = ec.parent.getElement(ec.index); 1477 if (child.getStartOffset() < offs && offs < child.getEndOffset()) { 1481 int index0 = ec.index; 1484 int index1 = index0; 1485 if (((offs + len) < ec.parent.getEndOffset()) && (len != 0)) { 1486 index1 = ec.parent.getElementIndex(offs+len); 1488 if (index1 == index0) { 1489 ec.removed.addElement(child); 1491 e = createLeafElement(ec.parent, child.getAttributes(), 1492 child.getStartOffset(), offs); 1493 ec.added.addElement(e); 1494 e = createLeafElement(ec.parent, child.getAttributes(), 1495 offs, offs + len); 1496 ec.added.addElement(e); 1497 e = createLeafElement(ec.parent, child.getAttributes(), 1498 offs + len, child.getEndOffset()); 1499 ec.added.addElement(e); 1500 return true; 1501 } else { 1502 child = ec.parent.getElement(index1); 1503 if ((offs + len) == child.getStartOffset()) { 1504 index1 = index0; 1506 } 1507 } 1508 splitEnd = true; 1509 } 1510 1511 pos = offs; 1513 child = ec.parent.getElement(index0); 1514 ec.removed.addElement(child); 1515 e = createLeafElement(ec.parent, child.getAttributes(), 1516 child.getStartOffset(), pos); 1517 ec.added.addElement(e); 1518 e = createLeafElement(ec.parent, child.getAttributes(), 1519 pos, child.getEndOffset()); 1520 ec.added.addElement(e); 1521 1522 for (int i = index0 + 1; i < index1; i++) { 1524 child = ec.parent.getElement(i); 1525 ec.removed.addElement(child); 1526 ec.added.addElement(child); 1527 } 1528 1529 if (index1 != index0) { 1530 child = ec.parent.getElement(index1); 1531 pos = offs + len; 1532 ec.removed.addElement(child); 1533 e = createLeafElement(ec.parent, child.getAttributes(), 1534 child.getStartOffset(), pos); 1535 ec.added.addElement(e); 1536 e = createLeafElement(ec.parent, child.getAttributes(), 1537 pos, child.getEndOffset()); 1538 ec.added.addElement(e); 1539 } 1540 } 1541 return splitEnd; 1542 } 1543 1544 1548 void endEdits(DefaultDocumentEvent de) { 1549 int n = changes.size(); 1550 for (int i = 0; i < n; i++) { 1551 ElemChanges ec = (ElemChanges) changes.elementAt(i); 1552 Element [] removed = new Element [ec.removed.size()]; 1553 ec.removed.copyInto(removed); 1554 Element [] added = new Element [ec.added.size()]; 1555 ec.added.copyInto(added); 1556 int index = ec.index; 1557 ((BranchElement) ec.parent).replace(index, removed.length, added); 1558 ElementEdit ee = new ElementEdit((BranchElement) ec.parent, 1559 index, removed, added); 1560 de.addEdit(ee); 1561 } 1562 1563 changes.removeAllElements(); 1564 path.removeAllElements(); 1565 1566 1585 } 1586 1587 1590 void beginEdits(int offset, int length) { 1591 this.offset = offset; 1592 this.length = length; 1593 this.endOffset = offset + length; 1594 pos = offset; 1595 if (changes == null) { 1596 changes = new Vector (); 1597 } else { 1598 changes.removeAllElements(); 1599 } 1600 if (path == null) { 1601 path = new Stack (); 1602 } else { 1603 path.removeAllElements(); 1604 } 1605 fracturedParent = null; 1606 fracturedChild = null; 1607 offsetLastIndex = offsetLastIndexOnReplace = false; 1608 } 1609 1610 1618 void push(Element e, int index, boolean isFracture) { 1619 ElemChanges ec = new ElemChanges(e, index, isFracture); 1620 path.push(ec); 1621 } 1622 1623 void push(Element e, int index) { 1624 push(e, index, false); 1625 } 1626 1627 void pop() { 1628 ElemChanges ec = (ElemChanges) path.peek(); 1629 path.pop(); 1630 if ((ec.added.size() > 0) || (ec.removed.size() > 0)) { 1631 changes.addElement(ec); 1632 } else if (! path.isEmpty()) { 1633 Element e = ec.parent; 1634 if(e.getElementCount() == 0) { 1635 ec = (ElemChanges) path.peek(); 1638 ec.added.removeElement(e); 1639 } 1640 } 1641 } 1642 1643 1646 void advance(int n) { 1647 pos += n; 1648 } 1649 1650 void insertElement(ElementSpec es) { 1651 ElemChanges ec = (ElemChanges) path.peek(); 1652 switch(es.getType()) { 1653 case ElementSpec.StartTagType: 1654 switch(es.getDirection()) { 1655 case ElementSpec.JoinNextDirection: 1656 Element parent = ec.parent.getElement(ec.index); 1659 1660 if(parent.isLeaf()) { 1661 if((ec.index + 1) < ec.parent.getElementCount()) 1664 parent = ec.parent.getElement(ec.index + 1); 1665 else 1666 throw new StateInvariantError ("Join next to leaf"); 1667 } 1668 push(parent, 0, true); 1673 break; 1674 case ElementSpec.JoinFractureDirection: 1675 if(!createdFracture) { 1676 fracture(path.size() - 1); 1678 } 1679 if(!ec.isFracture) { 1682 push(fracturedChild, 0, true); 1683 } 1684 else 1685 push(ec.parent.getElement(0), 0, true); 1687 break; 1688 default: 1689 Element belem = createBranchElement(ec.parent, 1690 es.getAttributes()); 1691 ec.added.addElement(belem); 1692 push(belem, 0); 1693 break; 1694 } 1695 break; 1696 case ElementSpec.EndTagType: 1697 pop(); 1698 break; 1699 case ElementSpec.ContentType: 1700 int len = es.getLength(); 1701 if (es.getDirection() != ElementSpec.JoinNextDirection) { 1702 Element leaf = createLeafElement(ec.parent, es.getAttributes(), 1703 pos, pos + len); 1704 ec.added.addElement(leaf); 1705 } 1706 else { 1707 if(!ec.isFracture) { 1713 Element first = null; 1714 if(insertPath != null) { 1715 for(int counter = insertPath.length - 1; 1716 counter >= 0; counter--) { 1717 if(insertPath[counter] == ec) { 1718 if(counter != (insertPath.length - 1)) 1719 first = ec.parent.getElement(ec.index); 1720 break; 1721 } 1722 } 1723 } 1724 if(first == null) 1725 first = ec.parent.getElement(ec.index + 1); 1726 Element leaf = createLeafElement(ec.parent, first. 1727 getAttributes(), pos, first.getEndOffset()); 1728 ec.added.addElement(leaf); 1729 ec.removed.addElement(first); 1730 } 1731 else { 1732 Element first = ec.parent.getElement(0); 1734 Element leaf = createLeafElement(ec.parent, first. 1735 getAttributes(), pos, first.getEndOffset()); 1736 ec.added.addElement(leaf); 1737 ec.removed.addElement(first); 1738 } 1739 } 1740 pos += len; 1741 break; 1742 } 1743 } 1744 1745 1753 boolean removeElements(Element elem, int rmOffs0, int rmOffs1) { 1754 if (! elem.isLeaf()) { 1755 int index0 = elem.getElementIndex(rmOffs0); 1757 int index1 = elem.getElementIndex(rmOffs1); 1758 push(elem, index0); 1759 ElemChanges ec = (ElemChanges)path.peek(); 1760 1761 if (index0 == index1) { 1764 Element child0 = elem.getElement(index0); 1765 if(rmOffs0 <= child0.getStartOffset() && 1766 rmOffs1 >= child0.getEndOffset()) { 1767 ec.removed.addElement(child0); 1769 } 1770 else if(removeElements(child0, rmOffs0, rmOffs1)) { 1771 ec.removed.addElement(child0); 1772 } 1773 } else { 1774 Element child0 = elem.getElement(index0); 1778 Element child1 = elem.getElement(index1); 1779 boolean containsOffs1 = (rmOffs1 < elem.getEndOffset()); 1780 if (containsOffs1 && canJoin(child0, child1)) { 1781 for (int i = index0; i <= index1; i++) { 1783 ec.removed.addElement(elem.getElement(i)); 1784 } 1785 Element e = join(elem, child0, child1, rmOffs0, rmOffs1); 1786 ec.added.addElement(e); 1787 } else { 1788 int rmIndex0 = index0 + 1; 1790 int rmIndex1 = index1 - 1; 1791 if (child0.getStartOffset() == rmOffs0 || 1792 (index0 == 0 && 1793 child0.getStartOffset() > rmOffs0 && 1794 child0.getEndOffset() <= rmOffs1)) { 1795 child0 = null; 1797 rmIndex0 = index0; 1798 } 1799 if (!containsOffs1) { 1800 child1 = null; 1801 rmIndex1++; 1802 } 1803 else if (child1.getStartOffset() == rmOffs1) { 1804 child1 = null; 1806 } 1807 if (rmIndex0 <= rmIndex1) { 1808 ec.index = rmIndex0; 1809 } 1810 for (int i = rmIndex0; i <= rmIndex1; i++) { 1811 ec.removed.addElement(elem.getElement(i)); 1812 } 1813 if (child0 != null) { 1814 if(removeElements(child0, rmOffs0, rmOffs1)) { 1815 ec.removed.insertElementAt(child0, 0); 1816 ec.index = index0; 1817 } 1818 } 1819 if (child1 != null) { 1820 if(removeElements(child1, rmOffs0, rmOffs1)) { 1821 ec.removed.addElement(child1); 1822 } 1823 } 1824 } 1825 } 1826 1827 pop(); 1829 1830 if(elem.getElementCount() == (ec.removed.size() - 1832 ec.added.size())) { 1833 return true; 1834 } 1835 } 1836 return false; 1837 } 1838 1839 1843 boolean canJoin(Element e0, Element e1) { 1844 if ((e0 == null) || (e1 == null)) { 1845 return false; 1846 } 1847 boolean leaf0 = e0.isLeaf(); 1849 boolean leaf1 = e1.isLeaf(); 1850 if(leaf0 != leaf1) { 1851 return false; 1852 } 1853 if (leaf0) { 1854 return e0.getAttributes().isEqual(e1.getAttributes()); 1857 } 1858 String name0 = e0.getName(); 1862 String name1 = e1.getName(); 1863 if (name0 != null) { 1864 return name0.equals(name1); 1865 } 1866 if (name1 != null) { 1867 return name1.equals(name0); 1868 } 1869 return true; 1871 } 1872 1873 1877 Element join(Element p, Element left, Element right, int rmOffs0, int rmOffs1) { 1878 if (left.isLeaf() && right.isLeaf()) { 1879 return createLeafElement(p, left.getAttributes(), left.getStartOffset(), 1880 right.getEndOffset()); 1881 } else if ((!left.isLeaf()) && (!right.isLeaf())) { 1882 Element to = createBranchElement(p, left.getAttributes()); 1887 int ljIndex = left.getElementIndex(rmOffs0); 1888 int rjIndex = right.getElementIndex(rmOffs1); 1889 Element lj = left.getElement(ljIndex); 1890 if (lj.getStartOffset() >= rmOffs0) { 1891 lj = null; 1892 } 1893 Element rj = right.getElement(rjIndex); 1894 if (rj.getStartOffset() == rmOffs1) { 1895 rj = null; 1896 } 1897 Vector children = new Vector (); 1898 1899 for (int i = 0; i < ljIndex; i++) { 1901 children.addElement(clone(to, left.getElement(i))); 1902 } 1903 1904 if (canJoin(lj, rj)) { 1906 Element e = join(to, lj, rj, rmOffs0, rmOffs1); 1907 children.addElement(e); 1908 } else { 1909 if (lj != null) { 1910 children.addElement(cloneAsNecessary(to, lj, rmOffs0, rmOffs1)); 1911 } 1912 if (rj != null) { 1913 children.addElement(cloneAsNecessary(to, rj, rmOffs0, rmOffs1)); 1914 } 1915 } 1916 1917 int n = right.getElementCount(); 1919 for (int i = (rj == null) ? rjIndex : rjIndex + 1; i < n; i++) { 1920 children.addElement(clone(to, right.getElement(i))); 1921 } 1922 1923 Element [] c = new Element [children.size()]; 1925 children.copyInto(c); 1926 ((BranchElement)to).replace(0, 0, c); 1927 return to; 1928 } else { 1929 throw new StateInvariantError ( 1930 "No support to join leaf element with non-leaf element"); 1931 } 1932 } 1933 1934 1942 public Element clone(Element parent, Element clonee) { 1943 if (clonee.isLeaf()) { 1944 return createLeafElement(parent, clonee.getAttributes(), 1945 clonee.getStartOffset(), 1946 clonee.getEndOffset()); 1947 } 1948 Element e = createBranchElement(parent, clonee.getAttributes()); 1949 int n = clonee.getElementCount(); 1950 Element [] children = new Element [n]; 1951 for (int i = 0; i < n; i++) { 1952 children[i] = clone(e, clonee.getElement(i)); 1953 } 1954 ((BranchElement)e).replace(0, 0, children); 1955 return e; 1956 } 1957 1958 1963 Element cloneAsNecessary(Element parent, Element clonee, int rmOffs0, int rmOffs1) { 1964 if (clonee.isLeaf()) { 1965 return createLeafElement(parent, clonee.getAttributes(), 1966 clonee.getStartOffset(), 1967 clonee.getEndOffset()); 1968 } 1969 Element e = createBranchElement(parent, clonee.getAttributes()); 1970 int n = clonee.getElementCount(); 1971 ArrayList childrenList = new ArrayList (n); 1972 for (int i = 0; i < n; i++) { 1973 Element elem = clonee.getElement(i); 1974 if (elem.getStartOffset() < rmOffs0 || elem.getEndOffset() > rmOffs1) { 1975 childrenList.add(cloneAsNecessary(e, elem, rmOffs0, rmOffs1)); 1976 } 1977 } 1978 Element [] children = new Element [childrenList.size()]; 1979 children = (Element [])childrenList.toArray(children); 1980 ((BranchElement)e).replace(0, 0, children); 1981 return e; 1982 } 1983 1984 1995 void fracture(int depth) { 1996 int cLength = insertPath.length; 1997 int lastIndex = -1; 1998 boolean needRecreate = recreateLeafs; 1999 ElemChanges lastChange = insertPath[cLength - 1]; 2000 boolean childAltered = ((lastChange.index + 1) < 2003 lastChange.parent.getElementCount()); 2004 int deepestAlteredIndex = (needRecreate) ? cLength : -1; 2005 int lastAlteredIndex = cLength - 1; 2006 2007 createdFracture = true; 2008 for(int counter = cLength - 2; counter >= 0; counter--) { 2012 ElemChanges change = insertPath[counter]; 2013 if(change.added.size() > 0 || counter == depth) { 2014 lastIndex = counter; 2015 if(!needRecreate && childAltered) { 2016 needRecreate = true; 2017 if(deepestAlteredIndex == -1) 2018 deepestAlteredIndex = lastAlteredIndex + 1; 2019 } 2020 } 2021 if(!childAltered && change.index < 2022 change.parent.getElementCount()) { 2023 childAltered = true; 2024 lastAlteredIndex = counter; 2025 } 2026 } 2027 if(needRecreate) { 2028 if(lastIndex == -1) 2031 lastIndex = cLength - 1; 2032 fractureFrom(insertPath, lastIndex, deepestAlteredIndex); 2033 } 2034 } 2035 2036 2045 void fractureFrom(ElemChanges[] changed, int startIndex, 2046 int endFractureIndex) { 2047 ElemChanges change = changed[startIndex]; 2049 Element child; 2050 Element newChild; 2051 int changeLength = changed.length; 2052 2053 if((startIndex + 1) == changeLength) 2054 child = change.parent.getElement(change.index); 2055 else 2056 child = change.parent.getElement(change.index - 1); 2057 if(child.isLeaf()) { 2058 newChild = createLeafElement(change.parent, 2059 child.getAttributes(), Math.max(endOffset, 2060 child.getStartOffset()), child.getEndOffset()); 2061 } 2062 else { 2063 newChild = createBranchElement(change.parent, 2064 child.getAttributes()); 2065 } 2066 fracturedParent = change.parent; 2067 fracturedChild = newChild; 2068 2069 Element parent = newChild; 2072 2073 while(++startIndex < endFractureIndex) { 2074 boolean isEnd = ((startIndex + 1) == endFractureIndex); 2075 boolean isEndLeaf = ((startIndex + 1) == changeLength); 2076 2077 change = changed[startIndex]; 2081 2082 if(isEnd) { 2085 if(offsetLastIndex || !isEndLeaf) 2086 child = null; 2087 else 2088 child = change.parent.getElement(change.index); 2089 } 2090 else { 2091 child = change.parent.getElement(change.index - 1); 2092 } 2093 if(child != null) { 2095 if(child.isLeaf()) { 2096 newChild = createLeafElement(parent, 2097 child.getAttributes(), Math.max(endOffset, 2098 child.getStartOffset()), child.getEndOffset()); 2099 } 2100 else { 2101 newChild = createBranchElement(parent, 2102 child.getAttributes()); 2103 } 2104 } 2105 else 2106 newChild = null; 2107 2108 int kidsToMove = change.parent.getElementCount() - 2110 change.index; 2111 Element [] kids; 2112 int moveStartIndex; 2113 int kidStartIndex = 1; 2114 2115 if(newChild == null) { 2116 if(isEndLeaf) { 2118 kidsToMove--; 2119 moveStartIndex = change.index + 1; 2120 } 2121 else { 2122 moveStartIndex = change.index; 2123 } 2124 kidStartIndex = 0; 2125 kids = new Element [kidsToMove]; 2126 } 2127 else { 2128 if(!isEnd) { 2129 kidsToMove++; 2131 moveStartIndex = change.index; 2132 } 2133 else { 2134 moveStartIndex = change.index + 1; 2136 } 2137 kids = new Element [kidsToMove]; 2138 kids[0] = newChild; 2139 } 2140 2141 for(int counter = kidStartIndex; counter < kidsToMove; 2142 counter++) { 2143 Element toMove =change.parent.getElement(moveStartIndex++); 2144 kids[counter] = recreateFracturedElement(parent, toMove); 2145 change.removed.addElement(toMove); 2146 } 2147 ((BranchElement)parent).replace(0, 0, kids); 2148 parent = newChild; 2149 } 2150 } 2151 2152 2158 Element recreateFracturedElement(Element parent, Element toDuplicate) { 2159 if(toDuplicate.isLeaf()) { 2160 return createLeafElement(parent, toDuplicate.getAttributes(), 2161 Math.max(toDuplicate.getStartOffset(), 2162 endOffset), 2163 toDuplicate.getEndOffset()); 2164 } 2165 Element newParent = createBranchElement(parent, toDuplicate. 2167 getAttributes()); 2168 int childCount = toDuplicate.getElementCount(); 2169 Element [] newKids = new Element [childCount]; 2170 for(int counter = 0; counter < childCount; counter++) { 2171 newKids[counter] = recreateFracturedElement(newParent, 2172 toDuplicate.getElement(counter)); 2173 } 2174 ((BranchElement)newParent).replace(0, 0, newKids); 2175 return newParent; 2176 } 2177 2178 2182 void fractureDeepestLeaf(ElementSpec[] specs) { 2183 ElemChanges ec = (ElemChanges) path.peek(); 2185 Element child = ec.parent.getElement(ec.index); 2186 if (offset != 0) { 2189 Element newChild = createLeafElement(ec.parent, 2190 child.getAttributes(), 2191 child.getStartOffset(), 2192 offset); 2193 2194 ec.added.addElement(newChild); 2195 } 2196 ec.removed.addElement(child); 2197 if(child.getEndOffset() != endOffset) 2198 recreateLeafs = true; 2199 else 2200 offsetLastIndex = true; 2201 } 2202 2203 2207 void insertFirstContent(ElementSpec[] specs) { 2208 ElementSpec firstSpec = specs[0]; 2209 ElemChanges ec = (ElemChanges) path.peek(); 2210 Element child = ec.parent.getElement(ec.index); 2211 int firstEndOffset = offset + firstSpec.getLength(); 2212 boolean isOnlyContent = (specs.length == 1); 2213 2214 switch(firstSpec.getDirection()) { 2215 case ElementSpec.JoinPreviousDirection: 2216 if(child.getEndOffset() != firstEndOffset && 2217 !isOnlyContent) { 2218 Element newE = createLeafElement(ec.parent, 2220 child.getAttributes(), child.getStartOffset(), 2221 firstEndOffset); 2222 ec.added.addElement(newE); 2223 ec.removed.addElement(child); 2224 if(child.getEndOffset() != endOffset) 2226 recreateLeafs = true; 2227 else 2228 offsetLastIndex = true; 2229 } 2230 else { 2231 offsetLastIndex = true; 2232 offsetLastIndexOnReplace = true; 2233 } 2234 break; 2237 case ElementSpec.JoinNextDirection: 2238 if(offset != 0) { 2239 Element newE = createLeafElement(ec.parent, 2242 child.getAttributes(), child.getStartOffset(), 2243 offset); 2244 ec.added.addElement(newE); 2245 Element nextChild = ec.parent.getElement(ec.index + 1); 2248 if(isOnlyContent) 2249 newE = createLeafElement(ec.parent, nextChild. 2250 getAttributes(), offset, nextChild.getEndOffset()); 2251 else 2252 newE = createLeafElement(ec.parent, nextChild. 2253 getAttributes(), offset, firstEndOffset); 2254 ec.added.addElement(newE); 2255 ec.removed.addElement(child); 2256 ec.removed.addElement(nextChild); 2257 } 2258 break; 2261 default: 2262 if(child.getStartOffset() != offset) { 2265 Element newE = createLeafElement(ec.parent, 2266 child.getAttributes(), child.getStartOffset(), 2267 offset); 2268 ec.added.addElement(newE); 2269 } 2270 ec.removed.addElement(child); 2271 Element newE = createLeafElement(ec.parent, 2273 firstSpec.getAttributes(), 2274 offset, firstEndOffset); 2275 ec.added.addElement(newE); 2276 if(child.getEndOffset() != endOffset) { 2277 recreateLeafs = true; 2279 } 2280 else { 2281 offsetLastIndex = true; 2282 } 2283 break; 2284 } 2285 } 2286 2287 Element root; 2288 transient int pos; transient int offset; 2290 transient int length; 2291 transient int endOffset; 2292 transient Vector changes; transient Stack path; transient boolean insertOp; 2295 2296 transient boolean recreateLeafs; 2298 2299 transient ElemChanges[] insertPath; 2300 2301 transient boolean createdFracture; 2302 2303 transient Element fracturedParent; 2304 2305 transient Element fracturedChild; 2306 2308 transient boolean offsetLastIndex; 2309 2312 transient boolean offsetLastIndexOnReplace; 2313 2314 2317 class ElemChanges { 2318 2319 ElemChanges(Element parent, int index, boolean isFracture) { 2320 this.parent = parent; 2321 this.index = index; 2322 this.isFracture = isFracture; 2323 added = new Vector (); 2324 removed = new Vector (); 2325 } 2326 2327 public String toString() { 2328 return "added: " + added + "\nremoved: " + removed + "\n"; 2329 } 2330 2331 Element parent; 2332 int index; 2333 Vector added; 2334 Vector removed; 2335 boolean isFracture; 2336 } 2337 2338 } 2339 2340 2344 public static class AttributeUndoableEdit extends AbstractUndoableEdit { 2345 public AttributeUndoableEdit(Element element, AttributeSet newAttributes, 2346 boolean isReplacing) { 2347 super(); 2348 this.element = element; 2349 this.newAttributes = newAttributes; 2350 this.isReplacing = isReplacing; 2351 copy = element.getAttributes().copyAttributes(); 2354 } 2355 2356 2361 public void redo() throws CannotRedoException { 2362 super.redo(); 2363 MutableAttributeSet as = (MutableAttributeSet )element 2364 .getAttributes(); 2365 if(isReplacing) 2366 as.removeAttributes(as); 2367 as.addAttributes(newAttributes); 2368 } 2369 2370 2375 public void undo() throws CannotUndoException { 2376 super.undo(); 2377 MutableAttributeSet as = (MutableAttributeSet )element.getAttributes(); 2378 as.removeAttributes(as); 2379 as.addAttributes(copy); 2380 } 2381 2382 protected AttributeSet newAttributes; 2384 protected AttributeSet copy; 2386 protected boolean isReplacing; 2388 protected Element element; 2390 } 2391 2392 2395 static class StyleChangeUndoableEdit extends AbstractUndoableEdit { 2396 public StyleChangeUndoableEdit(AbstractElement element, 2397 Style newStyle) { 2398 super(); 2399 this.element = element; 2400 this.newStyle = newStyle; 2401 oldStyle = element.getResolveParent(); 2402 } 2403 2404 2409 public void redo() throws CannotRedoException { 2410 super.redo(); 2411 element.setResolveParent(newStyle); 2412 } 2413 2414 2419 public void undo() throws CannotUndoException { 2420 super.undo(); 2421 element.setResolveParent(oldStyle); 2422 } 2423 2424 2425 protected AbstractElement element; 2426 2427 protected Style newStyle; 2428 2429 protected AttributeSet oldStyle; 2430 } 2431 2432 2433 2437 class StyleChangeHandler implements ChangeListener { 2438 public void stateChanged(ChangeEvent e) { 2439 Object source = e.getSource(); 2440 2441 if (source instanceof Style ) { 2442 styleChanged((Style )source); 2443 } 2444 else { 2445 styleChanged(null); 2446 } 2447 } 2448 } 2449 2450 2451 2455 class StyleContextChangeHandler implements ChangeListener { 2456 public void stateChanged(ChangeEvent e) { 2457 updateStylesListeningTo(); 2458 } 2459 } 2460 2461 2462 2466 class ChangeUpdateRunnable implements Runnable { 2467 boolean isPending = false; 2468 2469 public void run() { 2470 synchronized(this) { 2471 isPending = false; 2472 } 2473 2474 try { 2475 writeLock(); 2476 DefaultDocumentEvent dde = new DefaultDocumentEvent(0, 2477 getLength(), 2478 DocumentEvent.EventType.CHANGE); 2479 dde.end(); 2480 fireChangedUpdate(dde); 2481 } finally { 2482 writeUnlock(); 2483 } 2484 } 2485 } 2486} 2487 2488 2489 2490 2491 | Popular Tags |