| 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 }
|