package org.eclipse.text.undo;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.operations.AbstractOperation;
import org.eclipse.core.commands.operations.IContextReplacingOperation;
import org.eclipse.core.commands.operations.IOperationHistory;
import org.eclipse.core.commands.operations.IOperationHistoryListener;
import org.eclipse.core.commands.operations.IUndoContext;
import org.eclipse.core.commands.operations.IUndoableOperation;
import org.eclipse.core.commands.operations.ObjectUndoContext;
import org.eclipse.core.commands.operations.OperationHistoryEvent;
import org.eclipse.core.commands.operations.OperationHistoryFactory;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.DocumentRewriteSession;
import org.eclipse.jface.text.DocumentRewriteSessionType;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension4;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.TextUtilities;
public class DocumentUndoManager implements IDocumentUndoManager {
private static class UndoableTextChange extends AbstractOperation {
protected int fStart= -1;
protected int fEnd= -1;
protected String fText;
protected String fPreservedText;
protected long fUndoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP;
protected long fRedoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP;
protected DocumentUndoManager fDocumentUndoManager;
UndoableTextChange(DocumentUndoManager manager) {
super(UndoMessages.getString("DocumentUndoManager.operationLabel"));
this.fDocumentUndoManager= manager;
addContext(manager.getUndoContext());
}
protected void reinitialize() {
fStart= fEnd= -1;
fText= fPreservedText= null;
fUndoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP;
fRedoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP;
}
protected void set(int start, int end) {
fStart= start;
fEnd= end;
fText= null;
fPreservedText= null;
}
@Override
public void dispose() {
reinitialize();
}
protected void undoTextChange() {
try {
if (fDocumentUndoManager.fDocument instanceof IDocumentExtension4) {
((IDocumentExtension4) fDocumentUndoManager.fDocument).replace(fStart, fText
.length(), fPreservedText, fUndoModificationStamp);
} else {
fDocumentUndoManager.fDocument.replace(fStart, fText.length(),
fPreservedText);
}
} catch (BadLocationException x) {
}
}
@Override
public boolean canUndo() {
if (isValid()) {
if (fDocumentUndoManager.fDocument instanceof IDocumentExtension4) {
long docStamp= ((IDocumentExtension4) fDocumentUndoManager.fDocument)
.getModificationStamp();
boolean canUndo= docStamp == IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP
|| docStamp >= getRedoModificationStamp();
if (!canUndo
&& this == fDocumentUndoManager.fHistory
.getUndoOperation(fDocumentUndoManager.fUndoContext)
&& this != fDocumentUndoManager.fCurrent
&& !fDocumentUndoManager.fCurrent.isValid()
&& fDocumentUndoManager.fCurrent.fUndoModificationStamp !=
IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP) {
canUndo= fDocumentUndoManager.fCurrent.fRedoModificationStamp == docStamp;
}
if (!canUndo
&& this == fDocumentUndoManager.fHistory
.getUndoOperation(fDocumentUndoManager.fUndoContext)
&&
this instanceof UndoableCompoundTextChange
&& this == fDocumentUndoManager.fCurrent
&&
this.fStart == -1
&&
fDocumentUndoManager.fCurrent.fRedoModificationStamp != IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP) {
canUndo= fDocumentUndoManager.fCurrent.fRedoModificationStamp == docStamp;
}
return canUndo;
}
return true;
}
return false;
}
@Override
public boolean canRedo() {
if (isValid()) {
if (fDocumentUndoManager.fDocument instanceof IDocumentExtension4) {
long docStamp= ((IDocumentExtension4) fDocumentUndoManager.fDocument)
.getModificationStamp();
return docStamp == IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP
|| docStamp == getUndoModificationStamp();
}
return true;
}
return false;
}
@Override
public boolean canExecute() {
return fDocumentUndoManager.isConnected();
}
@Override
public IStatus execute(IProgressMonitor monitor, IAdaptable uiInfo) {
return Status.OK_STATUS;
}
@Override
public IStatus undo(IProgressMonitor monitor, IAdaptable uiInfo) {
if (isValid()) {
fDocumentUndoManager.fireDocumentUndo(fStart, fPreservedText, fText, uiInfo, DocumentUndoEvent.ABOUT_TO_UNDO, false);
undoTextChange();
fDocumentUndoManager.resetProcessChangeState();
fDocumentUndoManager.fireDocumentUndo(fStart, fPreservedText, fText, uiInfo, DocumentUndoEvent.UNDONE, false);
return Status.OK_STATUS;
}
return IOperationHistory.OPERATION_INVALID_STATUS;
}
protected void redoTextChange() {
try {
if (fDocumentUndoManager.fDocument instanceof IDocumentExtension4) {
((IDocumentExtension4) fDocumentUndoManager.fDocument).replace(fStart, fEnd - fStart, fText, fRedoModificationStamp);
} else {
fDocumentUndoManager.fDocument.replace(fStart, fEnd - fStart, fText);
}
} catch (BadLocationException x) {
}
}
@Override
public IStatus redo(IProgressMonitor monitor, IAdaptable uiInfo) {
if (isValid()) {
fDocumentUndoManager.fireDocumentUndo(fStart, fText, fPreservedText, uiInfo, DocumentUndoEvent.ABOUT_TO_REDO, false);
redoTextChange();
fDocumentUndoManager.resetProcessChangeState();
fDocumentUndoManager.fireDocumentUndo(fStart, fText, fPreservedText, uiInfo, DocumentUndoEvent.REDONE, false);
return Status.OK_STATUS;
}
return IOperationHistory.OPERATION_INVALID_STATUS;
}
protected void updateTextChange() {
fText= fDocumentUndoManager.fTextBuffer.toString();
fDocumentUndoManager.fTextBuffer.setLength(0);
fPreservedText= fDocumentUndoManager.fPreservedTextBuffer.toString();
fDocumentUndoManager.fPreservedTextBuffer.setLength(0);
}
protected UndoableTextChange createCurrent() {
if (fDocumentUndoManager.fFoldingIntoCompoundChange) {
return new UndoableCompoundTextChange(fDocumentUndoManager);
}
return new UndoableTextChange(fDocumentUndoManager);
}
protected void commit() {
if (fStart < 0) {
if (fDocumentUndoManager.fFoldingIntoCompoundChange) {
fDocumentUndoManager.fCurrent= createCurrent();
} else {
reinitialize();
}
} else {
updateTextChange();
fDocumentUndoManager.fCurrent= createCurrent();
}
fDocumentUndoManager.resetProcessChangeState();
}
protected void pretendCommit() {
if (fStart > -1) {
fText= fDocumentUndoManager.fTextBuffer.toString();
fPreservedText= fDocumentUndoManager.fPreservedTextBuffer.toString();
}
}
protected boolean attemptCommit() {
pretendCommit();
if (isValid()) {
fDocumentUndoManager.commit();
return true;
}
return false;
}
protected boolean isValid() {
return fStart > -1 && fEnd > -1 && fText != null;
}
@Override
public String toString() {
String delimiter= ", ";
StringBuilder text= new StringBuilder(super.toString());
text.append("\n");
text.append(this.getClass().getName());
text.append(" undo modification stamp: ");
text.append(fUndoModificationStamp);
text.append(" redo modification stamp: ");
text.append(fRedoModificationStamp);
text.append(" start: ");
text.append(fStart);
text.append(delimiter);
text.append("end: ");
text.append(fEnd);
text.append(delimiter);
text.append("text: '");
text.append(fText);
text.append('\'');
text.append(delimiter);
text.append("preservedText: '");
text.append(fPreservedText);
text.append('\'');
return text.toString();
}
protected long getUndoModificationStamp() {
return fUndoModificationStamp;
}
protected long getRedoModificationStamp() {
return fRedoModificationStamp;
}
}
private static class UndoableCompoundTextChange extends UndoableTextChange {
private List<UndoableTextChange> fChanges= new ArrayList<>();
UndoableCompoundTextChange(DocumentUndoManager manager) {
super(manager);
}
protected void add(UndoableTextChange change) {
fChanges.add(change);
}
@Override
public IStatus undo(IProgressMonitor monitor, IAdaptable uiInfo) {
int size= fChanges.size();
if (size > 0) {
UndoableTextChange c;
c= fChanges.get(0);
fDocumentUndoManager.fireDocumentUndo(c.fStart, c.fPreservedText, c.fText, uiInfo, DocumentUndoEvent.ABOUT_TO_UNDO, size > 1);
DocumentRewriteSession rewriteSession= null;
if (size > 25 && fDocumentUndoManager.fDocument instanceof IDocumentExtension4
&& ((IDocumentExtension4) fDocumentUndoManager.fDocument).getActiveRewriteSession() == null) {
DocumentRewriteSessionType sessionType= size > 1000 ? DocumentRewriteSessionType.UNRESTRICTED : DocumentRewriteSessionType.UNRESTRICTED_SMALL;
rewriteSession= ((IDocumentExtension4) fDocumentUndoManager.fDocument).startRewriteSession(sessionType);
}
for (int i= size - 1; i >= 0; --i) {
c= fChanges.get(i);
c.undoTextChange();
}
if (rewriteSession != null) {
((IDocumentExtension4) fDocumentUndoManager.fDocument).stopRewriteSession(rewriteSession);
}
fDocumentUndoManager.resetProcessChangeState();
fDocumentUndoManager.fireDocumentUndo(c.fStart, c.fPreservedText, c.fText, uiInfo,
DocumentUndoEvent.UNDONE, size > 1);
}
return Status.OK_STATUS;
}
@Override
public IStatus redo(IProgressMonitor monitor, IAdaptable uiInfo) {
int size= fChanges.size();
if (size > 0) {
UndoableTextChange c;
c= fChanges.get(size - 1);
fDocumentUndoManager.fireDocumentUndo(c.fStart, c.fText, c.fPreservedText, uiInfo, DocumentUndoEvent.ABOUT_TO_REDO, size > 1);
DocumentRewriteSession rewriteSession= null;
if (size > 25 && fDocumentUndoManager.fDocument instanceof IDocumentExtension4
&& ((IDocumentExtension4) fDocumentUndoManager.fDocument).getActiveRewriteSession() == null) {
DocumentRewriteSessionType sessionType= size > 1000 ? DocumentRewriteSessionType.UNRESTRICTED : DocumentRewriteSessionType.UNRESTRICTED_SMALL;
rewriteSession= ((IDocumentExtension4) fDocumentUndoManager.fDocument).startRewriteSession(sessionType);
}
for (int i= 0; i < size; ++i) {
c= fChanges.get(i);
c.redoTextChange();
}
if (rewriteSession != null) {
((IDocumentExtension4) fDocumentUndoManager.fDocument).stopRewriteSession(rewriteSession);
}
fDocumentUndoManager.resetProcessChangeState();
fDocumentUndoManager.fireDocumentUndo(c.fStart, c.fText, c.fPreservedText, uiInfo, DocumentUndoEvent.REDONE, size > 1);
}
return Status.OK_STATUS;
}
@Override
protected void updateTextChange() {
super.updateTextChange();
UndoableTextChange c= new UndoableTextChange(fDocumentUndoManager);
c.fStart= fStart;
c.fEnd= fEnd;
c.fText= fText;
c.fPreservedText= fPreservedText;
c.fUndoModificationStamp= fUndoModificationStamp;
c.fRedoModificationStamp= fRedoModificationStamp;
add(c);
reinitialize();
}
@Override
protected UndoableTextChange createCurrent() {
if (!fDocumentUndoManager.fFoldingIntoCompoundChange) {
return new UndoableTextChange(fDocumentUndoManager);
}
reinitialize();
return this;
}
@Override
protected void commit() {
if (fStart > -1) {
updateTextChange();
}
fDocumentUndoManager.fCurrent= createCurrent();
fDocumentUndoManager.resetProcessChangeState();
}
@Override
protected boolean isValid() {
return fStart > -1 || !fChanges.isEmpty();
}
@Override
protected long getUndoModificationStamp() {
if (fStart > -1) {
return super.getUndoModificationStamp();
} else if (!fChanges.isEmpty()) {
return fChanges.get(0)
.getUndoModificationStamp();
}
return fUndoModificationStamp;
}
@Override
protected long getRedoModificationStamp() {
if (fStart > -1) {
return super.getRedoModificationStamp();
} else if (!fChanges.isEmpty()) {
return fChanges.get(fChanges.size() - 1)
.getRedoModificationStamp();
}
return fRedoModificationStamp;
}
}
private class DocumentListener implements IDocumentListener {
private String fReplacedText;
@Override
public void documentAboutToBeChanged(DocumentEvent event) {
try {
fReplacedText= event.getDocument().get(event.getOffset(),
event.getLength());
fPreservedUndoModificationStamp= event.getModificationStamp();
} catch (BadLocationException x) {
fReplacedText= null;
}
}
@Override
public void documentChanged(DocumentEvent event) {
fPreservedRedoModificationStamp= event.getModificationStamp();
IUndoableOperation op= fHistory.getUndoOperation(fUndoContext);
boolean wasValid= false;
if (op != null) {
wasValid= op.canUndo();
}
processChange(event.getOffset(), event.getOffset()
+ event.getLength(), event.getText(), fReplacedText,
fPreservedUndoModificationStamp,
fPreservedRedoModificationStamp);
fCurrent.pretendCommit();
if (op == fCurrent) {
if (wasValid != fCurrent.isValid()) {
fHistory.operationChanged(op);
}
} else {
if (fCurrent != fLastAddedTextEdit && fCurrent.isValid()) {
addToOperationHistory(fCurrent);
}
}
}
}
private class HistoryListener implements IOperationHistoryListener {
private IUndoableOperation fOperation;
@Override
public void historyNotification(final OperationHistoryEvent event) {
final int type= event.getEventType();
switch (type) {
case OperationHistoryEvent.ABOUT_TO_UNDO:
case OperationHistoryEvent.ABOUT_TO_REDO:
if (event.getOperation().hasContext(fUndoContext)) {
if (event.getOperation() instanceof UndoableTextChange) {
listenToTextChanges(false);
if (type == OperationHistoryEvent.ABOUT_TO_UNDO) {
if (fFoldingIntoCompoundChange) {
endCompoundChange();
}
}
} else {
commit();
fLastAddedTextEdit= null;
}
fOperation= event.getOperation();
}
break;
case OperationHistoryEvent.UNDONE:
case OperationHistoryEvent.REDONE:
case OperationHistoryEvent.OPERATION_NOT_OK:
if (event.getOperation() == fOperation) {
listenToTextChanges(true);
fOperation= null;
}
break;
}
}
}
private ObjectUndoContext fUndoContext;
private IDocument fDocument;
private UndoableTextChange fCurrent;
private DocumentListener fDocumentListener;
private boolean fFoldingIntoCompoundChange= false;
private IOperationHistory fHistory;
private IOperationHistoryListener fHistoryListener;
private UndoableTextChange fLastAddedTextEdit= null;
private long fPreservedRedoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP;
private StringBuilder fPreservedTextBuffer;
private long fPreservedUndoModificationStamp= IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP;
private UndoableTextChange fPreviousDelete;
private StringBuilder fTextBuffer;
private boolean fInserting= false;
private boolean fOverwriting= false;
private ListenerList<IDocumentUndoListener> fDocumentUndoListeners;
private List<Object> fConnected;
public DocumentUndoManager(IDocument document) {
super();
Assert.isNotNull(document);
fDocument= document;
fHistory= OperationHistoryFactory.getOperationHistory();
fUndoContext= new ObjectUndoContext(fDocument);
fConnected= new ArrayList<>();
fDocumentUndoListeners= new ListenerList<>(ListenerList.IDENTITY);
}
@Override
public void addDocumentUndoListener(IDocumentUndoListener listener) {
fDocumentUndoListeners.add(listener);
}
@Override
public void removeDocumentUndoListener(IDocumentUndoListener listener) {
fDocumentUndoListeners.remove(listener);
}
@Override
public IUndoContext getUndoContext() {
return fUndoContext;
}
@Override
public void commit() {
if (fLastAddedTextEdit != fCurrent) {
fCurrent.pretendCommit();
if (fCurrent.isValid()) {
addToOperationHistory(fCurrent);
}
}
fCurrent.commit();
}
@Override
public void reset() {
if (isConnected()) {
shutdown();
initialize();
}
}
@Override
public boolean redoable() {
return OperationHistoryFactory.getOperationHistory().canRedo(fUndoContext);
}
@Override
public boolean undoable() {
return OperationHistoryFactory.getOperationHistory().canUndo(fUndoContext);
}
@Override
public void redo() throws ExecutionException {
if (isConnected() && redoable()) {
OperationHistoryFactory.getOperationHistory().redo(getUndoContext(), null, null);
}
}
@Override
public void undo() throws ExecutionException {
if (undoable()) {
OperationHistoryFactory.getOperationHistory().undo(fUndoContext, null, null);
}
}
@Override
public void connect(Object client) {
if (!isConnected()) {
initialize();
}
if (!fConnected.contains(client)) {
fConnected.add(client);
}
}
@Override
public void disconnect(Object client) {
fConnected.remove(client);
if (!isConnected()) {
shutdown();
}
}
@Override
public void beginCompoundChange() {
if (isConnected()) {
fFoldingIntoCompoundChange= true;
commit();
}
}
@Override
public void endCompoundChange() {
if (isConnected()) {
fFoldingIntoCompoundChange= false;
commit();
}
}
@Override
public void setMaximalUndoLevel(int undoLimit) {
fHistory.setLimit(fUndoContext, undoLimit);
}
void fireDocumentUndo(int offset, String text, String preservedText, Object source, int eventType, boolean isCompound) {
eventType= isCompound ? eventType | DocumentUndoEvent.COMPOUND : eventType;
DocumentUndoEvent event= new DocumentUndoEvent(fDocument, offset, text, preservedText, eventType, source);
for (IDocumentUndoListener listener : fDocumentUndoListeners) {
listener.documentUndoNotification(event);
}
}
private void addListeners() {
fHistoryListener= new HistoryListener();
fHistory.addOperationHistoryListener(fHistoryListener);
listenToTextChanges(true);
}
private void removeListeners() {
listenToTextChanges(false);
fHistory.removeOperationHistoryListener(fHistoryListener);
fHistoryListener= null;
}
private void addToOperationHistory(UndoableTextChange edit) {
if (!fFoldingIntoCompoundChange
|| edit instanceof UndoableCompoundTextChange) {
fHistory.add(edit);
fLastAddedTextEdit= edit;
}
}
private void disposeUndoHistory() {
fHistory.dispose(fUndoContext, true, true, true);
}
private void initializeUndoHistory() {
if (fHistory != null && fUndoContext != null) {
fHistory.dispose(fUndoContext, true, true, false);
}
}
private boolean isWhitespaceText(String text) {
if (text == null || text.isEmpty()) {
return false;
}
String[] delimiters= fDocument.getLegalLineDelimiters();
int index= TextUtilities.startsWith(delimiters, text);
if (index > -1) {
char c;
int length= text.length();
for (int i= delimiters[index].length(); i < length; i++) {
c= text.charAt(i);
if (c != ' ' && c != '\t') {
return false;
}
}
return true;
}
return false;
}
private void listenToTextChanges(boolean listen) {
if (listen) {
if (fDocumentListener == null && fDocument != null) {
fDocumentListener= new DocumentListener();
fDocument.addDocumentListener(fDocumentListener);
}
} else if (!listen) {
if (fDocumentListener != null && fDocument != null) {
fDocument.removeDocumentListener(fDocumentListener);
fDocumentListener= null;
}
}
}
private void processChange(int modelStart, int modelEnd,
String insertedText, String replacedText,
final long beforeChangeModificationStamp,
final long afterChangeModificationStamp) {
if (insertedText == null)
{
insertedText= "";
}
if (replacedText == null)
{
replacedText= "";
}
int length= insertedText.length();
int diff= modelEnd - modelStart;
if (fCurrent.fUndoModificationStamp == IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP) {
fCurrent.fUndoModificationStamp= beforeChangeModificationStamp;
}
if (diff < 0) {
int tmp= modelEnd;
modelEnd= modelStart;
modelStart= tmp;
}
if (modelStart == modelEnd) {
if ((length == 1) || isWhitespaceText(insertedText)) {
if (!fInserting
|| (modelStart != fCurrent.fStart
+ fTextBuffer.length())) {
fCurrent.fRedoModificationStamp= beforeChangeModificationStamp;
if (fCurrent.attemptCommit()) {
fCurrent.fUndoModificationStamp= beforeChangeModificationStamp;
}
fInserting= true;
}
if (fCurrent.fStart < 0) {
fCurrent.fStart= fCurrent.fEnd= modelStart;
}
if (length > 0) {
fTextBuffer.append(insertedText);
}
} else if (length > 0) {
fCurrent.fRedoModificationStamp= beforeChangeModificationStamp;
if (fCurrent.attemptCommit()) {
fCurrent.fUndoModificationStamp= beforeChangeModificationStamp;
}
fCurrent.fStart= fCurrent.fEnd= modelStart;
fTextBuffer.append(insertedText);
fCurrent.fRedoModificationStamp= afterChangeModificationStamp;
if (fCurrent.attemptCommit()) {
fCurrent.fUndoModificationStamp= afterChangeModificationStamp;
}
}
} else {
if (length == 0) {
length= replacedText.length();
String[] delimiters= fDocument.getLegalLineDelimiters();
if ((length == 1)
|| TextUtilities.equals(delimiters, replacedText) > -1) {
if (fPreviousDelete.fStart == modelStart
&& fPreviousDelete.fEnd == modelEnd) {
if (fCurrent.fStart == modelEnd
&& fCurrent.fEnd == modelStart) {
fCurrent.fStart= modelStart;
fCurrent.fEnd= modelEnd;
}
fPreservedTextBuffer.append(replacedText);
++fCurrent.fEnd;
} else if (fPreviousDelete.fStart == modelEnd) {
fPreservedTextBuffer.insert(0, replacedText);
fCurrent.fStart= modelStart;
} else {
fCurrent.fRedoModificationStamp= beforeChangeModificationStamp;
if (fCurrent.attemptCommit()) {
fCurrent.fUndoModificationStamp= beforeChangeModificationStamp;
}
fPreservedTextBuffer.append(replacedText);
fCurrent.fStart= modelStart;
fCurrent.fEnd= modelEnd;
}
fPreviousDelete.set(modelStart, modelEnd);
} else if (length > 0) {
fCurrent.fRedoModificationStamp= beforeChangeModificationStamp;
if (fCurrent.attemptCommit()) {
fCurrent.fUndoModificationStamp= beforeChangeModificationStamp;
}
fCurrent.fStart= modelStart;
fCurrent.fEnd= modelEnd;
fPreservedTextBuffer.append(replacedText);
}
} else {
if (length == 1) {
length= replacedText.length();
String[] delimiters= fDocument.getLegalLineDelimiters();
if ((length == 1)
|| TextUtilities.equals(delimiters, replacedText) > -1) {
if (!fOverwriting
|| (modelStart != fCurrent.fStart
+ fTextBuffer.length())) {
fCurrent.fRedoModificationStamp= beforeChangeModificationStamp;
if (fCurrent.attemptCommit()) {
fCurrent.fUndoModificationStamp= beforeChangeModificationStamp;
}
fOverwriting= true;
}
if (fCurrent.fStart < 0) {
fCurrent.fStart= modelStart;
}
fCurrent.fEnd= modelEnd;
fTextBuffer.append(insertedText);
fPreservedTextBuffer.append(replacedText);
fCurrent.fRedoModificationStamp= afterChangeModificationStamp;
return;
}
}
fCurrent.fRedoModificationStamp= beforeChangeModificationStamp;
if (fCurrent.attemptCommit()) {
fCurrent.fUndoModificationStamp= beforeChangeModificationStamp;
}
fCurrent.fStart= modelStart;
fCurrent.fEnd= modelEnd;
fTextBuffer.append(insertedText);
fPreservedTextBuffer.append(replacedText);
}
}
fCurrent.fRedoModificationStamp= afterChangeModificationStamp;
}
private void initialize() {
initializeUndoHistory();
fCurrent= new UndoableTextChange(this);
fPreviousDelete= new UndoableTextChange(this);
fTextBuffer= new StringBuilder();
fPreservedTextBuffer= new StringBuilder();
addListeners();
}
private void resetProcessChangeState() {
fInserting= false;
fOverwriting= false;
fPreviousDelete.reinitialize();
}
private void shutdown() {
removeListeners();
fCurrent= null;
fPreviousDelete= null;
fTextBuffer= null;
fPreservedTextBuffer= null;
disposeUndoHistory();
}
boolean isConnected() {
if (fConnected == null) {
return false;
}
return !fConnected.isEmpty();
}
@Override
public void transferUndoHistory(IDocumentUndoManager manager) {
IUndoContext oldUndoContext= manager.getUndoContext();
IUndoableOperation [] operations= OperationHistoryFactory.getOperationHistory().getUndoHistory(oldUndoContext);
for (IUndoableOperation operation : operations) {
IUndoableOperation op= operation;
if (op instanceof IContextReplacingOperation) {
((IContextReplacingOperation)op).replaceContext(oldUndoContext, getUndoContext());
} else {
op.addContext(getUndoContext());
op.removeContext(oldUndoContext);
}
if (op instanceof UndoableTextChange) {
((UndoableTextChange)op).fDocumentUndoManager= this;
}
}
IUndoableOperation op= OperationHistoryFactory.getOperationHistory().getUndoOperation(getUndoContext());
if (op != null && !(op instanceof UndoableTextChange)) {
return;
}
UndoableTextChange cmd= new UndoableTextChange(this);
cmd.fStart= cmd.fEnd= 0;
cmd.fText= cmd.fPreservedText= "";
if (fDocument instanceof IDocumentExtension4) {
cmd.fRedoModificationStamp= ((IDocumentExtension4)fDocument).getModificationStamp();
if (op != null) {
cmd.fUndoModificationStamp= ((UndoableTextChange)op).fRedoModificationStamp;
}
}
addToOperationHistory(cmd);
}
}