Copyright (c) 2000, 2010 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation
/******************************************************************************* * Copyright (c) 2000, 2010 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/
package org.eclipse.ltk.core.refactoring; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.resources.IFile; import org.eclipse.core.filebuffers.FileBuffers; import org.eclipse.core.filebuffers.ITextFileBuffer; import org.eclipse.core.filebuffers.ITextFileBufferManager; import org.eclipse.core.filebuffers.LocationKind; import org.eclipse.text.edits.MalformedTreeException; import org.eclipse.text.edits.TextEdit; import org.eclipse.text.edits.UndoEdit; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.link.LinkedModeModel; import org.eclipse.ltk.internal.core.refactoring.BufferValidationState; import org.eclipse.ltk.internal.core.refactoring.Changes; import org.eclipse.ltk.internal.core.refactoring.ContentStamps; import org.eclipse.ltk.internal.core.refactoring.Lock; import org.eclipse.ltk.internal.core.refactoring.RefactoringCorePlugin;
A change to perform the reverse change of a TextFileChange.

This class is not intended to be instantiated by clients. It is usually created by a TextFileChange object.

The class should be subclassed by clients also subclassing TextFileChange to provide a proper undo change object.

Since:3.0
/** * A change to perform the reverse change of a {@link TextFileChange}. * <p> * This class is not intended to be instantiated by clients. It is * usually created by a <code>TextFileChange</code> object. * </p> * <p> * The class should be subclassed by clients also subclassing <code> * TextFileChange</code> to provide a proper undo change object. * </p> * @since 3.0 */
public class UndoTextFileChange extends Change { private String fName; private UndoEdit fUndo; private IFile fFile; private ContentStamp fContentStampToRestore; private int fSaveMode; private boolean fDirty; private BufferValidationState fValidationState;
Create a new undo text file change object.
Params:
  • name – the human readable name of the change
  • file – the file the change is working on
  • stamp – the content stamp to restore when the undo is executed
  • undo – the edit representing the undo modifications
  • saveMode – the save mode as specified by TextFileChange
See Also:
/** * Create a new undo text file 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 undo 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 */
protected UndoTextFileChange(String name, IFile file, UndoEdit undo, ContentStamp stamp, int saveMode) { Assert.isNotNull(name); Assert.isNotNull(file); Assert.isNotNull(undo); fName= name; fFile= file; fUndo= undo; fContentStampToRestore= stamp; fSaveMode= saveMode; }
Returns the change's save mode.
See Also:
Returns:the change's save mode
/** * 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 int getSaveMode() { return fSaveMode; } @Override public String getName() { return fName; }
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.

Subclasses may override it to create a different undo change.

Params:
  • edit – the undo edit to create a undo change for
  • stampToRestore – the content stamp to restore when the undo edit is executed.
Throws:
Returns:the undo change
/** * 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 edit 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 edit, ContentStamp stampToRestore) throws CoreException { return new UndoTextFileChange(getName(), fFile, edit, stampToRestore, fSaveMode); } @Override public Object getModifiedElement() { return fFile; } @Override public Object[] getAffectedObjects() { Object modifiedElement= getModifiedElement(); if (modifiedElement == null) return null; return new Object[] { modifiedElement }; } @Override public void initializeValidationData(IProgressMonitor pm) { if (pm == null) pm= new NullProgressMonitor(); pm.beginTask("", 1); //$NON-NLS-1$ try { fValidationState= BufferValidationState.create(fFile); } finally { pm.done(); } } @Override public RefactoringStatus isValid(IProgressMonitor pm) throws CoreException { if (pm == null) pm= new NullProgressMonitor(); pm.beginTask("", 1); //$NON-NLS-1$ try { if (fValidationState == null) throw new CoreException(new Status(IStatus.ERROR, RefactoringCorePlugin.getPluginId(), "UndoTextFileChange has not been initialialized")); //$NON-NLS-1$ ITextFileBuffer buffer= FileBuffers.getTextFileBufferManager().getTextFileBuffer(fFile.getFullPath(), LocationKind.IFILE); fDirty= buffer != null && buffer.isDirty(); return fValidationState.isValid(needsSaving(), true); } finally { pm.done(); } } @Override 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(), LocationKind.IFILE, new SubProgressMonitor(pm, 1)); buffer= manager.getTextFileBuffer(fFile.getFullPath(), LocationKind.IFILE); IDocument document= buffer.getDocument(); ContentStamp currentStamp= ContentStamps.get(fFile, document); boolean[] setContentStampSuccess= { false }; UndoEdit redo= performEdits(buffer, document, setContentStampSuccess); if (needsSaving()) { buffer.commit(pm, false); if (!setContentStampSuccess[0]) { // We weren't able to restore document stamp. // Since we save restore the file stamp instead ContentStamps.set(fFile, fContentStampToRestore); } } return createUndoChange(redo, currentStamp); } catch (BadLocationException e) { if (fValidationState == null || !fValidationState.wasDerived()) throw Changes.asCoreException(e); else return new NullChange(); } catch (MalformedTreeException e) { if (fValidationState == null || !fValidationState.wasDerived()) throw Changes.asCoreException(e); else return new NullChange(); } catch (CoreException e) { if (fValidationState == null || !fValidationState.wasDerived()) throw e; else return new NullChange(); } finally { if (buffer != null) manager.disconnect(fFile.getFullPath(), LocationKind.IFILE, new SubProgressMonitor(pm, 1)); } } private UndoEdit performEdits(ITextFileBuffer buffer, final IDocument document, final boolean[] setContentStampSuccess) throws MalformedTreeException, BadLocationException, CoreException { if (! buffer.isSynchronizationContextRequested()) { return doPerformEdits(document, setContentStampSuccess); } ITextFileBufferManager fileBufferManager= FileBuffers.getTextFileBufferManager(); /** The lock for waiting for computation in the UI thread to complete. */ final Lock completionLock= new Lock(); final UndoEdit[] result= new UndoEdit[1]; final BadLocationException[] badLocationException= new BadLocationException[1]; final MalformedTreeException[] malformedTreeException= new MalformedTreeException[1]; final CoreException[] coreException= new CoreException[1]; Runnable runnable= new Runnable() { @Override public void run() { synchronized (completionLock) { try { result[0]= doPerformEdits(document, setContentStampSuccess); } catch (BadLocationException e) { badLocationException[0]= e; } catch (MalformedTreeException e) { malformedTreeException[0]= e; } catch (CoreException e) { coreException[0]= e; } finally { completionLock.fDone= true; completionLock.notifyAll(); } } } }; synchronized (completionLock) { fileBufferManager.execute(runnable); while (! completionLock.fDone) { try { completionLock.wait(500); } catch (InterruptedException x) { } } } if (badLocationException[0] != null) { throw badLocationException[0]; } else if (malformedTreeException[0] != null) { throw malformedTreeException[0]; } else if (coreException[0] != null) { throw coreException[0]; } return result[0]; } private UndoEdit doPerformEdits(IDocument document, boolean[] setContentStampSuccess) throws MalformedTreeException, BadLocationException, CoreException { // perform the changes LinkedModeModel.closeAllModels(document); UndoEdit redo= fUndo.apply(document, TextEdit.CREATE_UNDO); // try to restore the document content stamp setContentStampSuccess[0]= ContentStamps.set(document, fContentStampToRestore); return redo; } @Override public void dispose() { if (fValidationState != null) { fValidationState.dispose(); } } private boolean needsSaving() { return (fSaveMode & TextFileChange.FORCE_SAVE) != 0 || !fDirty && (fSaveMode & TextFileChange.KEEP_SAVE_STATE) != 0; } }