blob: 67bfd8038cb67539d8f587dd163b43beb08a3582 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ltk.internal.core.refactoring;
import java.util.LinkedList;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.text.edits.UndoEdit;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.core.resources.IFile;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.ContentStamp;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextFileChange;
/**
* A change to perform the reverse change of a {@link org.eclipse.ltk.core.refactoring.CompositeTextFileChange}.
* <p>
* This class is not intended to be instantiated by clients. It is usually
* created by a <code>CompositeTextFileChange</code> object.
* </p>
* <p>
* The class should be subclassed by clients also subclassing <code>
* CompositeTextFileChange</code>
* to provide a proper undo change object.
* </p>
*
* @since 3.2
*/
public class CompositeUndoChange extends Change {
private ContentStamp fContentStampToRestore;
private boolean fDirty;
private IFile fFile;
private String fName;
private int fSaveMode;
private UndoEdit[] fUndos;
private BufferValidationState fValidationState;
/**
* Create a new composite undo change object.
*
* @param name
* the human readable name of the change
* @param file
* the file the change is working on
* @param stamp
* the content stamp to restore when the undo is executed
* @param undos
* the edit representing the undo modifications
* @param saveMode
* the save mode as specified by {@link TextFileChange}
*
* @see TextFileChange#KEEP_SAVE_STATE
* @see TextFileChange#FORCE_SAVE
* @see TextFileChange#LEAVE_DIRTY
*/
public CompositeUndoChange(String name, IFile file, UndoEdit[] undos, ContentStamp stamp, int saveMode) {
Assert.isNotNull(name);
Assert.isNotNull(file);
Assert.isNotNull(undos);
fName= name;
fFile= file;
fUndos= undos;
fContentStampToRestore= stamp;
fSaveMode= saveMode;
}
/**
* Hook to create an undo change for the given undo edit. This hook gets
* called while performing the change to construct the corresponding undo
* change object.
* <p>
* Subclasses may override it to create a different undo change.
* </p>
*
* @param edits
* the {@link UndoEdit undo edit} to create a undo change for
* @param stampToRestore
* the content stamp to restore when the undo edit is executed.
*
* @return the undo change
*
* @throws CoreException
* if an undo change can't be created
*/
protected Change createUndoChange(UndoEdit[] edits, ContentStamp stampToRestore) throws CoreException {
return new CompositeUndoChange(getName(), fFile, edits, stampToRestore, fSaveMode);
}
/**
* {@inheritDoc}
*/
public void dispose() {
fValidationState.dispose();
}
/**
* {@inheritDoc}
*/
public final Object[] getAffectedObjects() {
Object modifiedElement= getModifiedElement();
if (modifiedElement == null)
return null;
return new Object[] { modifiedElement};
}
/**
* {@inheritDoc}
*/
public final Object getModifiedElement() {
return fFile;
}
/**
* {@inheritDoc}
*/
public final String getName() {
return fName;
}
/**
* Returns the change's save mode.
*
* @return the change's save mode
*
* @see TextFileChange#KEEP_SAVE_STATE
* @see TextFileChange#FORCE_SAVE
* @see TextFileChange#LEAVE_DIRTY
*/
public final int getSaveMode() {
return fSaveMode;
}
/**
* {@inheritDoc}
*/
public void initializeValidationData(IProgressMonitor pm) {
if (pm == null)
pm= new NullProgressMonitor();
pm.beginTask("", 1); //$NON-NLS-1$
fValidationState= BufferValidationState.create(fFile);
pm.worked(1);
}
/**
* {@inheritDoc}
*/
public RefactoringStatus isValid(IProgressMonitor pm) throws CoreException {
if (pm == null)
pm= new NullProgressMonitor();
pm.beginTask("", 1); //$NON-NLS-1$
ITextFileBuffer buffer= FileBuffers.getTextFileBufferManager().getTextFileBuffer(fFile.getFullPath());
fDirty= buffer != null && buffer.isDirty();
RefactoringStatus result= fValidationState.isValid(needsSaving());
pm.worked(1);
return result;
}
public final boolean needsSaving() {
return (fSaveMode & TextFileChange.FORCE_SAVE) != 0 || (!fDirty && (fSaveMode & TextFileChange.KEEP_SAVE_STATE) != 0);
}
/**
* {@inheritDoc}
*/
public Change perform(IProgressMonitor pm) throws CoreException {
if (pm == null)
pm= new NullProgressMonitor();
ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
pm.beginTask("", 2); //$NON-NLS-1$
ITextFileBuffer buffer= null;
try {
manager.connect(fFile.getFullPath(), new SubProgressMonitor(pm, 1));
buffer= manager.getTextFileBuffer(fFile.getFullPath());
IDocument document= buffer.getDocument();
ContentStamp currentStamp= ContentStamps.get(fFile, document);
// perform the changes
LinkedList list= new LinkedList();
for (int index= 0; index < fUndos.length; index++) {
UndoEdit edit= fUndos[index];
UndoEdit redo= edit.apply(document, TextEdit.CREATE_UNDO);
list.addFirst(redo);
}
// try to restore the document content stamp
boolean success= ContentStamps.set(document, fContentStampToRestore);
if (needsSaving()) {
buffer.commit(pm, false);
if (!success) {
// We weren't able to restore document stamp.
// Since we save restore the file stamp instead
ContentStamps.set(fFile, fContentStampToRestore);
}
}
return createUndoChange((UndoEdit[]) list.toArray(new UndoEdit[list.size()]), currentStamp);
} catch (BadLocationException e) {
throw Changes.asCoreException(e);
} finally {
if (buffer != null)
manager.disconnect(fFile.getFullPath(), new SubProgressMonitor(pm, 1));
}
}
}