1 11 12 package org.eclipse.jface.text; 13 14 15 import java.util.ArrayList ; 16 import java.util.List ; 17 18 import org.eclipse.swt.SWT; 19 import org.eclipse.swt.custom.StyledText; 20 import org.eclipse.swt.events.KeyEvent; 21 import org.eclipse.swt.events.KeyListener; 22 import org.eclipse.swt.events.MouseEvent; 23 import org.eclipse.swt.events.MouseListener; 24 import org.eclipse.swt.widgets.Display; 25 import org.eclipse.swt.widgets.Shell; 26 27 import org.eclipse.core.commands.ExecutionException; 28 import org.eclipse.core.commands.operations.AbstractOperation; 29 import org.eclipse.core.commands.operations.IOperationHistory; 30 import org.eclipse.core.commands.operations.IOperationHistoryListener; 31 import org.eclipse.core.commands.operations.IUndoContext; 32 import org.eclipse.core.commands.operations.IUndoableOperation; 33 import org.eclipse.core.commands.operations.ObjectUndoContext; 34 import org.eclipse.core.commands.operations.OperationHistoryEvent; 35 import org.eclipse.core.commands.operations.OperationHistoryFactory; 36 37 import org.eclipse.core.runtime.IAdaptable; 38 import org.eclipse.core.runtime.IProgressMonitor; 39 import org.eclipse.core.runtime.IStatus; 40 import org.eclipse.core.runtime.Status; 41 42 import org.eclipse.jface.dialogs.MessageDialog; 43 44 45 73 public class DefaultUndoManager implements IUndoManager, IUndoManagerExtension { 74 75 81 class TextCommand extends AbstractOperation { 82 83 84 protected int fStart= -1; 85 86 protected int fEnd= -1; 87 88 protected String fText; 89 90 protected String fPreservedText; 91 92 93 protected long fUndoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; 94 95 protected long fRedoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; 96 97 103 TextCommand(IUndoContext context) { 104 super(JFaceTextMessages.getString("DefaultUndoManager.operationLabel")); addContext(context); 106 } 107 108 111 protected void reinitialize() { 112 fStart= fEnd= -1; 113 fText= fPreservedText= null; 114 fUndoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; 115 fRedoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; 116 } 117 118 124 protected void set(int start, int end) { 125 fStart= start; 126 fEnd= end; 127 fText= null; 128 fPreservedText= null; 129 } 130 131 135 public void dispose() { 136 reinitialize(); 137 } 138 139 144 protected void undoTextChange() { 145 try { 146 IDocument document= fTextViewer.getDocument(); 147 if (document instanceof IDocumentExtension4) 148 ((IDocumentExtension4)document).replace(fStart, fText.length(), fPreservedText, fUndoModificationStamp); 149 else 150 document.replace(fStart, fText.length(), fPreservedText); 151 } catch (BadLocationException x) { 152 } 153 } 154 155 159 public boolean canUndo() { 160 161 if (isConnected() && isValid()) { 162 IDocument doc= fTextViewer.getDocument(); 163 if (doc instanceof IDocumentExtension4) { 164 long docStamp= ((IDocumentExtension4)doc).getModificationStamp(); 165 166 boolean canUndo= docStamp == IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP || 169 docStamp == getRedoModificationStamp(); 170 171 182 if (!canUndo && 183 this == fHistory.getUndoOperation(fUndoContext) && this != fCurrent && !fCurrent.isValid() && fCurrent.fUndoModificationStamp != IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP) { 188 canUndo= fCurrent.fRedoModificationStamp == docStamp; 189 } 190 196 if (!canUndo && 197 this == fHistory.getUndoOperation(fUndoContext) && this instanceof CompoundTextCommand && 199 this == fCurrent && this.fStart == -1 && fCurrent.fRedoModificationStamp != IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP) { canUndo= fCurrent.fRedoModificationStamp == docStamp; 203 } 204 205 } 206 return true; 208 } 209 return false; 210 } 211 212 216 public boolean canRedo() { 217 if (isConnected() && isValid()) { 218 IDocument doc= fTextViewer.getDocument(); 219 if (doc instanceof IDocumentExtension4) { 220 long docStamp= ((IDocumentExtension4)doc).getModificationStamp(); 221 return docStamp == IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP || 222 docStamp == getUndoModificationStamp(); 223 } 224 return true; 226 } 227 return false; 228 } 229 230 234 public boolean canExecute() { 235 return isConnected(); 236 } 237 238 242 public IStatus execute(IProgressMonitor monitor, IAdaptable uiInfo) { 243 return Status.OK_STATUS; 245 } 246 247 251 252 260 public IStatus undo(IProgressMonitor monitor, IAdaptable uiInfo) { 261 if (isValid()) { 262 undoTextChange(); 263 selectAndReveal(fStart, fPreservedText == null ? 0 : fPreservedText.length()); 264 resetProcessChangeSate(); 265 return Status.OK_STATUS; 266 } 267 return IOperationHistory.OPERATION_INVALID_STATUS; 268 } 269 270 275 protected void redoTextChange() { 276 try { 277 IDocument document= fTextViewer.getDocument(); 278 if (document instanceof IDocumentExtension4) 279 ((IDocumentExtension4)document).replace(fStart, fEnd - fStart, fText, fRedoModificationStamp); 280 else 281 fTextViewer.getDocument().replace(fStart, fEnd - fStart, fText); 282 } catch (BadLocationException x) { 283 } 284 } 285 286 294 public IStatus redo(IProgressMonitor monitor, IAdaptable uiInfo) { 295 if (isValid()) { 296 redoTextChange(); 297 resetProcessChangeSate(); 298 selectAndReveal(fStart, fText == null ? 0 : fText.length()); 299 return Status.OK_STATUS; 300 } 301 return IOperationHistory.OPERATION_INVALID_STATUS; 302 } 303 304 309 310 protected void updateCommand() { 311 fText= fTextBuffer.toString(); 312 fTextBuffer.setLength(0); 313 fPreservedText= fPreservedTextBuffer.toString(); 314 fPreservedTextBuffer.setLength(0); 315 } 316 317 323 protected TextCommand createCurrent() { 324 return fFoldingIntoCompoundChange ? new CompoundTextCommand(fUndoContext) : new TextCommand(fUndoContext); 325 } 326 327 330 protected void commit() { 331 if (fStart < 0) { 332 if (fFoldingIntoCompoundChange) { 333 fCurrent= createCurrent(); 334 } else { 335 reinitialize(); 336 } 337 } else { 338 updateCommand(); 339 fCurrent= createCurrent(); 340 } 341 resetProcessChangeSate(); 342 } 343 344 350 protected void pretendCommit() { 351 if (fStart > -1) { 352 fText= fTextBuffer.toString(); 353 fPreservedText= fPreservedTextBuffer.toString(); 354 } 355 } 356 357 365 protected boolean attemptCommit() { 366 pretendCommit(); 367 if (isValid()) { 368 DefaultUndoManager.this.commit(); 369 return true; 370 } 371 return false; 372 } 373 374 380 protected boolean isValid() { 381 return fStart > -1 && 382 fEnd > -1 && 383 fText != null; 384 } 385 386 390 public String toString() { 391 String delimiter= ", "; StringBuffer text= new StringBuffer (super.toString()); 393 text.append("\n"); text.append(this.getClass().getName()); 395 text.append(" undo modification stamp: "); text.append(fUndoModificationStamp); 397 text.append(" redo modification stamp: "); text.append(fRedoModificationStamp); 399 text.append(" start: "); text.append(fStart); 401 text.append(delimiter); 402 text.append("end: "); text.append(fEnd); 404 text.append(delimiter); 405 text.append("text: '"); text.append(fText); 407 text.append('\''); 408 text.append(delimiter); 409 text.append("preservedText: '"); text.append(fPreservedText); 411 text.append('\''); 412 return text.toString(); 413 } 414 415 421 protected long getUndoModificationStamp() { 422 return fUndoModificationStamp; 423 } 424 425 431 protected long getRedoModificationStamp() { 432 return fRedoModificationStamp; 433 } 434 } 435 436 440 class CompoundTextCommand extends TextCommand { 441 442 443 private List fCommands= new ArrayList (); 444 445 451 CompoundTextCommand(IUndoContext context) { 452 super(context); 453 } 454 455 460 protected void add(TextCommand command) { 461 fCommands.add(command); 462 } 463 464 467 public IStatus undo(IProgressMonitor monitor, IAdaptable uiInfo) { 468 resetProcessChangeSate(); 469 470 int size= fCommands.size(); 471 if (size > 0) { 472 473 TextCommand c; 474 475 for (int i= size -1; i > 0; --i) { 476 c= (TextCommand) fCommands.get(i); 477 c.undoTextChange(); 478 } 479 480 c= (TextCommand) fCommands.get(0); 481 c.undo(monitor, uiInfo); 482 } 483 484 return Status.OK_STATUS; 485 } 486 487 490 public IStatus redo(IProgressMonitor monitor, IAdaptable uiInfo) { 491 resetProcessChangeSate(); 492 493 int size= fCommands.size(); 494 if (size > 0) { 495 496 TextCommand c; 497 498 for (int i= 0; i < size -1; ++i) { 499 c= (TextCommand) fCommands.get(i); 500 c.redoTextChange(); 501 } 502 503 c= (TextCommand) fCommands.get(size -1); 504 c.redo(monitor, uiInfo); 505 } 506 return Status.OK_STATUS; 507 } 508 509 513 514 protected void updateCommand() { 515 super.updateCommand(); 517 518 TextCommand c= new TextCommand(fUndoContext); 520 c.fStart= fStart; 521 c.fEnd= fEnd; 522 c.fText= fText; 523 c.fPreservedText= fPreservedText; 524 c.fUndoModificationStamp= fUndoModificationStamp; 525 c.fRedoModificationStamp= fRedoModificationStamp; 526 add(c); 527 528 reinitialize(); 530 } 531 532 535 protected TextCommand createCurrent() { 536 537 if (!fFoldingIntoCompoundChange) 538 return new TextCommand(fUndoContext); 539 540 reinitialize(); 541 return this; 542 } 543 544 547 protected void commit() { 548 if (fStart > -1) 550 updateCommand(); 551 fCurrent= createCurrent(); 552 resetProcessChangeSate(); 553 } 554 555 561 protected boolean isValid() { 562 if (isConnected()) 563 return (fStart > -1 || fCommands.size() > 0); 564 return false; 565 } 566 567 573 protected long getUndoModificationStamp() { 574 if (fStart > -1) 575 return super.getUndoModificationStamp(); 576 else if (fCommands.size() > 0) 577 return ((TextCommand)fCommands.get(0)).getUndoModificationStamp(); 578 579 return fUndoModificationStamp; 580 } 581 582 588 protected long getRedoModificationStamp() { 589 if (fStart > -1) 590 return super.getRedoModificationStamp(); 591 else if (fCommands.size() > 0) 592 return ((TextCommand)fCommands.get(fCommands.size()-1)).getRedoModificationStamp(); 593 594 return fRedoModificationStamp; 595 } 596 } 597 598 601 class KeyAndMouseListener implements MouseListener, KeyListener { 602 603 606 public void mouseDoubleClick(MouseEvent e) { 607 } 608 609 613 public void mouseDown(MouseEvent e) { 614 if (e.button == 1) 615 commit(); 616 } 617 618 621 public void mouseUp(MouseEvent e) { 622 } 623 624 627 public void keyReleased(KeyEvent e) { 628 } 629 630 634 public void keyPressed(KeyEvent e) { 635 switch (e.keyCode) { 636 case SWT.ARROW_UP: 637 case SWT.ARROW_DOWN: 638 case SWT.ARROW_LEFT: 639 case SWT.ARROW_RIGHT: 640 commit(); 641 break; 642 } 643 } 644 } 645 646 649 class DocumentListener implements IDocumentListener { 650 651 private String fReplacedText; 652 653 656 public void documentAboutToBeChanged(DocumentEvent event) { 657 try { 658 fReplacedText= event.getDocument().get(event.getOffset(), event.getLength()); 659 fPreservedUndoModificationStamp= event.getModificationStamp(); 660 } catch (BadLocationException x) { 661 fReplacedText= null; 662 } 663 } 664 665 668 public void documentChanged(DocumentEvent event) { 669 fPreservedRedoModificationStamp= event.getModificationStamp(); 670 671 IUndoableOperation op= fHistory.getUndoOperation(fUndoContext); 674 boolean wasValid= false; 675 if (op != null) 676 wasValid= op.canUndo(); 677 processChange(event.getOffset(), event.getOffset() + event.getLength(), event.getText(), fReplacedText, fPreservedUndoModificationStamp, fPreservedRedoModificationStamp); 679 680 fCurrent.pretendCommit(); 682 683 if (op == fCurrent) { 684 if (wasValid != fCurrent.isValid()) 687 fHistory.operationChanged(op); 688 } 689 else { 690 if (fCurrent != fLastAddedCommand && fCurrent.isValid()) { 693 addToCommandStack(fCurrent); 694 } 695 } 696 } 697 } 698 699 702 class TextInputListener implements ITextInputListener { 703 704 707 public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { 708 if (oldInput != null && fDocumentListener != null) { 709 oldInput.removeDocumentListener(fDocumentListener); 710 commit(); 711 } 712 } 713 714 717 public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { 718 if (newInput != null) { 719 if (fDocumentListener == null) 720 fDocumentListener= new DocumentListener(); 721 newInput.addDocumentListener(fDocumentListener); 722 } 723 } 724 725 } 726 727 731 class HistoryListener implements IOperationHistoryListener { 732 private IUndoableOperation fOperation; 733 734 public void historyNotification(final OperationHistoryEvent event) { 735 final int type= event.getEventType(); 736 switch (type) { 737 case OperationHistoryEvent.ABOUT_TO_UNDO: 738 case OperationHistoryEvent.ABOUT_TO_REDO: 739 if (event.getOperation().hasContext(fUndoContext)) { 741 fTextViewer.getTextWidget().getDisplay().syncExec(new Runnable () { 742 public void run() { 743 if (event.getOperation() instanceof TextCommand) { 746 if (fTextViewer instanceof TextViewer) 747 ((TextViewer)fTextViewer).ignoreAutoEditStrategies(true); 748 listenToTextChanges(false); 749 750 if (type == OperationHistoryEvent.ABOUT_TO_UNDO) { 752 if (fFoldingIntoCompoundChange) { 753 endCompoundChange(); 754 } 755 } 756 } else { 757 commit(); 761 fLastAddedCommand= null; 762 } 763 } 764 }); 765 fOperation= event.getOperation(); 766 } 767 break; 768 case OperationHistoryEvent.UNDONE: 769 case OperationHistoryEvent.REDONE: 770 case OperationHistoryEvent.OPERATION_NOT_OK: 771 if (event.getOperation() == fOperation) { 772 fTextViewer.getTextWidget().getDisplay().syncExec(new Runnable () { 773 public void run() { 774 listenToTextChanges(true); 775 fOperation= null; 776 if (fTextViewer instanceof TextViewer) 777 ((TextViewer)fTextViewer).ignoreAutoEditStrategies(false); 778 } 779 }); 780 } 781 break; 782 } 783 } 784 785 } 786 787 788 private StringBuffer fTextBuffer= new StringBuffer (); 789 790 private StringBuffer fPreservedTextBuffer= new StringBuffer (); 791 792 protected long fPreservedUndoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; 793 794 protected long fPreservedRedoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; 795 796 private KeyAndMouseListener fKeyAndMouseListener; 797 798 private DocumentListener fDocumentListener; 799 800 private TextInputListener fTextInputListener; 801 802 803 804 private boolean fInserting= false; 805 806 private boolean fOverwriting= false; 807 808 private boolean fFoldingIntoCompoundChange= false; 809 810 811 private ITextViewer fTextViewer; 812 813 814 private int fUndoLevel; 815 816 private TextCommand fCurrent; 817 818 private TextCommand fPreviousDelete; 819 820 824 private IOperationHistory fHistory; 825 829 private IUndoContext fUndoContext; 830 835 private IOperationHistoryListener fHistoryListener= new HistoryListener(); 836 837 842 private TextCommand fLastAddedCommand= null; 843 844 849 public DefaultUndoManager(int undoLevel) { 850 fHistory= OperationHistoryFactory.getOperationHistory(); 851 setMaximalUndoLevel(undoLevel); 852 } 853 854 860 private boolean isConnected() { 861 return fTextViewer != null; 862 } 863 864 867 public void beginCompoundChange() { 868 if (isConnected()) { 869 fFoldingIntoCompoundChange= true; 870 commit(); 871 } 872 } 873 874 875 878 public void endCompoundChange() { 879 if (isConnected()) { 880 fFoldingIntoCompoundChange= false; 881 commit(); 882 } 883 } 884 885 888 private void addListeners() { 889 StyledText text= fTextViewer.getTextWidget(); 890 if (text != null) { 891 fKeyAndMouseListener= new KeyAndMouseListener(); 892 text.addMouseListener(fKeyAndMouseListener); 893 text.addKeyListener(fKeyAndMouseListener); 894 fTextInputListener= new TextInputListener(); 895 fTextViewer.addTextInputListener(fTextInputListener); 896 fHistory.addOperationHistoryListener(fHistoryListener); 897 listenToTextChanges(true); 898 } 899 } 900 901 904 private void removeListeners() { 905 StyledText text= fTextViewer.getTextWidget(); 906 if (text != null) { 907 if (fKeyAndMouseListener != null) { 908 text.removeMouseListener(fKeyAndMouseListener); 909 text.removeKeyListener(fKeyAndMouseListener); 910 fKeyAndMouseListener= null; 911 } 912 if (fTextInputListener != null) { 913 fTextViewer.removeTextInputListener(fTextInputListener); 914 fTextInputListener= null; 915 } 916 listenToTextChanges(false); 917 fHistory.removeOperationHistoryListener(fHistoryListener); 918 } 919 } 920 921 928 private void addToCommandStack(TextCommand command){ 929 if (!fFoldingIntoCompoundChange || command instanceof CompoundTextCommand) { 930 fHistory.add(command); 931 fLastAddedCommand= command; 932 } 933 } 934 935 940 private void disposeCommandStack() { 941 fHistory.dispose(fUndoContext, true, true, true); 942 } 943 944 949 private void initializeCommandStack() { 950 if (fHistory != null && fUndoContext != null) 951 fHistory.dispose(fUndoContext, true, true, false); 952 953 } 954 955 960 private void listenToTextChanges(boolean listen) { 961 if (listen) { 962 if (fDocumentListener == null && fTextViewer.getDocument() != null) { 963 fDocumentListener= new DocumentListener(); 964 fTextViewer.getDocument().addDocumentListener(fDocumentListener); 965 } 966 } else if (!listen) { 967 if (fDocumentListener != null && fTextViewer.getDocument() != null) { 968 fTextViewer.getDocument().removeDocumentListener(fDocumentListener); 969 fDocumentListener= null; 970 } 971 } 972 } 973 974 977 private void commit() { 978 if (fLastAddedCommand != fCurrent) { 982 fCurrent.pretendCommit(); 983 if (fCurrent.isValid()) 984 addToCommandStack(fCurrent); 985 } 986 fCurrent.commit(); 987 } 988 989 994 private void resetProcessChangeSate() { 995 fInserting= false; 996 fOverwriting= false; 997 fPreviousDelete.reinitialize(); 998 } 999 1000 1007 private boolean isWhitespaceText(String text) { 1008 1009 if (text == null || text.length() == 0) 1010 return false; 1011 1012 String [] delimiters= fTextViewer.getDocument().getLegalLineDelimiters(); 1013 int index= TextUtilities.startsWith(delimiters, text); 1014 if (index > -1) { 1015 char c; 1016 int length= text.length(); 1017 for (int i= delimiters[index].length(); i < length; i++) { 1018 c= text.charAt(i); 1019 if (c != ' ' && c != '\t') 1020 return false; 1021 } 1022 return true; 1023 } 1024 1025 return false; 1026 } 1027 1028 private void processChange(int modelStart, int modelEnd, String insertedText, String replacedText, long beforeChangeModificationStamp, long afterChangeModificationStamp) { 1029 1030 if (insertedText == null) 1031 insertedText= ""; 1033 if (replacedText == null) 1034 replacedText= ""; 1036 int length= insertedText.length(); 1037 int diff= modelEnd - modelStart; 1038 1039 if (fCurrent.fUndoModificationStamp == IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP) 1040 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp; 1041 1042 if (diff < 0) { 1044 int tmp= modelEnd; 1045 modelEnd= modelStart; 1046 modelStart= tmp; 1047 } 1048 1049 if (modelStart == modelEnd) { 1050 if ((length == 1) || isWhitespaceText(insertedText)) { 1052 if (!fInserting || (modelStart != fCurrent.fStart + fTextBuffer.length())) { 1054 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp; 1055 if (fCurrent.attemptCommit()) 1056 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp; 1057 1058 fInserting= true; 1059 } 1060 if (fCurrent.fStart < 0) 1061 fCurrent.fStart= fCurrent.fEnd= modelStart; 1062 if (length > 0) 1063 fTextBuffer.append(insertedText); 1064 } else if (length >= 0) { 1065 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp; 1067 if (fCurrent.attemptCommit()) 1068 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp; 1069 1070 fCurrent.fStart= fCurrent.fEnd= modelStart; 1071 fTextBuffer.append(insertedText); 1072 fCurrent.fRedoModificationStamp= afterChangeModificationStamp; 1073 if (fCurrent.attemptCommit()) 1074 fCurrent.fUndoModificationStamp= afterChangeModificationStamp; 1075 1076 } 1077 } else { 1078 if (length == 0) { 1079 length= replacedText.length(); 1081 String [] delimiters= fTextViewer.getDocument().getLegalLineDelimiters(); 1082 1083 if ((length == 1) || TextUtilities.equals(delimiters, replacedText) > -1) { 1084 1085 1087 if (fPreviousDelete.fStart == modelStart && fPreviousDelete.fEnd == modelEnd) { 1088 1090 if (fCurrent.fStart == modelEnd && fCurrent.fEnd == modelStart) { 1092 fCurrent.fStart= modelStart; 1093 fCurrent.fEnd= modelEnd; 1094 } 1095 fPreservedTextBuffer.append(replacedText); 1097 ++fCurrent.fEnd; 1098 1099 } else if (fPreviousDelete.fStart == modelEnd) { 1100 1102 fPreservedTextBuffer.insert(0, replacedText); 1104 fCurrent.fStart= modelStart; 1105 1106 } else { 1107 1109 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp; 1110 if (fCurrent.attemptCommit()) 1111 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp; 1112 1113 fPreservedTextBuffer.append(replacedText); 1115 fCurrent.fStart= modelStart; 1116 fCurrent.fEnd= modelEnd; 1117 } 1118 1119 fPreviousDelete.set(modelStart, modelEnd); 1120 1121 } else if (length > 0) { 1122 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp; 1124 if (fCurrent.attemptCommit()) 1125 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp; 1126 1127 fCurrent.fStart= modelStart; 1128 fCurrent.fEnd= modelEnd; 1129 fPreservedTextBuffer.append(replacedText); 1130 } 1131 } else { 1132 1134 if (length == 1) { 1135 length= replacedText.length(); 1136 String [] delimiters= fTextViewer.getDocument().getLegalLineDelimiters(); 1137 1138 if ((length == 1) || TextUtilities.equals(delimiters, replacedText) > -1) { 1139 if (!fOverwriting || (modelStart != fCurrent.fStart + fTextBuffer.length())) { 1141 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp; 1142 if (fCurrent.attemptCommit()) 1143 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp; 1144 1145 fOverwriting= true; 1146 } 1147 1148 if (fCurrent.fStart < 0) 1149 fCurrent.fStart= modelStart; 1150 1151 fCurrent.fEnd= modelEnd; 1152 fTextBuffer.append(insertedText); 1153 fPreservedTextBuffer.append(replacedText); 1154 fCurrent.fRedoModificationStamp= afterChangeModificationStamp; 1155 return; 1156 } 1157 } 1158 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp; 1160 if (fCurrent.attemptCommit()) 1161 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp; 1162 1163 fCurrent.fStart= modelStart; 1164 fCurrent.fEnd= modelEnd; 1165 fTextBuffer.append(insertedText); 1166 fPreservedTextBuffer.append(replacedText); 1167 } 1168 } 1169 fCurrent.fRedoModificationStamp= afterChangeModificationStamp; 1171 } 1172 1173 1180 private void openErrorDialog(final String title, final Exception ex) { 1181 Shell shell= null; 1182 if (isConnected()) { 1183 StyledText st= fTextViewer.getTextWidget(); 1184 if (st != null && !st.isDisposed()) 1185 shell= st.getShell(); 1186 } 1187 if (Display.getCurrent() != null) 1188 MessageDialog.openError(shell, title, ex.getLocalizedMessage()); 1189 else { 1190 Display display; 1191 final Shell finalShell= shell; 1192 if (finalShell != null) 1193 display= finalShell.getDisplay(); 1194 else 1195 display= Display.getDefault(); 1196 display.syncExec(new Runnable () { 1197 public void run() { 1198 MessageDialog.openError(finalShell, title, ex.getLocalizedMessage()); 1199 } 1200 }); 1201 } 1202 } 1203 1204 1207 public void setMaximalUndoLevel(int undoLevel) { 1208 fUndoLevel= Math.max(0, undoLevel); 1209 if (isConnected()) { 1210 fHistory.setLimit(fUndoContext, fUndoLevel); 1211 } 1212 } 1213 1214 1217 public void connect(ITextViewer textViewer) { 1218 if (!isConnected() && textViewer != null) { 1219 fTextViewer= textViewer; 1220 if (fUndoContext == null) 1221 fUndoContext= new ObjectUndoContext(this); 1222 1223 fHistory.setLimit(fUndoContext, fUndoLevel); 1224 1225 initializeCommandStack(); 1226 1227 fCurrent= new TextCommand(fUndoContext); 1229 1230 fPreviousDelete= new TextCommand(fUndoContext); 1231 addListeners(); 1232 } 1233 } 1234 1235 1238 public void disconnect() { 1239 if (isConnected()) { 1240 1241 removeListeners(); 1242 1243 fCurrent= null; 1244 fTextViewer= null; 1245 disposeCommandStack(); 1246 fTextBuffer= null; 1247 fPreservedTextBuffer= null; 1248 fUndoContext= null; 1249 } 1250 } 1251 1252 1255 public void reset() { 1256 if (isConnected()) { 1257 initializeCommandStack(); 1258 fCurrent= new TextCommand(fUndoContext); 1259 fFoldingIntoCompoundChange= false; 1260 fInserting= false; 1261 fOverwriting= false; 1262 fTextBuffer.setLength(0); 1263 fPreservedTextBuffer.setLength(0); 1264 fPreservedUndoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; 1265 fPreservedRedoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP; 1266 } 1267 } 1268 1269 1272 public boolean redoable() { 1273 return fHistory.canRedo(fUndoContext); 1274 } 1275 1276 1279 public boolean undoable() { 1280 return fHistory.canUndo(fUndoContext); 1281 } 1282 1283 1286 public void redo() { 1287 if (isConnected() && redoable()) { 1288 try { 1289 fHistory.redo(fUndoContext, null, null); 1290 } catch (ExecutionException ex) { 1291 openErrorDialog(JFaceTextMessages.getString("DefaultUndoManager.error.redoFailed.title"), ex); } 1293 } 1294 } 1295 1296 1299 public void undo() { 1300 if (isConnected() && undoable()) { 1301 try { 1302 fHistory.undo(fUndoContext, null, null); 1303 } catch (ExecutionException ex) { 1304 openErrorDialog(JFaceTextMessages.getString("DefaultUndoManager.error.undoFailed.title"), ex); } 1306 } 1307 } 1308 1309 1316 protected void selectAndReveal(int offset, int length) { 1317 if (fTextViewer instanceof ITextViewerExtension5) { 1318 ITextViewerExtension5 extension= (ITextViewerExtension5) fTextViewer; 1319 extension.exposeModelRange(new Region(offset, length)); 1320 } else if (!fTextViewer.overlapsWithVisibleRegion(offset, length)) 1321 fTextViewer.resetVisibleRegion(); 1322 1323 fTextViewer.setSelectedRange(offset, length); 1324 fTextViewer.revealRange(offset, length); 1325 } 1326 1327 1331 public IUndoContext getUndoContext() { 1332 return fUndoContext; 1333 } 1334 1335} 1336 | Popular Tags |