Copyright (c) 2000, 2009 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, 2009 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.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.ltk.internal.core.refactoring.NotCancelableProgressMonitor;
Operation that, when run, performs a Change
object. The operation can be created in two different ways: with a given change or with a CreateChangeOperation
. If created the second way the given create change operation will be used to create the actual change to perform. If the change has been performed successfully (e.g. changeExecuted()
returns true
) then the operation has called Change.dispose()
as well to clear-up internal state in the change object. If it hasn't been executed the change, the change is still intact and the client is responsible to dispose the change object.
If an undo change has been provided by the change to execute then the operation calls Change.initializeValidationData(IProgressMonitor)
to initialize the undo change's validation data.
If an undo manager has been set via the method setUndoManager(IUndoManager, String)
then the undo object, if any has been provided, will be pushed onto the manager's undo stack.
The operation should be executed via the run method offered by
IWorkspace
to achieve proper delta batching.
Note: this class is not intended to be extended outside of the refactoring framework.
Since: 3.0 @noextend This class is not intended to be subclassed by clients.
/**
* Operation that, when run, performs a {@link Change} object. The operation
* can be created in two different ways: with a given change or with a
* {@link CreateChangeOperation}. If created the second way the given create
* change operation will be used to create the actual change to perform.
* <p>
* If the change has been performed successfully (e.g. {@link #changeExecuted()} returns
* <code>true</code>) then the operation has called {@link Change#dispose()} as well
* to clear-up internal state in the change object. If it hasn't been executed the
* change, the change is still intact and the client is responsible to dispose the
* change object.
* </p>
* <p>
* If an undo change has been provided by the change to execute then the operation
* calls {@link Change#initializeValidationData(IProgressMonitor)} to initialize the
* undo change's validation data.
* </p>
* <p>
* If an undo manager has been set via the method {@link #setUndoManager(IUndoManager, String)}
* then the undo object, if any has been provided, will be pushed onto the manager's
* undo stack.
* </p>
* <p>
* The operation should be executed via the run method offered by
* <code>IWorkspace</code> to achieve proper delta batching.
* </p>
* <p>
* Note: this class is not intended to be extended outside of the refactoring framework.
* </p>
*
* @since 3.0
*
* @noextend This class is not intended to be subclassed by clients.
*/
public class PerformChangeOperation implements IWorkspaceRunnable {
private Change fChange;
private CreateChangeOperation fCreateChangeOperation;
private RefactoringStatus fValidationStatus;
private Change fUndoChange;
private String fUndoName;
private IUndoManager fUndoManager;
private boolean fChangeExecuted;
private boolean fChangeExecutionFailed;
private ISchedulingRule fSchedulingRule;
Creates a new perform change operation instance for the given change.
Params: - change – the change to be applied to the workbench
/**
* Creates a new perform change operation instance for the given change.
*
* @param change the change to be applied to the workbench
*/
public PerformChangeOperation(Change change) {
Assert.isNotNull(change);
fChange= change;
fSchedulingRule= ResourcesPlugin.getWorkspace().getRoot();
}
Creates a new PerformChangeOperation
for the given CreateChangeOperation
. The create change operation is used to create the actual change to execute. Params: - op – the
CreateChangeOperation
used to create the
actual change object
/**
* Creates a new <code>PerformChangeOperation</code> for the given {@link
* CreateChangeOperation}. The create change operation is used to create
* the actual change to execute.
*
* @param op the <code>CreateChangeOperation</code> used to create the
* actual change object
*/
public PerformChangeOperation(CreateChangeOperation op) {
Assert.isNotNull(op);
fCreateChangeOperation= op;
fSchedulingRule= ResourcesPlugin.getWorkspace().getRoot();
}
Returns true
if the change execution failed.
Returns: true
if the change execution failed;
false
otherwise
/**
* Returns <code>true</code> if the change execution failed.
*
* @return <code>true</code> if the change execution failed;
* <code>false</code> otherwise
*
*/
public boolean changeExecutionFailed() {
return fChangeExecutionFailed;
}
Returns true
if the change has been executed. Otherwise
false
is returned.
Returns: true
if the change has been executed, otherwise
false
/**
* Returns <code>true</code> if the change has been executed. Otherwise <code>
* false</code> is returned.
*
* @return <code>true</code> if the change has been executed, otherwise
* <code>false</code>
*/
public boolean changeExecuted() {
return fChangeExecuted;
}
Returns the status of the condition checking. Returns null
if
no condition checking has been requested.
Returns: the status of the condition checking
/**
* Returns the status of the condition checking. Returns <code>null</code> if
* no condition checking has been requested.
*
* @return the status of the condition checking
*/
public RefactoringStatus getConditionCheckingStatus() {
if (fCreateChangeOperation != null)
return fCreateChangeOperation.getConditionCheckingStatus();
return null;
}
Returns the change used by this operation. This is either the change passed to
the constructor or the one create by the CreateChangeOperation
.
Method returns null
if the create operation did not create
a corresponding change or hasn't been executed yet.
Returns: the change used by this operation or null
if no change
has been created
/**
* Returns the change used by this operation. This is either the change passed to
* the constructor or the one create by the <code>CreateChangeOperation</code>.
* Method returns <code>null</code> if the create operation did not create
* a corresponding change or hasn't been executed yet.
*
* @return the change used by this operation or <code>null</code> if no change
* has been created
*/
public Change getChange() {
return fChange;
}
Returns the undo change of the change performed by this operation. Returns
null
if the change hasn't been performed yet or if the change
doesn't provide a undo.
Returns: the undo change of the performed change or null
/**
* Returns the undo change of the change performed by this operation. Returns
* <code>null</code> if the change hasn't been performed yet or if the change
* doesn't provide a undo.
*
* @return the undo change of the performed change or <code>null</code>
*/
public Change getUndoChange() {
return fUndoChange;
}
Returns the refactoring status returned from the call IChange#isValid()
.
Returns null
if the change has not been executed.
Returns: the change's validation status
/**
* Returns the refactoring status returned from the call <code>IChange#isValid()</code>.
* Returns <code>null</code> if the change has not been executed.
*
* @return the change's validation status
*/
public RefactoringStatus getValidationStatus() {
return fValidationStatus;
}
Sets the undo manager. If the executed change provides an undo change,
then the undo change is pushed onto this manager.
Params: - manager – the undo manager to use or
null
if no
undo recording is desired - undoName – the name used to present the undo change on the undo
stack. Must be a human-readable string. Must not be
null
if manager is unequal null
/**
* Sets the undo manager. If the executed change provides an undo change,
* then the undo change is pushed onto this manager.
*
* @param manager the undo manager to use or <code>null</code> if no
* undo recording is desired
* @param undoName the name used to present the undo change on the undo
* stack. Must be a human-readable string. Must not be <code>null</code>
* if manager is unequal <code>null</code>
*/
public void setUndoManager(IUndoManager manager, String undoName) {
if (manager != null) {
Assert.isNotNull(undoName);
}
fUndoManager= manager;
fUndoName= undoName;
}
Sets the scheduling rule used to execute this operation. If
not set then the workspace root is used. The supplied Change
must be able to be performed in the provided scheduling rule.
Params: - rule – the rule to use, or
null
to use no scheduling rule
Since: 3.3
/**
* Sets the scheduling rule used to execute this operation. If
* not set then the workspace root is used. The supplied Change
* must be able to be performed in the provided scheduling rule.
*
* @param rule the rule to use, or <code>null</code> to use no scheduling rule
* @since 3.3
*/
public void setSchedulingRule(ISchedulingRule rule) {
fSchedulingRule= rule;
}
@Override
public void run(IProgressMonitor pm) throws CoreException {
if (pm == null)
pm= new NullProgressMonitor();
try {
fChangeExecuted= false;
if (createChange()) {
pm.beginTask("", 4); //$NON-NLS-1$
pm.subTask(""); //$NON-NLS-1$
fCreateChangeOperation.run(new SubProgressMonitor(pm, 3));
// Check for cancellation before executing the change, since canceling
// during change execution is not supported
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=187265 ):
if (pm.isCanceled())
throw new OperationCanceledException();
fChange= fCreateChangeOperation.getChange();
if (fChange != null) {
executeChange(new SubProgressMonitor(pm, 1));
} else {
pm.worked(1);
}
} else {
executeChange(pm);
}
} finally {
pm.done();
}
}
Actually executes the change.
Params: - pm – a progress monitor to report progress
Throws: - CoreException – if an unexpected error occurs during
change execution
/**
* Actually executes the change.
*
* @param pm a progress monitor to report progress
*
* @throws CoreException if an unexpected error occurs during
* change execution
*/
protected void executeChange(IProgressMonitor pm) throws CoreException {
fChangeExecuted= false;
if (!fChange.isEnabled())
return;
IWorkspaceRunnable runnable= new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
boolean undoInitialized= false;
try {
monitor.beginTask("", 10); //$NON-NLS-1$
fValidationStatus= fChange.isValid(new SubProgressMonitor(monitor, 1));
if (fValidationStatus.hasFatalError())
return;
boolean aboutToPerformChangeCalled= false;
try {
if (fUndoManager != null) {
ResourcesPlugin.getWorkspace().checkpoint(false);
fUndoManager.aboutToPerformChange(fChange);
aboutToPerformChangeCalled= true;
}
fChangeExecutionFailed= true;
fUndoChange= fChange.perform(new SubProgressMonitor(monitor, 9));
fChangeExecutionFailed= false;
fChangeExecuted= true;
} finally {
if (fUndoManager != null) {
ResourcesPlugin.getWorkspace().checkpoint(false);
if (aboutToPerformChangeCalled)
fUndoManager.changePerformed(fChange, !fChangeExecutionFailed);
}
}
fChange.dispose();
if (fUndoChange != null) {
fUndoChange.initializeValidationData(new NotCancelableProgressMonitor(
new SubProgressMonitor(monitor, 1)));
undoInitialized= true;
}
if (fUndoManager != null) {
if (fUndoChange != null) {
fUndoManager.addUndo(fUndoName, fUndoChange);
} else {
fUndoManager.flush();
}
}
} catch (CoreException | RuntimeException e) {
if (fUndoManager != null)
fUndoManager.flush();
if (fUndoChange != null && undoInitialized) {
Change ch= fUndoChange;
fUndoChange= null;
ch.dispose();
}
fUndoChange= null;
throw e;
} finally {
monitor.done();
}
}
};
ResourcesPlugin.getWorkspace().run(runnable, fSchedulingRule, IWorkspace.AVOID_UPDATE, pm);
}
private boolean createChange() {
return fCreateChangeOperation != null;
}
}