| 1 7 package javax.swing.text; 8 9 import java.util.*; 10 import java.io.*; 11 import java.awt.font.TextAttribute ; 12 import java.text.Bidi ; 13 14 import javax.swing.UIManager ; 15 import javax.swing.undo.*; 16 import javax.swing.event.ChangeListener ; 17 import javax.swing.event.*; 18 import javax.swing.tree.TreeNode ; 19 20 import sun.font.BidiUtils; 21 22 82 public abstract class AbstractDocument implements Document , Serializable { 83 84 90 protected AbstractDocument(Content data) { 91 this(data, StyleContext.getDefaultStyleContext()); 92 } 93 94 101 protected AbstractDocument(Content data, AttributeContext context) { 102 this.data = data; 103 this.context = context; 104 bidiRoot = new BidiRootElement(); 105 106 if (defaultI18NProperty == null) { 107 Object o = java.security.AccessController.doPrivileged( 109 new java.security.PrivilegedAction () { 110 public Object run() { 111 return System.getProperty(I18NProperty); 112 } 113 } 114 ); 115 if (o != null) { 116 defaultI18NProperty = Boolean.valueOf((String )o); 117 } else { 118 defaultI18NProperty = Boolean.FALSE; 119 } 120 } 121 putProperty( I18NProperty, defaultI18NProperty); 122 123 writeLock(); 129 try { 130 Element [] p = new Element [1]; 131 p[0] = new BidiElement( bidiRoot, 0, 1, 0 ); 132 bidiRoot.replace(0,0,p); 133 } finally { 134 writeUnlock(); 135 } 136 } 137 138 146 public Dictionary<Object ,Object > getDocumentProperties() { 147 if (documentProperties == null) { 148 documentProperties = new Hashtable(2); 149 } 150 return documentProperties; 151 } 152 153 159 public void setDocumentProperties(Dictionary<Object ,Object > x) { 160 documentProperties = x; 161 } 162 163 172 protected void fireInsertUpdate(DocumentEvent e) { 173 notifyingListeners = true; 174 try { 175 Object [] listeners = listenerList.getListenerList(); 177 for (int i = listeners.length-2; i>=0; i-=2) { 180 if (listeners[i]==DocumentListener.class) { 181 ((DocumentListener)listeners[i+1]).insertUpdate(e); 185 } 186 } 187 } finally { 188 notifyingListeners = false; 189 } 190 } 191 192 201 protected void fireChangedUpdate(DocumentEvent e) { 202 notifyingListeners = true; 203 try { 204 Object [] listeners = listenerList.getListenerList(); 206 for (int i = listeners.length-2; i>=0; i-=2) { 209 if (listeners[i]==DocumentListener.class) { 210 ((DocumentListener)listeners[i+1]).changedUpdate(e); 214 } 215 } 216 } finally { 217 notifyingListeners = false; 218 } 219 } 220 221 230 protected void fireRemoveUpdate(DocumentEvent e) { 231 notifyingListeners = true; 232 try { 233 Object [] listeners = listenerList.getListenerList(); 235 for (int i = listeners.length-2; i>=0; i-=2) { 238 if (listeners[i]==DocumentListener.class) { 239 ((DocumentListener)listeners[i+1]).removeUpdate(e); 243 } 244 } 245 } finally { 246 notifyingListeners = false; 247 } 248 } 249 250 259 protected void fireUndoableEditUpdate(UndoableEditEvent e) { 260 Object [] listeners = listenerList.getListenerList(); 262 for (int i = listeners.length-2; i>=0; i-=2) { 265 if (listeners[i]==UndoableEditListener.class) { 266 ((UndoableEditListener)listeners[i+1]).undoableEditHappened(e); 270 } 271 } 272 } 273 274 309 public <T extends EventListener> T[] getListeners(Class <T> listenerType) { 310 return listenerList.getListeners(listenerType); 311 } 312 313 320 public int getAsynchronousLoadPriority() { 321 Integer loadPriority = (Integer ) 322 getProperty(AbstractDocument.AsyncLoadPriority); 323 if (loadPriority != null) { 324 return loadPriority.intValue(); 325 } 326 return -1; 327 } 328 329 335 public void setAsynchronousLoadPriority(int p) { 336 Integer loadPriority = (p >= 0) ? new Integer (p) : null; 337 putProperty(AbstractDocument.AsyncLoadPriority, loadPriority); 338 } 339 340 350 public void setDocumentFilter(DocumentFilter filter) { 351 documentFilter = filter; 352 } 353 354 363 public DocumentFilter getDocumentFilter() { 364 return documentFilter; 365 } 366 367 369 399 public void render(Runnable r) { 400 readLock(); 401 try { 402 r.run(); 403 } finally { 404 readUnlock(); 405 } 406 } 407 408 415 public int getLength() { 416 return data.length() - 1; 417 } 418 419 425 public void addDocumentListener(DocumentListener listener) { 426 listenerList.add(DocumentListener.class, listener); 427 } 428 429 435 public void removeDocumentListener(DocumentListener listener) { 436 listenerList.remove(DocumentListener.class, listener); 437 } 438 439 451 public DocumentListener[] getDocumentListeners() { 452 return (DocumentListener[])listenerList.getListeners( 453 DocumentListener.class); 454 } 455 456 465 public void addUndoableEditListener(UndoableEditListener listener) { 466 listenerList.add(UndoableEditListener.class, listener); 467 } 468 469 475 public void removeUndoableEditListener(UndoableEditListener listener) { 476 listenerList.remove(UndoableEditListener.class, listener); 477 } 478 479 492 public UndoableEditListener[] getUndoableEditListeners() { 493 return (UndoableEditListener[])listenerList.getListeners( 494 UndoableEditListener.class); 495 } 496 497 508 public final Object getProperty(Object key) { 509 return getDocumentProperties().get(key); 510 } 511 512 513 526 public final void putProperty(Object key, Object value) { 527 if (value != null) { 528 getDocumentProperties().put(key, value); 529 } else { 530 getDocumentProperties().remove(key); 531 } 532 if( key == TextAttribute.RUN_DIRECTION 533 && Boolean.TRUE.equals(getProperty(I18NProperty)) ) 534 { 535 writeLock(); 538 try { 539 DefaultDocumentEvent e 540 = new DefaultDocumentEvent(0, getLength(), 541 DocumentEvent.EventType.INSERT); 542 updateBidi( e ); 543 } finally { 544 writeUnlock(); 545 } 546 } 547 } 548 549 566 public void remove(int offs, int len) throws BadLocationException { 567 DocumentFilter filter = getDocumentFilter(); 568 569 writeLock(); 570 try { 571 if (filter != null) { 572 filter.remove(getFilterBypass(), offs, len); 573 } 574 else { 575 handleRemove(offs, len); 576 } 577 } finally { 578 writeUnlock(); 579 } 580 } 581 582 586 void handleRemove(int offs, int len) throws BadLocationException { 587 if (len > 0) { 588 if (offs < 0 || (offs + len) > getLength()) { 589 throw new BadLocationException ("Invalid remove", 590 getLength() + 1); 591 } 592 DefaultDocumentEvent chng = 593 new DefaultDocumentEvent(offs, len, DocumentEvent.EventType.REMOVE); 594 595 boolean isComposedTextElement = false; 596 isComposedTextElement = Utilities.isComposedTextElement(this, offs); 598 599 removeUpdate(chng); 600 UndoableEdit u = data.remove(offs, len); 601 if (u != null) { 602 chng.addEdit(u); 603 } 604 postRemoveUpdate(chng); 605 chng.end(); 607 fireRemoveUpdate(chng); 608 if ((u != null) && !isComposedTextElement) { 611 fireUndoableEditUpdate(new UndoableEditEvent(this, chng)); 612 } 613 } 614 } 615 616 620 private static final boolean isComplex(char ch) { 621 return (ch >= '\u0900' && ch <= '\u0D7F') || (ch >= '\u0E00' && ch <= '\u0E7F') || (ch >= '\uD800' && ch <= '\uDFFF'); } 625 626 private static final boolean isComplex(char[] text, int start, int limit) { 627 for (int i = start; i < limit; ++i) { 628 if (isComplex(text[i])) { 629 return true; 630 } 631 } 632 return false; 633 } 634 635 655 public void replace(int offset, int length, String text, 656 AttributeSet attrs) throws BadLocationException { 657 if (length == 0 && (text == null || text.length() == 0)) { 658 return; 659 } 660 DocumentFilter filter = getDocumentFilter(); 661 662 writeLock(); 663 try { 664 if (filter != null) { 665 filter.replace(getFilterBypass(), offset, length, text, 666 attrs); 667 } 668 else { 669 if (length > 0) { 670 remove(offset, length); 671 } 672 if (text != null && text.length() > 0) { 673 insertString(offset, text, attrs); 674 } 675 } 676 } finally { 677 writeUnlock(); 678 } 679 } 680 681 699 public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { 700 if ((str == null) || (str.length() == 0)) { 701 return; 702 } 703 DocumentFilter filter = getDocumentFilter(); 704 705 writeLock(); 706 try { 707 if (filter != null) { 708 filter.insertString(getFilterBypass(), offs, str, a); 709 } 710 else { 711 handleInsertString(offs, str, a); 712 } 713 } finally { 714 writeUnlock(); 715 } 716 } 717 718 722 void handleInsertString(int offs, String str, AttributeSet a) 723 throws BadLocationException { 724 if ((str == null) || (str.length() == 0)) { 725 return; 726 } 727 UndoableEdit u = data.insertString(offs, str); 728 DefaultDocumentEvent e = 729 new DefaultDocumentEvent(offs, str.length(), DocumentEvent.EventType.INSERT); 730 if (u != null) { 731 e.addEdit(u); 732 } 733 734 if( getProperty(I18NProperty).equals( Boolean.FALSE ) ) { 736 Object d = getProperty(TextAttribute.RUN_DIRECTION); 739 if ((d != null) && (d.equals(TextAttribute.RUN_DIRECTION_RTL))) { 740 putProperty( I18NProperty, Boolean.TRUE); 741 } else { 742 char[] chars = str.toCharArray(); 743 if (Bidi.requiresBidi(chars, 0, chars.length) || 744 isComplex(chars, 0, chars.length)) { 745 putProperty( I18NProperty, Boolean.TRUE); 747 } 748 } 749 } 750 751 insertUpdate(e, a); 752 e.end(); 754 fireInsertUpdate(e); 755 if (u != null && 758 (a == null || !a.isDefined(StyleConstants.ComposedTextAttribute))) { 759 fireUndoableEditUpdate(new UndoableEditEvent(this, e)); 760 } 761 } 762 763 773 public String getText(int offset, int length) throws BadLocationException { 774 if (length < 0) { 775 throw new BadLocationException ("Length must be positive", length); 776 } 777 String str = data.getString(offset, length); 778 return str; 779 } 780 781 813 public void getText(int offset, int length, Segment txt) throws BadLocationException { 814 if (length < 0) { 815 throw new BadLocationException ("Length must be positive", length); 816 } 817 data.getChars(offset, length, txt); 818 } 819 820 835 public synchronized Position createPosition(int offs) throws BadLocationException { 836 return data.createPosition(offs); 837 } 838 839 846 public final Position getStartPosition() { 847 Position p; 848 try { 849 p = createPosition(0); 850 } catch (BadLocationException bl) { 851 p = null; 852 } 853 return p; 854 } 855 856 863 public final Position getEndPosition() { 864 Position p; 865 try { 866 p = createPosition(data.length()); 867 } catch (BadLocationException bl) { 868 p = null; 869 } 870 return p; 871 } 872 873 880 public Element [] getRootElements() { 881 Element [] elems = new Element [2]; 882 elems[0] = getDefaultRootElement(); 883 elems[1] = getBidiRootElement(); 884 return elems; 885 } 886 887 895 public abstract Element getDefaultRootElement(); 896 897 899 903 private DocumentFilter.FilterBypass getFilterBypass() { 904 if (filterBypass == null) { 905 filterBypass = new DefaultFilterBypass(); 906 } 907 return filterBypass; 908 } 909 910 915 public Element getBidiRootElement() { 916 return bidiRoot; 917 } 918 919 923 boolean isLeftToRight(int p0, int p1) { 924 if(!getProperty(I18NProperty).equals(Boolean.TRUE)) { 925 return true; 926 } 927 Element bidiRoot = getBidiRootElement(); 928 int index = bidiRoot.getElementIndex(p0); 929 Element bidiElem = bidiRoot.getElement(index); 930 if(bidiElem.getEndOffset() >= p1) { 931 AttributeSet bidiAttrs = bidiElem.getAttributes(); 932 return ((StyleConstants.getBidiLevel(bidiAttrs) % 2) == 0); 933 } 934 return true; 935 } 936 937 945 public abstract Element  |