1 11 package org.eclipse.text.undo; 12 13 import java.util.ArrayList ; 14 import java.util.List ; 15 16 import org.eclipse.core.commands.ExecutionException; 17 import org.eclipse.core.commands.operations.AbstractOperation; 18 import org.eclipse.core.commands.operations.IContextReplacingOperation; 19 import org.eclipse.core.commands.operations.IOperationHistory; 20 import org.eclipse.core.commands.operations.IOperationHistoryListener; 21 import org.eclipse.core.commands.operations.IUndoContext; 22 import org.eclipse.core.commands.operations.IUndoableOperation; 23 import org.eclipse.core.commands.operations.ObjectUndoContext; 24 import org.eclipse.core.commands.operations.OperationHistoryEvent; 25 import org.eclipse.core.commands.operations.OperationHistoryFactory; 26 27 import org.eclipse.core.runtime.Assert; 28 import org.eclipse.core.runtime.IAdaptable; 29 import org.eclipse.core.runtime.IProgressMonitor; 30 import org.eclipse.core.runtime.IStatus; 31 import org.eclipse.core.runtime.ListenerList; 32 import org.eclipse.core.runtime.Status; 33 34 import org.eclipse.jface.text.BadLocationException; 35 import org.eclipse.jface.text.DocumentEvent; 36 import org.eclipse.jface.text.IDocument; 37 import org.eclipse.jface.text.IDocumentExtension4; 38 import org.eclipse.jface.text.IDocumentListener; 39 import org.eclipse.jface.text.TextUtilities; 40 41 63 public class DocumentUndoManager implements IDocumentUndoManager { 64 65 66 73 private static class UndoableTextChange extends AbstractOperation { 74 75 76 protected int fStart= -1; 77 78 79 protected int fEnd= -1; 80 81 82 protected String fText; 83 84 85 protected String fPreservedText; 86 87 88 protected long fUndoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; 89 90 91 protected long fRedoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; 92 93 94 protected DocumentUndoManager fDocumentUndoManager; 95 96 101 UndoableTextChange(DocumentUndoManager manager) { 102 super(UndoMessages.getString("DocumentUndoManager.operationLabel")); this.fDocumentUndoManager= manager; 104 addContext(manager.getUndoContext()); 105 } 106 107 110 protected void reinitialize() { 111 fStart= fEnd= -1; 112 fText= fPreservedText= null; 113 fUndoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; 114 fRedoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; 115 } 116 117 123 protected void set(int start, int end) { 124 fStart= start; 125 fEnd= end; 126 fText= null; 127 fPreservedText= null; 128 } 129 130 133 public void dispose() { 134 reinitialize(); 135 } 136 137 140 protected void undoTextChange() { 141 try { 142 if (fDocumentUndoManager.fDocument instanceof IDocumentExtension4) 143 ((IDocumentExtension4) fDocumentUndoManager.fDocument).replace(fStart, fText 144 .length(), fPreservedText, fUndoModificationStamp); 145 else 146 fDocumentUndoManager.fDocument.replace(fStart, fText.length(), 147 fPreservedText); 148 } catch (BadLocationException x) { 149 } 150 } 151 152 155 public boolean canUndo() { 156 if (isValid()) { 157 if (fDocumentUndoManager.fDocument instanceof IDocumentExtension4) { 158 long docStamp= ((IDocumentExtension4) fDocumentUndoManager.fDocument) 159 .getModificationStamp(); 160 161 boolean canUndo= docStamp == IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP 164 || docStamp == getRedoModificationStamp(); 165 166 179 if (!canUndo 180 && this == fDocumentUndoManager.fHistory 181 .getUndoOperation(fDocumentUndoManager.fUndoContext) 182 && this != fDocumentUndoManager.fCurrent 184 && !fDocumentUndoManager.fCurrent.isValid() 186 && fDocumentUndoManager.fCurrent.fUndoModificationStamp != 189 IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP) { 191 canUndo= fDocumentUndoManager.fCurrent.fRedoModificationStamp == docStamp; 192 } 193 199 if (!canUndo 200 && this == fDocumentUndoManager.fHistory 201 .getUndoOperation(fDocumentUndoManager.fUndoContext) 202 && this instanceof UndoableCompoundTextChange 204 && this == fDocumentUndoManager.fCurrent 205 && this.fStart == -1 207 && fDocumentUndoManager.fCurrent.fRedoModificationStamp != IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP) { 209 canUndo= fDocumentUndoManager.fCurrent.fRedoModificationStamp == docStamp; 211 } 212 213 } 214 return true; 217 } 218 return false; 219 } 220 221 224 public boolean canRedo() { 225 if (isValid()) { 226 if (fDocumentUndoManager.fDocument instanceof IDocumentExtension4) { 227 long docStamp= ((IDocumentExtension4) fDocumentUndoManager.fDocument) 228 .getModificationStamp(); 229 return docStamp == IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP 230 || docStamp == getUndoModificationStamp(); 231 } 232 return true; 235 } 236 return false; 237 } 238 239 242 public boolean canExecute() { 243 return fDocumentUndoManager.isConnected(); 244 } 245 246 249 public IStatus execute(IProgressMonitor monitor, IAdaptable uiInfo) { 250 return Status.OK_STATUS; 253 } 254 255 259 public IStatus undo(IProgressMonitor monitor, IAdaptable uiInfo) { 260 if (isValid()) { 261 fDocumentUndoManager.fireDocumentUndo(fStart, fPreservedText, fText, uiInfo, DocumentUndoEvent.ABOUT_TO_UNDO, false); 262 undoTextChange(); 263 fDocumentUndoManager.resetProcessChangeState(); 264 fDocumentUndoManager.fireDocumentUndo(fStart, fPreservedText, fText, uiInfo, DocumentUndoEvent.UNDONE, false); 265 return Status.OK_STATUS; 266 } 267 return IOperationHistory.OPERATION_INVALID_STATUS; 268 } 269 270 273 protected void redoTextChange() { 274 try { 275 if (fDocumentUndoManager.fDocument instanceof IDocumentExtension4) 276 ((IDocumentExtension4) fDocumentUndoManager.fDocument).replace(fStart, fEnd - fStart, fText, fRedoModificationStamp); 277 else 278 fDocumentUndoManager.fDocument.replace(fStart, fEnd - fStart, fText); 279 } catch (BadLocationException x) { 280 } 281 } 282 283 291 public IStatus redo(IProgressMonitor monitor, IAdaptable uiInfo) { 292 if (isValid()) { 293 redoTextChange(); 294 fDocumentUndoManager.resetProcessChangeState(); 295 fDocumentUndoManager.fireDocumentUndo(fStart, fText, fPreservedText, uiInfo, DocumentUndoEvent.REDONE, false); 296 return Status.OK_STATUS; 297 } 298 return IOperationHistory.OPERATION_INVALID_STATUS; 299 } 300 301 304 305 protected void updateTextChange() { 306 fText= fDocumentUndoManager.fTextBuffer.toString(); 307 fDocumentUndoManager.fTextBuffer.setLength(0); 308 fPreservedText= fDocumentUndoManager.fPreservedTextBuffer.toString(); 309 fDocumentUndoManager.fPreservedTextBuffer.setLength(0); 310 } 311 312 318 protected UndoableTextChange createCurrent() { 319 if (fDocumentUndoManager.fFoldingIntoCompoundChange) 320 return new UndoableCompoundTextChange(fDocumentUndoManager); 321 return new UndoableTextChange(fDocumentUndoManager); 322 } 323 324 327 protected void commit() { 328 if (fStart < 0) { 329 if (fDocumentUndoManager.fFoldingIntoCompoundChange) { 330 fDocumentUndoManager.fCurrent= createCurrent(); 331 } else { 332 reinitialize(); 333 } 334 } else { 335 updateTextChange(); 336 fDocumentUndoManager.fCurrent= createCurrent(); 337 } 338 fDocumentUndoManager.resetProcessChangeState(); 339 } 340 341 345 protected void pretendCommit() { 346 if (fStart > -1) { 347 fText= fDocumentUndoManager.fTextBuffer.toString(); 348 fPreservedText= fDocumentUndoManager.fPreservedTextBuffer.toString(); 349 } 350 } 351 352 359 protected boolean attemptCommit() { 360 pretendCommit(); 361 if (isValid()) { 362 fDocumentUndoManager.commit(); 363 return true; 364 } 365 return false; 366 } 367 368 373 protected boolean isValid() { 374 return fStart > -1 && fEnd > -1 && fText != null; 375 } 376 377 380 public String toString() { 381 String delimiter= ", "; StringBuffer text= new StringBuffer (super.toString()); 383 text.append("\n"); text.append(this.getClass().getName()); 385 text.append(" undo modification stamp: "); text.append(fUndoModificationStamp); 387 text.append(" redo modification stamp: "); text.append(fRedoModificationStamp); 389 text.append(" start: "); text.append(fStart); 391 text.append(delimiter); 392 text.append("end: "); text.append(fEnd); 394 text.append(delimiter); 395 text.append("text: '"); text.append(fText); 397 text.append('\''); 398 text.append(delimiter); 399 text.append("preservedText: '"); text.append(fPreservedText); 401 text.append('\''); 402 return text.toString(); 403 } 404 405 410 protected long getUndoModificationStamp() { 411 return fUndoModificationStamp; 412 } 413 414 419 protected long getRedoModificationStamp() { 420 return fRedoModificationStamp; 421 } 422 } 423 424 425 429 private static class UndoableCompoundTextChange extends UndoableTextChange { 430 431 432 private List fChanges= new ArrayList (); 433 434 440 UndoableCompoundTextChange(DocumentUndoManager manager) { 441 super(manager); 442 } 443 444 449 protected void add(UndoableTextChange change) { 450 fChanges.add(change); 451 } 452 453 456 public IStatus undo(IProgressMonitor monitor, IAdaptable uiInfo) { 457 458 int size= fChanges.size(); 459 if (size > 0) { 460 UndoableTextChange c; 461 462 c= (UndoableTextChange) fChanges.get(0); 463 fDocumentUndoManager.fireDocumentUndo(c.fStart, c.fPreservedText, c.fText, uiInfo, DocumentUndoEvent.ABOUT_TO_UNDO, true); 464 465 for (int i= size - 1; i >= 0; --i) { 466 c= (UndoableTextChange) fChanges.get(i); 467 c.undoTextChange(); 468 } 469 fDocumentUndoManager.resetProcessChangeState(); 470 fDocumentUndoManager.fireDocumentUndo(c.fStart, c.fPreservedText, c.fText, uiInfo, 471 DocumentUndoEvent.UNDONE, true); 472 } 473 return Status.OK_STATUS; 474 } 475 476 479 public IStatus redo(IProgressMonitor monitor, IAdaptable uiInfo) { 480 481 int size= fChanges.size(); 482 if (size > 0) { 483 484 UndoableTextChange c; 485 c= (UndoableTextChange) fChanges.get(size - 1); 486 fDocumentUndoManager.fireDocumentUndo(c.fStart, c.fText, c.fPreservedText, uiInfo, DocumentUndoEvent.ABOUT_TO_REDO, true); 487 488 for (int i= 0; i <= size - 1; ++i) { 489 c= (UndoableTextChange) fChanges.get(i); 490 c.redoTextChange(); 491 } 492 fDocumentUndoManager.resetProcessChangeState(); 493 fDocumentUndoManager.fireDocumentUndo(c.fStart, c.fText, c.fPreservedText, uiInfo, 494 DocumentUndoEvent.REDONE, true); 495 } 496 497 return Status.OK_STATUS; 498 } 499 500 503 protected void updateTextChange() { 504 super.updateTextChange(); 506 507 UndoableTextChange c= new UndoableTextChange(fDocumentUndoManager); 509 c.fStart= fStart; 510 c.fEnd= fEnd; 511 c.fText= fText; 512 c.fPreservedText= fPreservedText; 513 c.fUndoModificationStamp= fUndoModificationStamp; 514 c.fRedoModificationStamp= fRedoModificationStamp; 515 add(c); 516 517 reinitialize(); 519 } 520 521 524 protected UndoableTextChange createCurrent() { 525 526 if (!fDocumentUndoManager.fFoldingIntoCompoundChange) 527 return new UndoableTextChange(fDocumentUndoManager); 528 529 reinitialize(); 530 return this; 531 } 532 533 536 protected void commit() { 537 if (fStart > -1) 539 updateTextChange(); 540 fDocumentUndoManager.fCurrent= createCurrent(); 541 fDocumentUndoManager.resetProcessChangeState(); 542 } 543 544 547 protected boolean isValid() { 548 return fStart > -1 || fChanges.size() > 0; 549 } 550 551 554 protected long getUndoModificationStamp() { 555 if (fStart > -1) 556 return super.getUndoModificationStamp(); 557 else if (fChanges.size() > 0) 558 return ((UndoableTextChange) fChanges.get(0)) 559 .getUndoModificationStamp(); 560 561 return fUndoModificationStamp; 562 } 563 564 567 protected long getRedoModificationStamp() { 568 if (fStart > -1) 569 return super.getRedoModificationStamp(); 570 else if (fChanges.size() > 0) 571 return ((UndoableTextChange) fChanges.get(fChanges.size() - 1)) 572 .getRedoModificationStamp(); 573 574 return fRedoModificationStamp; 575 } 576 } 577 578 579 582 private class DocumentListener implements IDocumentListener { 583 584 private String fReplacedText; 585 586 589 public void documentAboutToBeChanged(DocumentEvent event) { 590 try { 591 fReplacedText= event.getDocument().get(event.getOffset(), 592 event.getLength()); 593 fPreservedUndoModificationStamp= event.getModificationStamp(); 594 } catch (BadLocationException x) { 595 fReplacedText= null; 596 } 597 } 598 599 602 public void documentChanged(DocumentEvent event) { 603 fPreservedRedoModificationStamp= event.getModificationStamp(); 604 605 IUndoableOperation op= fHistory.getUndoOperation(fUndoContext); 609 boolean wasValid= false; 610 if (op != null) 611 wasValid= op.canUndo(); 612 processChange(event.getOffset(), event.getOffset() 614 + event.getLength(), event.getText(), fReplacedText, 615 fPreservedUndoModificationStamp, 616 fPreservedRedoModificationStamp); 617 618 fCurrent.pretendCommit(); 621 622 if (op == fCurrent) { 623 if (wasValid != fCurrent.isValid()) 628 fHistory.operationChanged(op); 629 } else { 630 if (fCurrent != fLastAddedTextEdit && fCurrent.isValid()) { 635 addToOperationHistory(fCurrent); 636 } 637 } 638 } 639 } 640 641 644 private class HistoryListener implements IOperationHistoryListener { 645 646 private IUndoableOperation fOperation; 647 648 public void historyNotification(final OperationHistoryEvent event) { 649 final int type= event.getEventType(); 650 switch (type) { 651 case OperationHistoryEvent.ABOUT_TO_UNDO: 652 case OperationHistoryEvent.ABOUT_TO_REDO: 653 if (event.getOperation().hasContext(fUndoContext)) { 655 if (event.getOperation() instanceof UndoableTextChange) { 659 listenToTextChanges(false); 660 661 if (type == OperationHistoryEvent.ABOUT_TO_UNDO) { 663 if (fFoldingIntoCompoundChange) { 664 endCompoundChange(); 665 } 666 } 667 } else { 668 commit(); 672 fLastAddedTextEdit= null; 673 } 674 fOperation= event.getOperation(); 675 } 676 break; 677 case OperationHistoryEvent.UNDONE: 678 case OperationHistoryEvent.REDONE: 679 case OperationHistoryEvent.OPERATION_NOT_OK: 680 if (event.getOperation() == fOperation) { 681 listenToTextChanges(true); 682 fOperation= null; 683 } 684 break; 685 } 686 } 687 688 } 689 690 693 private ObjectUndoContext fUndoContext; 694 695 698 private IDocument fDocument; 699 700 703 private UndoableTextChange fCurrent; 704 705 708 private DocumentListener fDocumentListener; 709 710 713 private boolean fFoldingIntoCompoundChange= false; 714 715 718 private IOperationHistory fHistory; 719 720 724 private IOperationHistoryListener fHistoryListener; 725 726 731 private UndoableTextChange fLastAddedTextEdit= null; 732 733 736 private long fPreservedRedoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; 737 738 741 private StringBuffer fPreservedTextBuffer; 742 743 746 private long fPreservedUndoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; 747 748 751 private UndoableTextChange fPreviousDelete; 752 753 756 private StringBuffer fTextBuffer; 757 758 759 private boolean fInserting= false; 760 761 762 private boolean fOverwriting= false; 763 764 765 private ListenerList fDocumentUndoListeners; 766 767 768 private List fConnected; 769 770 776 public DocumentUndoManager(IDocument document) { 777 super(); 778 Assert.isNotNull(document); 779 fDocument= document; 780 fHistory= OperationHistoryFactory.getOperationHistory(); 781 fUndoContext= new ObjectUndoContext(fDocument); 782 fConnected= new ArrayList (); 783 fDocumentUndoListeners= new ListenerList(); 784 } 785 786 789 public void addDocumentUndoListener(IDocumentUndoListener listener) { 790 fDocumentUndoListeners.add(listener); 791 } 792 793 796 public void removeDocumentUndoListener(IDocumentUndoListener listener) { 797 fDocumentUndoListeners.remove(listener); 798 } 799 800 803 public IUndoContext getUndoContext() { 804 return fUndoContext; 805 } 806 807 810 public void commit() { 811 if (fLastAddedTextEdit != fCurrent) { 815 fCurrent.pretendCommit(); 816 if (fCurrent.isValid()) 817 addToOperationHistory(fCurrent); 818 } 819 fCurrent.commit(); 820 } 821 822 825 public void reset() { 826 if (isConnected()) { 827 shutdown(); 828 initialize(); 829 } 830 } 831 832 835 public boolean redoable() { 836 return OperationHistoryFactory.getOperationHistory().canRedo(fUndoContext); 837 } 838 839 842 public boolean undoable() { 843 return OperationHistoryFactory.getOperationHistory().canUndo(fUndoContext); 844 } 845 846 849 public void redo() throws ExecutionException { 850 if (isConnected() && redoable()) 851 OperationHistoryFactory.getOperationHistory().redo(getUndoContext(), null, null); 852 } 853 854 857 public void undo() throws ExecutionException { 858 if (undoable()) 859 OperationHistoryFactory.getOperationHistory().undo(fUndoContext, null, null); 860 } 861 862 865 public void connect(Object client) { 866 if (!isConnected()) { 867 initialize(); 868 } 869 if (!fConnected.contains(client)) 870 fConnected.add(client); 871 } 872 873 876 public void disconnect(Object client) { 877 fConnected.remove(client); 878 if (!isConnected()) { 879 shutdown(); 880 } 881 } 882 883 886 public void beginCompoundChange() { 887 if (isConnected()) { 888 fFoldingIntoCompoundChange= true; 889 commit(); 890 } 891 } 892 893 896 public void endCompoundChange() { 897 if (isConnected()) { 898 fFoldingIntoCompoundChange= false; 899 commit(); 900 } 901 } 902 903 906 public void setMaximalUndoLevel(int undoLimit) { 907 fHistory.setLimit(fUndoContext, undoLimit); 908 } 909 910 922 void fireDocumentUndo(int offset, String text, String preservedText, Object source, int eventType, boolean isCompound) { 923 eventType= isCompound ? eventType | DocumentUndoEvent.COMPOUND : eventType; 924 DocumentUndoEvent event= new DocumentUndoEvent(fDocument, offset, text, preservedText, eventType, source); 925 Object [] listeners= fDocumentUndoListeners.getListeners(); 926 for (int i= 0; i < listeners.length; i++) { 927 ((IDocumentUndoListener)listeners[i]).documentUndoNotification(event); 928 } 929 } 930 931 935 private void addListeners() { 936 fHistoryListener= new HistoryListener(); 937 fHistory.addOperationHistoryListener(fHistoryListener); 938 listenToTextChanges(true); 939 } 940 941 944 private void removeListeners() { 945 listenToTextChanges(false); 946 fHistory.removeOperationHistoryListener(fHistoryListener); 947 fHistoryListener= null; 948 } 949 950 957 private void addToOperationHistory(UndoableTextChange edit) { 958 if (!fFoldingIntoCompoundChange 959 || edit instanceof UndoableCompoundTextChange) { 960 fHistory.add(edit); 961 fLastAddedTextEdit= edit; 962 } 963 } 964 965 968 private void disposeUndoHistory() { 969 fHistory.dispose(fUndoContext, true, true, true); 970 } 971 972 975 private void initializeUndoHistory() { 976 if (fHistory != null && fUndoContext != null) 977 fHistory.dispose(fUndoContext, true, true, false); 978 979 } 980 981 989 private boolean isWhitespaceText(String text) { 990 991 if (text == null || text.length() == 0) 992 return false; 993 994 String [] delimiters= fDocument.getLegalLineDelimiters(); 995 int index= TextUtilities.startsWith(delimiters, text); 996 if (index > -1) { 997 char c; 998 int length= text.length(); 999 for (int i= delimiters[index].length(); i < length; i++) { 1000 c= text.charAt(i); 1001 if (c != ' ' && c != '\t') 1002 return false; 1003 } 1004 return true; 1005 } 1006 1007 return false; 1008 } 1009 1010 1015 private void listenToTextChanges(boolean listen) { 1016 if (listen) { 1017 if (fDocumentListener == null && fDocument != null) { 1018 fDocumentListener= new DocumentListener(); 1019 fDocument.addDocumentListener(fDocumentListener); 1020 } 1021 } else if (!listen) { 1022 if (fDocumentListener != null && fDocument != null) { 1023 fDocument.removeDocumentListener(fDocumentListener); 1024 fDocumentListener= null; 1025 } 1026 } 1027 } 1028 1029 private void processChange(int modelStart, int modelEnd, 1030 String insertedText, String replacedText, 1031 long beforeChangeModificationStamp, 1032 long afterChangeModificationStamp) { 1033 1034 if (insertedText == null) 1035 insertedText= ""; 1037 if (replacedText == null) 1038 replacedText= ""; 1040 int length= insertedText.length(); 1041 int diff= modelEnd - modelStart; 1042 1043 if (fCurrent.fUndoModificationStamp == IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP) 1044 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp; 1045 1046 if (diff < 0) { 1048 int tmp= modelEnd; 1049 modelEnd= modelStart; 1050 modelStart= tmp; 1051 } 1052 1053 if (modelStart == modelEnd) { 1054 if ((length == 1) || isWhitespaceText(insertedText)) { 1056 if (!fInserting 1058 || (modelStart != fCurrent.fStart 1059 + fTextBuffer.length())) { 1060 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp; 1061 if (fCurrent.attemptCommit()) 1062 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp; 1063 1064 fInserting= true; 1065 } 1066 if (fCurrent.fStart < 0) 1067 fCurrent.fStart= fCurrent.fEnd= modelStart; 1068 if (length > 0) 1069 fTextBuffer.append(insertedText); 1070 } else if (length > 0) { 1071 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp; 1073 if (fCurrent.attemptCommit()) 1074 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp; 1075 1076 fCurrent.fStart= fCurrent.fEnd= modelStart; 1077 fTextBuffer.append(insertedText); 1078 fCurrent.fRedoModificationStamp= afterChangeModificationStamp; 1079 if (fCurrent.attemptCommit()) 1080 fCurrent.fUndoModificationStamp= afterChangeModificationStamp; 1081 1082 } 1083 } else { 1084 if (length == 0) { 1085 length= replacedText.length(); 1088 String [] delimiters= fDocument.getLegalLineDelimiters(); 1089 1090 if ((length == 1) 1091 || TextUtilities.equals(delimiters, replacedText) > -1) { 1092 1093 1095 if (fPreviousDelete.fStart == modelStart 1096 && fPreviousDelete.fEnd == modelEnd) { 1097 1099 if (fCurrent.fStart == modelEnd 1101 && fCurrent.fEnd == modelStart) { 1102 fCurrent.fStart= modelStart; 1103 fCurrent.fEnd= modelEnd; 1104 } 1105 fPreservedTextBuffer.append(replacedText); 1107 ++fCurrent.fEnd; 1108 1109 } else if (fPreviousDelete.fStart == modelEnd) { 1110 1112 fPreservedTextBuffer.insert(0, replacedText); 1114 fCurrent.fStart= modelStart; 1115 1116 } else { 1117 1119 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp; 1120 if (fCurrent.attemptCommit()) 1121 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp; 1122 1123 fPreservedTextBuffer.append(replacedText); 1126 fCurrent.fStart= modelStart; 1127 fCurrent.fEnd= modelEnd; 1128 } 1129 1130 fPreviousDelete.set(modelStart, modelEnd); 1131 1132 } else if (length > 0) { 1133 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp; 1135 if (fCurrent.attemptCommit()) 1136 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp; 1137 1138 fCurrent.fStart= modelStart; 1139 fCurrent.fEnd= modelEnd; 1140 fPreservedTextBuffer.append(replacedText); 1141 } 1142 } else { 1143 1145 if (length == 1) { 1146 length= replacedText.length(); 1147 String [] delimiters= fDocument.getLegalLineDelimiters(); 1148 1149 if ((length == 1) 1150 || TextUtilities.equals(delimiters, replacedText) > -1) { 1151 if (!fOverwriting 1153 || (modelStart != fCurrent.fStart 1154 + fTextBuffer.length())) { 1155 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp; 1156 if (fCurrent.attemptCommit()) 1157 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp; 1158 1159 fOverwriting= true; 1160 } 1161 1162 if (fCurrent.fStart < 0) 1163 fCurrent.fStart= modelStart; 1164 1165 fCurrent.fEnd= modelEnd; 1166 fTextBuffer.append(insertedText); 1167 fPreservedTextBuffer.append(replacedText); 1168 fCurrent.fRedoModificationStamp= afterChangeModificationStamp; 1169 return; 1170 } 1171 } 1172 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp; 1174 if (fCurrent.attemptCommit()) 1175 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp; 1176 1177 fCurrent.fStart= modelStart; 1178 fCurrent.fEnd= modelEnd; 1179 fTextBuffer.append(insertedText); 1180 fPreservedTextBuffer.append(replacedText); 1181 } 1182 } 1183 fCurrent.fRedoModificationStamp= afterChangeModificationStamp; 1186 } 1187 1188 1191 private void initialize() { 1192 initializeUndoHistory(); 1193 1194 fCurrent= new UndoableTextChange(this); 1196 fPreviousDelete= new UndoableTextChange(this); 1197 fTextBuffer= new StringBuffer (); 1198 fPreservedTextBuffer= new StringBuffer (); 1199 1200 addListeners(); 1201 } 1202 1203 1208 private void resetProcessChangeState() { 1209 fInserting= false; 1210 fOverwriting= false; 1211 fPreviousDelete.reinitialize(); 1212 } 1213 1214 1217 private void shutdown() { 1218 removeListeners(); 1219 1220 fCurrent= null; 1221 fPreviousDelete= null; 1222 fTextBuffer= null; 1223 fPreservedTextBuffer= null; 1224 1225 disposeUndoHistory(); 1226 } 1227 1228 1234 boolean isConnected() { 1235 if (fConnected == null) 1236 return false; 1237 return !fConnected.isEmpty(); 1238 } 1239 1240 1243 public void transferUndoHistory(IDocumentUndoManager manager) { 1244 IUndoContext oldUndoContext= manager.getUndoContext(); 1245 IUndoableOperation [] operations= OperationHistoryFactory.getOperationHistory().getUndoHistory(oldUndoContext); 1247 for (int i= 0; i< operations.length; i++) { 1248 IUndoableOperation op= operations[i]; 1250 if (op instanceof IContextReplacingOperation) { 1251 ((IContextReplacingOperation)op).replaceContext(oldUndoContext, getUndoContext()); 1252 } else { 1253 op.addContext(getUndoContext()); 1254 op.removeContext(oldUndoContext); 1255 } 1256 if (op instanceof UndoableTextChange) { 1258 ((UndoableTextChange)op).fDocumentUndoManager= this; 1259 } 1260 } 1261 1262 IUndoableOperation op= OperationHistoryFactory.getOperationHistory().getUndoOperation(getUndoContext()); 1268 UndoableTextChange cmd= new UndoableTextChange(this); 1269 cmd.fStart= cmd.fEnd= 0; 1270 cmd.fText= cmd.fPreservedText= ""; if (fDocument instanceof IDocumentExtension4) { 1272 cmd.fRedoModificationStamp= ((IDocumentExtension4)fDocument).getModificationStamp(); 1273 if (op instanceof UndoableTextChange) { 1274 cmd.fUndoModificationStamp= ((UndoableTextChange)op).fRedoModificationStamp; 1275 } 1276 } 1277 addToOperationHistory(cmd); 1278 } 1279 1280} 1281 | Popular Tags |