1 19 20 package org.netbeans.editor; 21 22 import java.beans.PropertyVetoException ; 23 import java.beans.VetoableChangeListener ; 24 import java.util.Hashtable ; 25 import java.util.ArrayList ; 26 import java.util.Dictionary ; 27 import java.util.Enumeration ; 28 import java.util.Map ; 29 import java.io.Reader ; 30 import java.io.Writer ; 31 import java.io.IOException ; 32 import java.beans.PropertyChangeListener ; 33 import java.beans.PropertyChangeEvent ; 34 import java.util.EventListener ; 35 import java.util.HashMap ; 36 import java.util.logging.Logger ; 37 import javax.swing.event.DocumentListener ; 38 import javax.swing.event.UndoableEditListener ; 39 import javax.swing.text.BadLocationException ; 40 import javax.swing.text.DefaultEditorKit ; 41 import javax.swing.text.Position ; 42 import javax.swing.text.Element ; 43 import javax.swing.text.AttributeSet ; 44 import javax.swing.text.AbstractDocument ; 45 import javax.swing.text.StyleConstants ; 46 import javax.swing.event.DocumentEvent ; 47 import javax.swing.event.UndoableEditEvent ; 48 import javax.swing.text.Segment ; 49 import javax.swing.undo.AbstractUndoableEdit ; 50 import javax.swing.undo.UndoableEdit ; 51 import javax.swing.undo.CompoundEdit ; 52 import javax.swing.undo.CannotUndoException ; 53 import javax.swing.undo.CannotRedoException ; 54 import org.netbeans.lib.editor.util.swing.DocumentListenerPriority; 55 56 62 63 public class BaseDocument extends AbstractDocument implements SettingsChangeListener, AtomicLockDocument { 64 65 private static final Logger LOG = Logger.getLogger(BaseDocument.class.getName()); 66 67 68 public static final String ID_PROP = "id"; 70 71 public static final String READ_LINE_SEPARATOR_PROP 72 = DefaultEditorKit.EndOfLineStringProperty; 73 74 77 public static final String WRITE_LINE_SEPARATOR_PROP 78 = "write-line-separator"; 80 81 public static final String FILE_NAME_PROP = "file-name"; 83 84 public static final String WRAP_SEARCH_MARK_PROP = "wrap-search-mark"; 86 90 public static final String UNDO_MANAGER_PROP = "undo-manager"; 92 95 public static final String KIT_CLASS_PROP = "kit-class"; 97 98 public static final String STRING_FINDER_PROP = "string-finder"; 100 101 public static final String STRING_BWD_FINDER_PROP = "string-bwd-finder"; 103 104 public static final String BLOCKS_FINDER_PROP = "blocks-finder"; 106 111 public static final String LINE_LIMIT_PROP = "line-limit"; 113 114 117 public static final String LINE_BATCH_SIZE = "line-batch-size"; 119 120 public static final String LS_CR = "\r"; 122 123 public static final String LS_LF = "\n"; 125 126 public static final String LS_CRLF = "\r\n"; 128 133 private static final String BEFORE_MODIFICATION_LISTENER = "modificationListener"; 135 138 private static final int MAX_READ_THREADS = 10; 139 140 141 private static final String WRITE_LOCK_MISSING 142 = "extWriteUnlock() without extWriteLock()"; 144 private static final Object annotationsLock = new Object (); 145 private static final Object getVisColFromPosLock = new Object (); 146 private static final Object getOffsetFromVisColLock = new Object (); 147 148 149 private static final boolean debug 150 = Boolean.getBoolean("netbeans.debug.editor.document"); 152 private static final boolean debugStack 153 = Boolean.getBoolean("netbeans.debug.editor.document.stack"); 155 private static final boolean debugNoText 156 = Boolean.getBoolean("netbeans.debug.editor.document.notext"); 158 159 private static final boolean debugRead 160 = Boolean.getBoolean("netbeans.debug.editor.document.read"); 162 public static final ThreadLocal THREAD_LOCAL_LOCK_DEPTH = new ThreadLocal (); 163 private static final Integer [] lockIntegers 164 = new Integer [] { 165 null, 166 new Integer (1), 167 new Integer (2), 168 new Integer (3) 169 }; 170 171 172 private int tabSize = SettingsDefaults.defaultTabSize.intValue(); 173 174 177 private Integer shiftWidth; 178 179 180 private int writeDepth; 181 182 183 private int atomicDepth; 184 185 186 protected boolean inited; 187 188 189 protected boolean modified; 190 191 192 PropertyChangeListener findSupportListener; 193 194 195 protected Element defaultRootElem; 196 197 private SyntaxSupport syntaxSupport; 198 199 200 private DrawLayerList drawLayerList = new DrawLayerList(); 201 202 203 boolean undoMergeReset; 204 205 206 Class kitClass; 207 208 213 private AtomicCompoundEdit atomicEdits; 214 215 private Acceptor identifierAcceptor; 216 217 private Acceptor whitespaceAcceptor; 218 219 private ArrayList syntaxList = new ArrayList (); 220 221 222 private ArrayList posList = new ArrayList (); 223 224 225 private ArrayList posFreeList = new ArrayList (); 226 227 228 protected LineRootElement lineRootElement; 229 230 234 UndoableEdit lastModifyUndoEdit; 236 237 private Annotations annotations; 238 239 243 private boolean composedText = false; 244 245 249 final Map marks = new HashMap (); 250 final MarkVector marksStorage = new MarkVector(); 251 252 253 private FinderFactory.VisColPosFwdFinder visColPosFwdFinder; 254 255 256 private FinderFactory.PosVisColFwdFinder posVisColFwdFinder; 257 258 259 private AtomicLockEvent atomicLockEventInstance = new AtomicLockEvent(this); 260 261 private FixLineSyntaxState fixLineSyntaxState; 262 private UndoableEdit removeUpdateLineUndo; 263 264 private Object [] atomicLockListenerList; 265 266 270 private final ThreadLocal STATUS = new ThreadLocal (); 271 272 private boolean modsUndoneOrRedone; 273 274 private DocumentListener postModificationDocumentListener; 275 276 private Position lastPositionEditedByTyping = null; 277 278 283 public BaseDocument(Class kitClass, boolean addToRegistry) { 284 super(new DocumentContent()); 285 this.kitClass = kitClass; 286 287 setDocumentProperties(createDocumentProperties(getDocumentProperties())); 288 super.addDocumentListener( 289 org.netbeans.lib.editor.util.swing.DocumentUtilities.initPriorityListening(this)); 290 291 putProperty(GapStart.class, getDocumentContent()); 292 putProperty("supportsModificationListener", Boolean.TRUE); 294 lineRootElement = new LineRootElement(this); 295 296 settingsChange(null); Settings.addSettingsChangeListener(this); 298 299 putProperty(READ_LINE_SEPARATOR_PROP, Analyzer.getPlatformLS()); 301 302 BaseKit kit = BaseKit.getKit(kitClass); 304 if (kit != null) { 305 kit.initDocument(this); 306 } 307 308 if (addToRegistry) { 310 Registry.addDocument(this); } 312 313 findSupportListener = new PropertyChangeListener () { 315 public void propertyChange(PropertyChangeEvent evt) { 316 findSupportChange(evt); 317 } 318 }; 319 FindSupport.getFindSupport().addPropertyChangeListener(findSupportListener); 320 findSupportChange(null); } 322 323 private DocumentContent getDocumentContent() { 324 return (DocumentContent)getContent(); 325 } 326 327 public CharSeq getText() { 328 return getDocumentContent(); 329 } 330 331 private void findSupportChange(PropertyChangeEvent evt) { 332 putProperty(STRING_FINDER_PROP, null); 334 putProperty(STRING_BWD_FINDER_PROP, null); 335 putProperty(BLOCKS_FINDER_PROP, null); 336 } 337 338 341 public void settingsChange(SettingsChangeEvent evt) { 342 String settingName = (evt != null) ? evt.getSettingName() : null; 343 344 if (settingName == null || SettingsNames.TAB_SIZE.equals(settingName)) { 345 tabSize = SettingsUtil.getPositiveInteger(kitClass, SettingsNames.TAB_SIZE, 346 SettingsDefaults.defaultTabSize); 347 } 348 349 if (settingName == null || SettingsNames.INDENT_SHIFT_WIDTH.equals(settingName)) { 350 Object shw = Settings.getValue(kitClass, SettingsNames.INDENT_SHIFT_WIDTH); 351 if (shw instanceof Integer ) { shiftWidth = (Integer )shw; 353 } 354 } 355 356 if (settingName == null || SettingsNames.READ_BUFFER_SIZE.equals(settingName)) { 357 int readBufferSize = SettingsUtil.getPositiveInteger(kitClass, 358 SettingsNames.READ_BUFFER_SIZE, SettingsDefaults.defaultReadBufferSize); 359 putProperty(SettingsNames.READ_BUFFER_SIZE, new Integer (readBufferSize)); 360 } 361 362 if (settingName == null || SettingsNames.WRITE_BUFFER_SIZE.equals(settingName)) { 363 int writeBufferSize = SettingsUtil.getPositiveInteger(kitClass, 364 SettingsNames.WRITE_BUFFER_SIZE, SettingsDefaults.defaultWriteBufferSize); 365 putProperty(SettingsNames.WRITE_BUFFER_SIZE, new Integer (writeBufferSize)); 366 } 367 368 if (settingName == null || SettingsNames.MARK_DISTANCE.equals(settingName)) { 369 int markDistance = SettingsUtil.getPositiveInteger(kitClass, 370 SettingsNames.MARK_DISTANCE, SettingsDefaults.defaultMarkDistance); 371 putProperty(SettingsNames.MARK_DISTANCE, new Integer (markDistance)); 372 } 373 374 if (settingName == null || SettingsNames.MAX_MARK_DISTANCE.equals(settingName)) { 375 int maxMarkDistance = SettingsUtil.getPositiveInteger(kitClass, 376 SettingsNames.MAX_MARK_DISTANCE, SettingsDefaults.defaultMaxMarkDistance); 377 putProperty(SettingsNames.MAX_MARK_DISTANCE, new Integer (maxMarkDistance)); 378 } 379 380 if (settingName == null || SettingsNames.MIN_MARK_DISTANCE.equals(settingName)) { 381 int minMarkDistance = SettingsUtil.getPositiveInteger(kitClass, 382 SettingsNames.MIN_MARK_DISTANCE, SettingsDefaults.defaultMinMarkDistance); 383 putProperty(SettingsNames.MIN_MARK_DISTANCE, new Integer (minMarkDistance)); 384 } 385 386 if (settingName == null || SettingsNames.READ_MARK_DISTANCE.equals(settingName)) { 387 int readMarkDistance = SettingsUtil.getPositiveInteger(kitClass, 388 SettingsNames.READ_MARK_DISTANCE, SettingsDefaults.defaultReadMarkDistance); 389 putProperty(SettingsNames.READ_MARK_DISTANCE, new Integer (readMarkDistance)); 390 } 391 392 if (settingName == null || SettingsNames.SYNTAX_UPDATE_BATCH_SIZE.equals(settingName)) { 393 int syntaxUpdateBatchSize = SettingsUtil.getPositiveInteger(kitClass, 394 SettingsNames.SYNTAX_UPDATE_BATCH_SIZE, SettingsDefaults.defaultSyntaxUpdateBatchSize); 395 putProperty(SettingsNames.SYNTAX_UPDATE_BATCH_SIZE, new Integer (syntaxUpdateBatchSize)); 396 } 397 398 if (settingName == null || SettingsNames.LINE_BATCH_SIZE.equals(settingName)) { 399 int lineBatchSize = SettingsUtil.getPositiveInteger(kitClass, 400 SettingsNames.LINE_BATCH_SIZE, SettingsDefaults.defaultLineBatchSize); 401 putProperty(SettingsNames.LINE_BATCH_SIZE, new Integer (lineBatchSize)); 402 } 403 404 if (settingName == null || SettingsNames.IDENTIFIER_ACCEPTOR.equals(settingName)) { 405 identifierAcceptor = SettingsUtil.getAcceptor(kitClass, 406 SettingsNames.IDENTIFIER_ACCEPTOR, AcceptorFactory.LETTER_DIGIT); 407 } 408 409 if (settingName == null || SettingsNames.WHITESPACE_ACCEPTOR.equals(settingName)) { 410 whitespaceAcceptor = SettingsUtil.getAcceptor(kitClass, 411 SettingsNames.WHITESPACE_ACCEPTOR, AcceptorFactory.WHITESPACE); 412 } 413 414 boolean stopOnEOL = SettingsUtil.getBoolean(kitClass, 415 SettingsNames.WORD_MOVE_NEWLINE_STOP, true); 416 if (settingName == null || SettingsNames.NEXT_WORD_FINDER.equals(settingName)) { 417 putProperty(SettingsNames.NEXT_WORD_FINDER, 418 SettingsUtil.getValue(kitClass, SettingsNames.NEXT_WORD_FINDER, 419 new FinderFactory.NextWordFwdFinder(this, stopOnEOL, false))); 420 } 421 422 if (settingName == null || SettingsNames.PREVIOUS_WORD_FINDER.equals(settingName)) { 423 putProperty(SettingsNames.PREVIOUS_WORD_FINDER, 424 SettingsUtil.getValue(kitClass, SettingsNames.PREVIOUS_WORD_FINDER, 425 new FinderFactory.PreviousWordBwdFinder(this, stopOnEOL, false))); 426 } 427 428 } 429 430 Syntax getFreeSyntax() { 431 BaseKit kit = BaseKit.getKit(kitClass); 432 synchronized (Settings.class) { 433 int cnt = syntaxList.size(); 434 return (cnt > 0) ? (Syntax)syntaxList.remove(cnt - 1) 435 : kit.createSyntax(this); 436 } 437 } 438 439 void releaseSyntax(Syntax syntax) { 440 synchronized (Settings.class) { 441 syntaxList.add(syntax); 442 } 443 } 444 445 446 public Formatter getFormatter() { 447 return Formatter.getFormatter(kitClass); 448 } 449 450 public SyntaxSupport getSyntaxSupport() { 451 if (syntaxSupport == null) { 452 syntaxSupport = BaseKit.getKit(kitClass).createSyntaxSupport(this); 453 } 454 return syntaxSupport; 455 } 456 457 473 public int processText(TextBatchProcessor tbp, int startPos, int endPos) 474 throws BadLocationException { 475 if (endPos == -1) { 476 endPos = getLength(); 477 } 478 int batchLineCnt = ((Integer )getProperty(SettingsNames.LINE_BATCH_SIZE)).intValue(); 479 int batchStart = startPos; 480 int ret = -1; 481 if (startPos < endPos) { while (ret < 0 && batchStart < endPos) { 483 int batchEnd = Math.min(Utilities.getRowStart(this, batchStart, batchLineCnt), endPos); 484 if (batchEnd == -1) { batchEnd = endPos; 486 } 487 ret = tbp.processTextBatch(this, batchStart, batchEnd, (batchEnd == endPos)); 488 batchLineCnt *= 2; batchStart = batchEnd; 490 } 491 } else { 492 while (ret < 0 && batchStart > endPos) { 493 int batchEnd = Math.max(Utilities.getRowStart(this, batchStart, -batchLineCnt), endPos); 494 ret = tbp.processTextBatch(this, batchStart, batchEnd, (batchEnd == endPos)); 495 batchLineCnt *= 2; batchStart = batchEnd; 497 } 498 } 499 return ret; 500 } 501 502 503 public boolean isIdentifierPart(char ch) { 504 return identifierAcceptor.accept(ch); 505 } 506 507 public boolean isWhitespace(char ch) { 508 return whitespaceAcceptor.accept(ch); 509 } 510 511 515 int storePosition(int pos) throws BadLocationException { 516 MultiMark mark = getDocumentContent().createBiasMark(pos, Position.Bias.Forward); 517 int ind; 518 if (posFreeList.size() > 0) { 519 ind = ((Integer )posFreeList.remove(posFreeList.size() - 1)).intValue(); 520 posList.set(ind, mark); 521 } else { ind = posList.size(); 523 posList.add(mark); 524 } 525 return ind; 526 } 527 528 int getStoredPosition(int posID) { 529 if (posID < 0 || posID >= posList.size()) { 530 return -1; 531 } 532 MultiMark mark = (MultiMark)posList.get(posID); 533 return (mark != null) ? mark.getOffset() : -1; 534 } 535 536 void removeStoredPosition(int posID) { 537 if (posID >= 0 || posID < posList.size()) { 538 Mark mark = (Mark)posList.get(posID); 539 posList.set(posID, null); posFreeList.add(new Integer (posID)); 541 542 try { 544 mark.remove(); 545 } catch (InvalidMarkException e) { 546 } 547 } 548 } 549 550 551 public void insertString(int offset, String text, AttributeSet a) 552 throws BadLocationException { 553 if (text == null || text.length() == 0) { 554 return; 555 } 556 557 if (offset < 0 || offset > getLength()) { 559 throw new BadLocationException ("Wrong insert position " + offset, offset); } 561 562 text = Analyzer.convertLSToLF(text); 564 565 boolean activePostModification; 568 DocumentEvent postModificationEvent = null; 569 synchronized (this) { 570 activePostModification = (postModificationDocumentListener != null); 571 if (activePostModification) { 572 atomicLock(); 573 } 574 } 575 try { 576 577 boolean notifyMod = notifyModifyCheckStart(offset, "insertString() vetoed"); boolean modFinished = false; extWriteLock(); 581 try { 582 583 591 592 preInsertCheck(offset, text, a); 593 594 UndoableEdit edit = getContent().insertString(offset, text); 596 597 602 603 if (debug) { 604 System.err.println("BaseDocument.insertString(): doc=" + this + (modified ? "" : " - first modification") + ", offset=" + Utilities.offsetToLineColumnString(this, offset) + (debugNoText ? "" : (", text='" + text + "'")) ); 609 } 610 if (debugStack) { 611 Thread.dumpStack(); 612 } 613 614 BaseDocumentEvent evt = createDocumentEvent(offset, text.length(), DocumentEvent.EventType.INSERT); 615 616 preInsertUpdate(evt, a); 617 618 if (edit != null) { 619 evt.addEdit(edit); 620 621 lastModifyUndoEdit = edit; } 623 624 modified = true; 625 626 if (atomicDepth > 0) { 627 if (atomicEdits == null) { 628 atomicEdits = new AtomicCompoundEdit(); 629 } 630 atomicEdits.addEdit(evt); } 632 633 insertUpdate(evt, a); 634 635 evt.end(); 636 637 fireInsertUpdate(evt); 638 639 boolean isComposedText = ((a != null) 640 && (a.isDefined(StyleConstants.ComposedTextAttribute))); 641 642 if (composedText && !isComposedText) 643 composedText = false; 644 if (!composedText && isComposedText) 645 composedText = true; 646 647 if (atomicDepth == 0 && !isComposedText) { fireUndoableEditUpdate(new UndoableEditEvent (this, evt)); 649 } 650 modFinished = true; 651 postModificationEvent = evt; 652 } finally { 653 extWriteUnlock(); 654 if (notifyMod) { 656 notifyModifyCheckEnd(modFinished); 657 } 658 } 659 660 } finally { if (activePostModification) { 662 if (postModificationEvent != null) { if (postModificationDocumentListener != null) { 664 postModificationDocumentListener.insertUpdate(postModificationEvent); 665 } 666 } 667 atomicUnlock(); 668 } 669 } 670 } 671 672 public void checkTrailingSpaces(int offset) { 673 try { 674 int lineNum = Utilities.getLineOffset(this, offset); 675 int lastEditedLine = lastPositionEditedByTyping != null ? Utilities.getLineOffset(this, lastPositionEditedByTyping.getOffset()) : -1; 676 if (lastEditedLine != -1 && lastEditedLine != lineNum) { 677 Element root = getDefaultRootElement(); 679 Element elem = root.getElement(lastEditedLine); 680 int start = elem.getStartOffset(); 681 int end = elem.getEndOffset(); 682 String line = getText(start, end - start); 683 684 int endIndex = line.length() - 1; 685 if (endIndex >= 0 && line.charAt(endIndex) == '\n') { 686 endIndex--; 687 if (endIndex >= 0 && line.charAt(endIndex) == '\r') { 688 endIndex--; 689 } 690 } 691 692 int startIndex = endIndex; 693 while (startIndex >= 0 && Character.isWhitespace(line.charAt(startIndex)) && line.charAt(startIndex) != '\n' && 694 line.charAt(startIndex) != '\r') { 695 startIndex--; 696 } 697 startIndex++; 698 if (startIndex >= 0 && startIndex <= endIndex) { 699 remove(start + startIndex, endIndex - startIndex + 1); 700 } 701 } 702 } catch (BadLocationException e) { 703 e.printStackTrace(); 704 } 705 } 706 707 708 public void remove(int offset, int len) throws BadLocationException { 709 if (len > 0) { 710 if (offset < 0) { 711 throw new BadLocationException ("Wrong remove position " + offset, offset); } 713 714 boolean activePostModification; 717 DocumentEvent postModificationEvent = null; 718 synchronized (this) { 719 activePostModification = (postModificationDocumentListener != null); 720 if (activePostModification) { 721 atomicLock(); 722 } 723 } 724 try { 725 726 boolean notifyMod = notifyModifyCheckStart(offset, "remove() vetoed"); boolean modFinished = false; extWriteLock(); 729 try { 730 int docLen = getLength(); 731 if (offset < 0 || offset > docLen) { 732 throw new BadLocationException ("Wrong remove position " + offset, offset); } 734 if (offset + len > docLen) { 735 throw new BadLocationException ("End offset of removed text " + (offset + len) + " > getLength()=" + docLen, offset + len 738 ); } 740 741 preRemoveCheck(offset, len); 742 743 BaseDocumentEvent evt = createDocumentEvent(offset, len, DocumentEvent.EventType.REMOVE); 744 745 removeUpdate(evt); 746 747 UndoableEdit edit = getContent().remove(offset, len); 748 if (edit != null) { 749 evt.addEdit(edit); 750 751 lastModifyUndoEdit = edit; } 753 754 if (debug) { 755 System.err.println("BaseDocument.remove(): doc=" + this + ", origDocLen=" + docLen + ", offset=" + Utilities.offsetToLineColumnString(this, offset) + ", len=" + len + (debugNoText ? "" : (", removedText='" + ((DocumentContent.Edit)edit).getUndoRedoText() + "'")) ); 761 } 762 if (debugStack) { 763 Thread.dumpStack(); 764 } 765 766 if (atomicDepth > 0) { if (atomicEdits == null) { 768 atomicEdits = new AtomicCompoundEdit(); 769 } 770 atomicEdits.addEdit(evt); } 772 773 postRemoveUpdate(evt); 774 775 evt.end(); 776 777 fireRemoveUpdate(evt); 778 if (atomicDepth == 0 && !composedText) { 779 fireUndoableEditUpdate(new UndoableEditEvent (this, evt)); 780 } 781 782 modFinished = true; 783 postModificationEvent = evt; 784 } finally { 785 extWriteUnlock(); 786 if (notifyMod) { 788 notifyModifyCheckEnd(modFinished); 789 } 790 } 791 792 } finally { if (activePostModification) { 794 if (postModificationEvent != null) { if (postModificationDocumentListener != null) { 796 postModificationDocumentListener.removeUpdate(postModificationEvent); 797 } 798 } 799 atomicUnlock(); 800 } 801 } 802 803 } 804 } 805 806 820 boolean notifyModifyCheckStart(int offset, String vetoExceptionText) throws BadLocationException { 821 NotifyModifyStatus notifyModifyStatus = (NotifyModifyStatus)STATUS.get(); 822 boolean notifyMod; 823 if (notifyModifyStatus == null) { notifyModifyStatus = new NotifyModifyStatus (this); 825 STATUS.set (notifyModifyStatus); 826 notifyModify(notifyModifyStatus); 827 notifyMod = true; 828 } else { 829 notifyMod = false; 830 } 831 832 if (notifyModifyStatus.isModificationVetoed()) { 833 if (notifyMod) { 834 STATUS.set (null); 835 } 836 throw new BadLocationException (vetoExceptionText, offset); 837 } 838 return notifyMod; 839 } 840 841 852 void notifyModifyCheckEnd(boolean modFinished) { 853 NotifyModifyStatus notifyModifyStatus = (NotifyModifyStatus)STATUS.get(); 854 STATUS.set (null); 855 if (!modFinished) { 856 notifyUnmodify(notifyModifyStatus); 857 } 858 } 859 860 867 protected void preInsertCheck(int offset, String text, AttributeSet a) 868 throws BadLocationException { 869 } 870 871 877 protected void preRemoveCheck(int offset, int len) 878 throws BadLocationException { 879 } 880 881 protected void insertUpdate(DefaultDocumentEvent chng, AttributeSet attr) { 882 super.insertUpdate(chng, attr); 883 884 org.netbeans.lib.editor.util.swing.DocumentUtilities.addEventPropertyStorage(chng); 886 org.netbeans.lib.editor.util.swing.DocumentUtilities.putEventProperty(chng, String .class, 887 ((BaseDocumentEvent)chng).getText()); 888 889 MarksStorageUndo marksStorageUndo = new MarksStorageUndo(chng); 890 marksStorageUndo.updateMarksStorage(); 891 chng.addEdit(marksStorageUndo); 893 UndoableEdit lineUndo = lineRootElement.insertUpdate(chng.getOffset(), chng.getLength()); 894 if (lineUndo != null) { 895 chng.addEdit(lineUndo); 896 } 897 898 fixLineSyntaxState.update(false); 899 chng.addEdit(fixLineSyntaxState.createAfterLineUndo()); 900 fixLineSyntaxState = null; 901 902 org.netbeans.lib.editor.util.swing.DocumentUtilities.addEventPropertyStorage(chng); 904 BaseDocumentEvent bEvt = (BaseDocumentEvent)chng; 905 org.netbeans.lib.editor.util.swing.DocumentUtilities.putEventProperty( 906 chng, String .class, bEvt.getText()); 907 908 } 909 910 protected void preInsertUpdate(DefaultDocumentEvent chng, AttributeSet attr) { 911 fixLineSyntaxState = new FixLineSyntaxState(chng); 912 chng.addEdit(fixLineSyntaxState.createBeforeLineUndo()); 913 } 914 915 protected void removeUpdate(DefaultDocumentEvent chng) { 916 super.removeUpdate(chng); 917 918 org.netbeans.lib.editor.util.swing.DocumentUtilities.addEventPropertyStorage(chng); 920 String removedText; 921 try { 922 removedText = getText(chng.getOffset(), chng.getLength()); 923 } catch (BadLocationException e) { 924 removedText = null; 926 } 927 org.netbeans.lib.editor.util.swing.DocumentUtilities.putEventProperty(chng, String .class, 928 removedText); 929 930 removeUpdateLineUndo = lineRootElement.removeUpdate(chng.getOffset(), chng.getLength()); 932 933 fixLineSyntaxState = new FixLineSyntaxState(chng); 934 chng.addEdit(fixLineSyntaxState.createBeforeLineUndo()); 935 } 936 937 protected void postRemoveUpdate(DefaultDocumentEvent chng) { 938 super.postRemoveUpdate(chng); 939 940 MarksStorageUndo marksStorageUndo = new MarksStorageUndo(chng); 941 marksStorageUndo.updateMarksStorage(); 942 chng.addEdit(marksStorageUndo); 944 if (removeUpdateLineUndo != null) { 945 chng.addEdit(removeUpdateLineUndo); 946 removeUpdateLineUndo = null; 947 } 948 949 fixLineSyntaxState.update(false); 950 chng.addEdit(fixLineSyntaxState.createAfterLineUndo()); 951 fixLineSyntaxState = null; 952 953 org.netbeans.lib.editor.util.swing.DocumentUtilities.addEventPropertyStorage(chng); 955 BaseDocumentEvent bEvt = (BaseDocumentEvent)chng; 956 org.netbeans.lib.editor.util.swing.DocumentUtilities.putEventProperty( 957 chng, String .class, bEvt.getText()); 958 } 959 960 public String getText(int[] block) throws BadLocationException { 961 return getText(block[0], block[1] - block[0]); 962 } 963 964 969 public char[] getChars(int pos, int len) throws BadLocationException { 970 char[] chars = new char[len]; 971 getChars(pos, chars, 0, len); 972 return chars; 973 } 974 975 979 public char[] getChars(int[] block) throws BadLocationException { 980 return getChars(block[0], block[1] - block[0]); 981 } 982 983 990 public void getChars(int pos, char ret[], int offset, int len) 991 throws BadLocationException { 992 DocumentUtilities.copyText(this, pos, pos + len, ret, offset); 993 } 994 995 1001 public int find(Finder finder, int startPos, int limitPos) 1002 throws BadLocationException { 1003 int docLen = getLength(); 1004 if (limitPos == -1) { 1005 limitPos = docLen; 1006 } 1007 if (startPos == -1) { 1008 startPos = docLen; 1009 } 1010 1011 if (finder instanceof AdjustFinder) { 1012 if (startPos == limitPos) { finder.reset(); return -1; } 1016 1017 boolean forwardAdjustedSearch = (startPos < limitPos); 1018 startPos = ((AdjustFinder)finder).adjustStartPos(this, startPos); 1019 limitPos = ((AdjustFinder)finder).adjustLimitPos(this, limitPos); 1020 boolean voidSearch = (forwardAdjustedSearch ? (startPos >= limitPos) : (startPos <= limitPos)); 1021 if (voidSearch) { 1022 finder.reset(); 1023 return -1; 1024 } 1025 } 1026 1027 finder.reset(); 1028 if (startPos == limitPos) { 1029 return -1; 1030 } 1031 1032 Segment text = DocumentUtilities.SEGMENT_CACHE.getSegment(); 1033 try { 1034 int gapStart = DocumentUtilities.getGapStart(this); 1035 if (gapStart == -1) { 1036 throw new IllegalStateException ("Cannot get gapStart"); } 1038 1039 int pos = startPos; boolean fwdSearch = (startPos <= limitPos); if (fwdSearch) { 1042 while (pos >= startPos && pos < limitPos) { 1043 int p0; int p1; if (pos < gapStart) { p0 = startPos; 1047 p1 = Math.min(gapStart, limitPos); 1048 } else { p0 = Math.max(gapStart, startPos); 1050 p1 = limitPos; 1051 } 1052 1053 getText(p0, p1 - p0, text); 1054 pos = finder.find(p0 - text.offset, text.array, 1055 text.offset, text.offset + text.count, pos, limitPos); 1056 1057 if (finder.isFound()) { 1058 return pos; 1059 } 1060 } 1061 1062 } else { pos--; while (limitPos <= pos && pos <= startPos) { 1065 int p0; int p1; if (pos < gapStart) { p0 = limitPos; 1069 p1 = Math.min(gapStart, startPos); 1070 } else { p0 = Math.max(gapStart, limitPos); 1072 p1 = startPos; 1073 } 1074 1075 getText(p0, p1 - p0, text); 1076 pos = finder.find(p0 - text.offset, text.array, 1077 text.offset, text.offset + text.count, pos, limitPos); 1078 1079 if (finder.isFound()) { 1080 return pos; 1081 } 1082 } 1083 } 1084 1085 return -1; 1087 } finally { 1088 DocumentUtilities.SEGMENT_CACHE.releaseSegment(text); 1089 } 1090 } 1091 1092 1093 public void repaintBlock(int startOffset, int endOffset) { 1094 BaseDocumentEvent evt = createDocumentEvent(startOffset, 1095 endOffset - startOffset, DocumentEvent.EventType.CHANGE); 1096 fireChangedUpdate(evt); 1097 } 1098 1099 public void print(PrintContainer container) { 1100 print(container, true, true,0,getLength()); 1101 } 1102 1103 1115 public void print(PrintContainer container, boolean usePrintColoringMap, boolean lineNumberEnabled, int startOffset, 1116 int endOffset) { 1117 readLock(); 1118 try { 1119 EditorUI editorUI = BaseKit.getKit(kitClass).createPrintEditorUI(this, 1120 usePrintColoringMap, lineNumberEnabled); 1121 1122 DrawGraphics.PrintDG printDG = new DrawGraphics.PrintDG(container); 1123 DrawEngine.getDrawEngine().draw(printDG, editorUI, startOffset, endOffset, 0, 0, Integer.MAX_VALUE); 1124 } catch (BadLocationException e) { 1125 e.printStackTrace(); 1126 } finally { 1127 readUnlock(); 1128 } 1129 } 1130 1131 1142 public void print(PrintContainer container, boolean usePrintColoringMap, Boolean lineNumberEnabled, int startOffset, 1143 int endOffset) { 1144 readLock(); 1145 try { 1146 boolean lineNumberEnabledPar = true; 1147 boolean forceLineNumbers = false; 1148 if (lineNumberEnabled != null) { 1149 lineNumberEnabledPar = lineNumberEnabled.booleanValue(); 1150 forceLineNumbers = lineNumberEnabled.booleanValue(); 1151 } 1152 EditorUI editorUI = BaseKit.getKit(kitClass).createPrintEditorUI(this, usePrintColoringMap, lineNumberEnabledPar); 1153 if (forceLineNumbers) { 1154 editorUI.setLineNumberVisibleSetting(true); 1155 editorUI.setLineNumberEnabled(true); 1156 editorUI.updateLineNumberWidth(0); 1157 } 1158 1159 DrawGraphics.PrintDG printDG = new DrawGraphics.PrintDG(container); 1160 DrawEngine.getDrawEngine().draw(printDG, editorUI, startOffset, endOffset, 0, 0, Integer.MAX_VALUE); 1161 } catch (BadLocationException e) { 1162 e.printStackTrace(); 1163 } finally { 1164 readUnlock(); 1165 } 1166 } 1167 1168 1169 public Position createPosition(int offset, Position.Bias bias) 1170 throws BadLocationException { 1171 return getDocumentContent().createBiasPosition(offset, bias); 1172 } 1173 1174 MultiMark createMark(int offset) throws BadLocationException { 1175 return getDocumentContent().createMark(offset); 1176 } 1177 1178 MultiMark createBiasMark(int offset, Position.Bias bias) throws BadLocationException { 1179 return getDocumentContent().createBiasMark(offset, bias); 1180 } 1181 1182 1183 public Element [] getRootElements() { 1184 Element [] elems = new Element [1]; 1185 elems[0] = getDefaultRootElement(); 1186 return elems; 1187 } 1188 1189 1190 public Element getDefaultRootElement() { 1191 if (defaultRootElem == null) { 1192 defaultRootElem = getLineRootElement(); 1193 } 1194 return defaultRootElem; 1195 } 1196 1197 1198 public void render(Runnable r) { 1199 readLock(); 1200 assert incrementThreadLocalLockDepth(); 1201 try { 1202 r.run(); 1203 } finally { 1204 assert decrementThreadLocalLockDepth(); 1205 readUnlock(); 1206 } 1207 } 1208 1209 private boolean incrementThreadLocalLockDepth() { 1210 Integer depthInteger = (Integer )THREAD_LOCAL_LOCK_DEPTH.get(); 1211 if (depthInteger == null) { 1212 depthInteger = lockIntegers[1]; 1213 } else { 1214 int newDepth = depthInteger.intValue() + 1; 1215 depthInteger = (newDepth < lockIntegers.length) 1216 ? lockIntegers[newDepth] 1217 : new Integer (newDepth); 1218 } 1219 THREAD_LOCAL_LOCK_DEPTH.set(depthInteger); 1220 return true; 1221 } 1222 1223 private boolean decrementThreadLocalLockDepth() { 1224 Integer depthInteger = (Integer )THREAD_LOCAL_LOCK_DEPTH.get(); 1225 assert (depthInteger != null); 1226 int newDepth = depthInteger.intValue() - 1; 1227 assert (newDepth >= 0); 1228 THREAD_LOCAL_LOCK_DEPTH.set( 1229 (newDepth < lockIntegers.length) 1230 ? lockIntegers[newDepth] 1231 : new Integer (newDepth) 1232 ); 1233 return true; 1234 } 1235 1236 1243 public void runAtomic(Runnable r) { 1244 runAtomicAsUser(r); 1245 } 1246 1247 1251 public void runAtomicAsUser(Runnable r) { 1252 boolean completed = false; 1253 atomicLock(); 1254 try { 1255 r.run(); 1256 completed = true; 1257 } finally { 1258 try { 1259 if (!completed) { 1260 breakAtomicLock(); 1261 } 1262 } finally { 1263 atomicUnlock(); 1264 } 1265 } 1266 } 1267 1268 1272 public void read(Reader reader, int pos) 1273 throws IOException , BadLocationException { 1274 extWriteLock(); 1275 try { 1276 1277 if (pos < 0 || pos > getLength()) { 1278 throw new BadLocationException ("BaseDocument.read()", pos); } 1280 1281 if (inited || modified) { Analyzer.read(this, reader, pos); 1283 } else { Analyzer.initialRead(this, reader, true); 1285 inited = true; } 1287 if (debugRead) { 1288 System.err.println("BaseDocument.read(): StreamDescriptionProperty: "+getProperty(StreamDescriptionProperty)); 1289 } 1290 1291 Content content = getContent(); 1293 if (content instanceof DocumentContent) { 1294 ((DocumentContent)content).compact(); 1295 } 1296 } finally { 1297 extWriteUnlock(); 1298 } 1299 } 1300 1301 1306 public void write(Writer writer, int pos, int len) 1307 throws IOException , BadLocationException { 1308 readLock(); 1309 try { 1310 1311 if ((pos < 0) || ((pos + len) > getLength())) { 1312 throw new BadLocationException ("BaseDocument.write()", pos); } 1314 Analyzer.write(this, writer, pos, len); 1315 writer.flush(); 1316 } finally { 1317 readUnlock(); 1318 } 1319 } 1320 1321 1327 public void invalidateSyntaxMarks() { 1328 extWriteLock(); 1329 try { 1330 FixLineSyntaxState.invalidateAllSyntaxStateInfos(this); 1331 repaintBlock(0, getLength()); 1332 } finally { 1333 extWriteUnlock(); 1334 } 1335 } 1336 1337 1340 public int getTabSize() { 1341 return tabSize; 1342 } 1343 1344 1351 public int getShiftWidth() { 1352 if (shiftWidth != null) { 1353 return shiftWidth.intValue(); 1354 1355 } else { 1356 return getFormatter().getSpacesPerTab(); 1357 } 1358 } 1359 1360 public final Class getKitClass() { 1361 return kitClass; 1362 } 1363 1364 1367 public void resetUndoMerge() { 1368 undoMergeReset = true; 1369 } 1370 1371 1374 protected void fireChangedUpdate(DocumentEvent e) { 1375 super.fireChangedUpdate(e); 1376 } 1377 protected void fireInsertUpdate(DocumentEvent e) { 1378 super.fireInsertUpdate(e); 1379 } 1380 protected void fireRemoveUpdate(DocumentEvent e) { 1381 super.fireRemoveUpdate(e); 1382 } 1383 1384 protected void fireUndoableEditUpdate(UndoableEditEvent e) { 1385 Object [] listeners = (atomicLockListenerList != null) 1389 ? atomicLockListenerList 1390 : listenerList.getListenerList(); 1391 1392 for (int i = listeners.length - 2; i >= 0; i -= 2) { 1393 if (listeners[i] == UndoableEditListener .class) { 1394 ((UndoableEditListener )listeners[i + 1]).undoableEditHappened(e); 1395 } 1396 } 1397 } 1398 1399 1402 public synchronized final void extWriteLock() { 1403 if (Thread.currentThread() != getCurrentWriter()) { 1404 super.writeLock(); 1405 assert incrementThreadLocalLockDepth(); 1406 } else { writeDepth++; } 1409 } 1410 1411 1414 public synchronized final void extWriteUnlock() { 1415 if (Thread.currentThread() != getCurrentWriter()) { 1416 throw new RuntimeException (WRITE_LOCK_MISSING); 1417 } 1418 1419 if (writeDepth == 0) { assert decrementThreadLocalLockDepth(); 1421 super.writeUnlock(); 1422 } else { writeDepth--; 1424 } 1425 } 1426 1427 public final void atomicLock() { 1428 synchronized (this) { 1429 NotifyModifyStatus notifyModifyStatus = (NotifyModifyStatus)STATUS.get(); 1430 if (notifyModifyStatus == null) { 1431 notifyModifyStatus = new NotifyModifyStatus (this); 1433 STATUS.set (notifyModifyStatus); 1434 } else { 1436 } 1438 1439 extWriteLock(); 1440 atomicDepth++; 1441 if (atomicDepth == 1) { fireAtomicLock(atomicLockEventInstance); 1443 atomicLockListenerList = listenerList.getListenerList(); 1445 } 1446 } 1447 } 1448 1449 public final void atomicUnlock() { 1450 boolean modsDone = false; 1451 boolean lastAtomic = false; 1452 synchronized (this) { 1453 extWriteUnlock(); 1454 if (atomicDepth == 0) { 1455 throw new IllegalStateException ("atomicUnlock() without atomicLock()"); } 1457 1458 1459 if (--atomicDepth == 0) { lastAtomic = true; 1461 fireAtomicUnlock(atomicLockEventInstance); 1462 1463 if (atomicEdits != null && atomicEdits.size() > 0) { 1464 modsDone = true; 1465 atomicEdits.end(); 1467 fireUndoableEditUpdate(new UndoableEditEvent (this, atomicEdits)); 1468 atomicEdits = null; 1469 } 1470 1471 if (modsUndoneOrRedone) { modsUndoneOrRedone = false; 1473 modsDone = true; 1474 } 1475 atomicLockListenerList = null; 1476 } 1477 } 1478 1479 if (modsDone) { 1485 NotifyModifyStatus notifyModifyStatus = (NotifyModifyStatus)STATUS.get(); 1486 notifyModify(notifyModifyStatus); 1487 } 1488 1489 if (lastAtomic) { 1490 STATUS.set (null); 1491 } 1492 } 1493 1494 void markModsUndoneOrRedone() { 1495 modsUndoneOrRedone = true; 1496 } 1497 1498 1501 public final boolean isAtomicLock() { 1502 return (atomicDepth > 0); 1503 } 1504 1505 1510 public final void breakAtomicLock() { 1511 if (atomicEdits != null && atomicEdits.size() > 0) { 1512 atomicEdits.end(); 1513 atomicEdits.undo(); 1514 atomicEdits = null; 1515 } 1516 } 1517 1518 1522 private void notifyModify(NotifyModifyStatus notifyModifyStatus) { 1523 notifyModifyStatus.setModificationVetoed(false); 1524 VetoableChangeListener bml = notifyModifyStatus.getBeforeModificationListener(); 1525 if (bml != null) { 1526 try { 1527 bml.vetoableChange(new PropertyChangeEvent (this, "modified", null, Boolean.TRUE)); } catch (PropertyVetoException ex) { 1529 notifyModifyStatus.setModificationVetoed(true); 1531 } 1532 } 1533 } 1534 1535 1540 private void notifyUnmodify(NotifyModifyStatus notifyModifyStatus) { 1541 VetoableChangeListener bml = notifyModifyStatus.getBeforeModificationListener(); 1542 if (bml != null) { 1543 try { 1544 bml.vetoableChange(new PropertyChangeEvent (this, "modified", null, Boolean.FALSE)); } catch (PropertyVetoException e) { 1546 } 1548 notifyModifyStatus.setModificationVetoed(false); 1549 } 1550 } 1551 1552 public void atomicUndo() { 1553 breakAtomicLock(); 1554 } 1555 1556 public void addAtomicLockListener(AtomicLockListener l) { 1557 listenerList.add(AtomicLockListener.class, l); 1558 } 1559 1560 public void removeAtomicLockListener(AtomicLockListener l) { 1561 listenerList.remove(AtomicLockListener.class, l); 1562 } 1563 1564 private void fireAtomicLock(AtomicLockEvent evt) { 1565 EventListener [] listeners = listenerList.getListeners(AtomicLockListener.class); 1566 int cnt = listeners.length; 1567 for (int i = 0; i < cnt; i++) { 1568 ((AtomicLockListener)listeners[i]).atomicLock(evt); 1569 } 1570 } 1571 1572 private void fireAtomicUnlock(AtomicLockEvent evt) { 1573 EventListener [] listeners = listenerList.getListeners(AtomicLockListener.class); 1574 int cnt = listeners.length; 1575 for (int i = 0; i < cnt; i++) { 1576 ((AtomicLockListener)listeners[i]).atomicUnlock(evt); 1577 } 1578 } 1579 1580 protected final int getAtomicDepth() { 1581 return atomicDepth; 1582 } 1583 1584 public void addDocumentListener(DocumentListener listener) { 1585 if (!org.netbeans.lib.editor.util.swing.DocumentUtilities.addPriorityDocumentListener( 1586 this, listener, DocumentListenerPriority.DEFAULT)) 1587 super.addDocumentListener(listener); 1588 } 1589 1590 public void removeDocumentListener(DocumentListener listener) { 1591 if (!org.netbeans.lib.editor.util.swing.DocumentUtilities.removePriorityDocumentListener( 1592 this, listener, DocumentListenerPriority.DEFAULT)) 1593 super.removeDocumentListener(listener); 1594 } 1595 1596 protected BaseDocumentEvent createDocumentEvent(int pos, int length, 1597 DocumentEvent.EventType type) { 1598 return new BaseDocumentEvent(this, pos, length, type); 1599 } 1600 1601 1617 public void setPostModificationDocumentListener(DocumentListener listener) { 1618 this.postModificationDocumentListener = listener; 1619 } 1620 1621 1624 public boolean isModified() { 1625 return modified; 1626 } 1627 1628 1635 public DrawLayer findLayer(String layerName) { 1636 return drawLayerList.findLayer(layerName); 1637 } 1638 1639 1645 public boolean addLayer(DrawLayer layer, int visibility) { 1646 if (drawLayerList.add(layer, visibility)) { 1647 BaseDocumentEvent evt = createDocumentEvent(0, 0, DocumentEvent.EventType.CHANGE); 1648 evt.addEdit(new BaseDocumentEvent.DrawLayerChange(layer.getName(), visibility)); 1649 fireChangedUpdate(evt); 1650 return true; 1651 } else { 1652 return false; 1653 } 1654 } 1655 1656 final DrawLayerList getDrawLayerList() { 1657 return drawLayerList; 1658 } 1659 1660 private LineRootElement getLineRootElement() { 1661 return lineRootElement; 1662 } 1663 1664 public Element getParagraphElement(int pos) { 1665 return getLineRootElement().getElement( 1666 getLineRootElement().getElementIndex(pos)); 1667 } 1668 1669 1673 public Annotations getAnnotations() { 1674 synchronized (annotationsLock) { 1675 if (annotations == null) { 1676 annotations = new Annotations(this); 1677 } 1678 return annotations; 1679 } 1680 } 1681 1682 1685 void prepareSyntax(Segment text, Syntax syntax, int reqPos, int reqLen, 1686 boolean forceLastBuffer, boolean forceNotLastBuffer) throws BadLocationException { 1687 FixLineSyntaxState.prepareSyntax(this, text, syntax, reqPos, reqLen, 1688 forceLastBuffer, forceNotLastBuffer); 1689 } 1690 1691 int getTokenSafeOffset(int offset) { 1692 return FixLineSyntaxState.getTokenSafeOffset(this, offset); 1693 } 1694 1695 1702 int getOffsetFromVisCol(int visCol, int startLinePos) 1703 throws BadLocationException { 1704 1705 synchronized (getOffsetFromVisColLock) { 1706 if (startLinePos < 0 || startLinePos >= getLength()) { 1707 throw new BadLocationException ("Invalid start line offset", startLinePos); } 1709 if (visCol <= 0) { 1710 return startLinePos; 1711 } 1712 if (visColPosFwdFinder == null) { 1713 visColPosFwdFinder = new FinderFactory.VisColPosFwdFinder(); 1714 } 1715 visColPosFwdFinder.setVisCol(visCol); 1716 visColPosFwdFinder.setTabSize(getTabSize()); 1717 int pos = find(visColPosFwdFinder, startLinePos, -1); 1718 return (pos != -1) 1719 ? pos 1720 : Utilities.getRowEnd(this, startLinePos); 1721 } 1722 } 1723 1724 1730 int getVisColFromPos(int pos) throws BadLocationException { 1731 synchronized (getVisColFromPosLock) { 1732 if (pos < 0 || pos > getLength()) { 1733 throw new BadLocationException ("Invalid offset", pos); } 1735 1736 if (posVisColFwdFinder == null) { 1737 posVisColFwdFinder = new FinderFactory.PosVisColFwdFinder(); 1738 } 1739 1740 int startLinePos = Utilities.getRowStart(this, pos); 1741 posVisColFwdFinder.setTabSize(getTabSize()); 1742 find(posVisColFwdFinder, startLinePos, pos); 1743 return posVisColFwdFinder.getVisCol(); 1744 } 1745 } 1746 1747 protected Dictionary createDocumentProperties(Dictionary origDocumentProperties) { 1748 return new LazyPropertyMap(origDocumentProperties); 1749 } 1750 1751 public String toString() { 1752 return super.toString() + ", kitClass=" + getKitClass() + ", docLen=" + getLength(); } 1755 1756 1757 public String toStringDetail() { 1758 return toString(); 1759 } 1760 1761 1764 class AtomicCompoundEdit extends CompoundEdit { 1765 1766 private UndoableEdit previousEdit; 1767 1768 public void undo() throws CannotUndoException { 1769 atomicLock(); 1770 try { 1771 super.undo(); 1772 } finally { 1773 atomicUnlock(); 1774 } 1775 1776 if (previousEdit != null) { 1777 previousEdit.undo(); 1778 } 1779 1780 } 1781 1782 public void redo() throws CannotRedoException { 1783 if (previousEdit != null) { 1784 previousEdit.redo(); 1785 } 1786 1787 atomicLock(); 1788 try { 1789 super.redo(); 1790 } finally { 1791 atomicUnlock(); 1792 } 1793 } 1794 1795 public void die() { 1796 super.die(); 1797 1798 if (previousEdit != null) { 1799 previousEdit.die(); 1800 previousEdit = null; 1801 } 1802 } 1803 1804 public int size() { 1805 return edits.size(); 1806 } 1807 1808 public boolean replaceEdit(UndoableEdit anEdit) { 1809 UndoableEdit childEdit; 1810 if (size() == 1 && ((childEdit = (UndoableEdit )getEdits().get(0)) instanceof BaseDocumentEvent)) { 1811 BaseDocumentEvent childEvt = (BaseDocumentEvent)childEdit; 1812 if (anEdit instanceof BaseDocument.AtomicCompoundEdit) { 1813 BaseDocument.AtomicCompoundEdit compEdit 1814 = (BaseDocument.AtomicCompoundEdit)anEdit; 1815 1816 if (!undoMergeReset && compEdit.getEdits().size() == 1) { 1817 UndoableEdit edit = (UndoableEdit )compEdit.getEdits().get(0); 1818 if (edit instanceof BaseDocumentEvent && childEvt.canMerge((BaseDocumentEvent)edit)) { 1819 previousEdit = anEdit; 1820 return true; 1821 } 1822 } 1823 } else if (anEdit instanceof BaseDocumentEvent) { 1824 BaseDocumentEvent evt = (BaseDocumentEvent)anEdit; 1825 1826 if (!undoMergeReset && childEvt.canMerge(evt)) { 1827 previousEdit = anEdit; 1828 return true; 1829 } 1830 } 1831 } 1832 undoMergeReset = false; 1833 return false; 1834 } 1835 1836 java.util.Vector getEdits() { 1837 return edits; 1838 } 1839 1840 } 1841 1842 1847 public interface PropertyEvaluator { 1848 1849 1850 public Object getValue(); 1851 1852 } 1853 1854 protected static class LazyPropertyMap extends Hashtable { 1855 1856 protected LazyPropertyMap(Dictionary dict) { 1857 super(5); 1858 1859 Enumeration en = dict.keys(); 1860 while (en.hasMoreElements()) { 1861 Object key = en.nextElement(); 1862 put(key, dict.get(key)); 1863 } 1864 } 1865 1866 public Object get(Object key) { 1867 Object val = super.get(key); 1868 if (val instanceof PropertyEvaluator) { 1869 val = ((PropertyEvaluator)val).getValue(); 1870 } 1871 1872 return val; 1873 } 1874 1875 } 1876 1877 private static final class MarksStorageUndo extends AbstractUndoableEdit { 1878 1879 private DocumentEvent evt; 1880 1881 MarksStorageUndo(DocumentEvent evt) { 1882 this.evt = evt; 1883 } 1884 1885 private int getLength() { 1886 int length = evt.getLength(); 1887 if (evt.getType() == DocumentEvent.EventType.REMOVE) { 1888 length = -length; 1889 } 1890 return length; 1891 } 1892 1893 void updateMarksStorage() { 1894 BaseDocument doc = (BaseDocument)evt.getDocument(); 1895 doc.marksStorage.update(evt.getOffset(), getLength(), null); 1897 } 1898 1899 public void undo() throws CannotUndoException { 1900 BaseDocument doc = (BaseDocument)evt.getDocument(); 1901 doc.marksStorage.update(evt.getOffset(), -getLength(), null); 1903 super.undo(); 1904 } 1905 1906 public void redo() throws CannotRedoException { 1907 updateMarksStorage(); 1908 super.redo(); 1909 } 1910 1911 1912 } 1913 1914 private static final class NotifyModifyStatus { 1915 1922 private final VetoableChangeListener beforeModificationListener; 1923 1924 1932 private boolean modificationVetoed; 1933 1934 NotifyModifyStatus(BaseDocument document) { 1935 beforeModificationListener = (VetoableChangeListener )document.getProperty(BEFORE_MODIFICATION_LISTENER); 1936 } 1937 1938 public boolean isModificationVetoed() { 1939 return modificationVetoed; 1940 } 1941 1942 public void setModificationVetoed(boolean modificationVetoed) { 1943 this.modificationVetoed = modificationVetoed; 1944 } 1945 1946 public VetoableChangeListener getBeforeModificationListener() { 1947 return beforeModificationListener; 1948 } 1949 } 1950 1951} 1952 | Popular Tags |