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
@noextendThis 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; } }