/******************************************************************************* * Copyright (c) 2000, 2009 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.core.refactoring; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.PlatformObject; import org.eclipse.core.runtime.SubProgressMonitor; /** * Abstract super class for all refactorings. Refactorings are used to perform behavior-preserving * workspace transformations. A refactoring offers two different kind of methods: * <ol> * <li>methods to check conditions to determine if the refactoring can be carried out in general and * if transformation will be behavior-preserving.</li> * <li>a method to create a {@link org.eclipse.ltk.core.refactoring.Change} object that represents * the actual work space modifications.</li> * </ol> * The life cycle of a refactoring is as follows: * <ol> * <li>the refactoring gets created</li> * <li>the refactoring is initialized with the elements to be refactored. It is up to a concrete * refactoring implementation to provide corresponding API.</li> * <li>{@link #checkInitialConditions(IProgressMonitor)} is called. The method can be called more * than once.</li> * <li>additional arguments are provided to perform the refactoring (for example the new name of a * element in the case of a rename refactoring). It is up to a concrete implementation to provide * corresponding API.</li> * <li>{@link #checkFinalConditions(IProgressMonitor)} is called. The method can be called more than * once. The method must not be called if {@link #checkInitialConditions(IProgressMonitor)} returns * a refactoring status of severity {@link RefactoringStatus#FATAL}.</li> * <li>{@link #createChange(IProgressMonitor)} is called. The method must only be called once after * each call to {@link #checkFinalConditions(IProgressMonitor)} and should not be called if one of * the condition checking methods returns a refactoring status of severity * {@link RefactoringStatus#FATAL}.</li> * <li>steps 4 to 6 can be executed repeatedly (for example when the user goes back from the preview * page).</li> * </ol> * * <p> * A refactoring can not assume that all resources are saved before any methods are called on it. * Therefore a refactoring must be able to deal with unsaved resources. * </p> * <p> * The class should be subclassed by clients wishing to implement new refactorings. * </p> * * * @since 3.0 * * @author Mohsen Vakilian, nchen - Enabled the refactoring to keep track of its invoker. * */ public abstract class Refactoring extends PlatformObject { private Object fValidationContext; /** * Sets the validation context used when calling * {@link org.eclipse.core.resources.IWorkspace#validateEdit(org.eclipse.core.resources.IFile[], java.lang.Object)} * . * * @param context the <code>org.eclipse.swt.widgets.Shell</code> that is to be used to parent * any dialogs with the user, or <code>null</code> if there is no UI context * (declared as an <code>Object</code> to avoid any direct references on the SWT * component) */ public final void setValidationContext(Object context) { fValidationContext= context; } /** * Returns the validation context * * @return the validation context or <code>null</code> if no validation context has been set. */ public final Object getValidationContext() { return fValidationContext; } /** * Returns the refactoring's name. * * @return the refactoring's human readable name. Must not be <code>null</code> */ public abstract String getName(); //---- Conditions ------------------------------------------------------------ /** * Returns the tick provider used for progress reporting for this refactoring. * * @return the refactoring tick provider used for progress reporting * * @since 3.2 */ public final RefactoringTickProvider getRefactoringTickProvider() { RefactoringTickProvider result= doGetRefactoringTickProvider(); if (result == null) { result= RefactoringTickProvider.DEFAULT; } return result; } /** * Hook method to provide the tick provider used for progress reporting. * <p> * Subclasses may override this method * </p> * * @return the refactoring tick provider used for progress reporting * * @since 3.2 */ protected RefactoringTickProvider doGetRefactoringTickProvider() { return RefactoringTickProvider.DEFAULT; } /** * Checks all conditions. This implementation calls <code>checkInitialConditions</code> and * <code>checkFinalConditions</code>. * <p> * Subclasses may extend this method to provide additional condition checks. * </p> * * @param pm a progress monitor to report progress * * @return a refactoring status. If the status is <code>RefactoringStatus#FATAL</code> the * refactoring has to be considered as not being executable. * * @throws CoreException if an exception occurred during condition checking. If this happens * then the condition checking has to be interpreted as failed * * @throws OperationCanceledException if the condition checking got canceled * * @see #checkInitialConditions(IProgressMonitor) * @see #checkFinalConditions(IProgressMonitor) */ public RefactoringStatus checkAllConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException { RefactoringTickProvider refactoringTickProvider= getRefactoringTickProvider(); pm.beginTask("", refactoringTickProvider.getCheckAllConditionsTicks()); //$NON-NLS-1$ RefactoringStatus result= new RefactoringStatus(); result.merge(checkInitialConditions(new SubProgressMonitor(pm, refactoringTickProvider.getCheckInitialConditionsTicks()))); if (!result.hasFatalError()) { if (pm.isCanceled()) throw new OperationCanceledException(); result.merge(checkFinalConditions(new SubProgressMonitor(pm, refactoringTickProvider.getCheckFinalConditionsTicks()))); } pm.done(); return result; } /** * Checks some initial conditions based on the element to be refactored. The method is typically * called by the UI to perform an initial checks after an action has been executed. * <p> * The refactoring has to be considered as not being executable if the returned status has the * severity of <code>RefactoringStatus#FATAL</code>. * </p> * <p> * This method can be called more than once. * </p> * * @param pm a progress monitor to report progress. Although initial checks are supposed to * execute fast, there can be certain situations where progress reporting is * necessary. For example rebuilding a corrupted index may report progress. * * @return a refactoring status. If the status is <code>RefactoringStatus#FATAL</code> the * refactoring has to be considered as not being executable. * * @throws CoreException if an exception occurred during initial condition checking. If this * happens then the initial condition checking has to be interpreted as failed * * @throws OperationCanceledException if the condition checking got canceled * * @see #checkFinalConditions(IProgressMonitor) * @see RefactoringStatus#FATAL */ public abstract RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException; /** * After <code>checkInitialConditions</code> has been performed and the user has provided all * input necessary to perform the refactoring this method is called to check the remaining * preconditions. * <p> * The refactoring has to be considered as not being executable if the returned status has the * severity of <code>RefactoringStatus#FATAL</code>. * </p> * <p> * This method can be called more than once. * </p> * * @param pm a progress monitor to report progress * * @return a refactoring status. If the status is <code>RefactoringStatus#FATAL</code> the * refactoring is considered as not being executable. * * @throws CoreException if an exception occurred during final condition checking If this * happens then the final condition checking is interpreted as failed * * @throws OperationCanceledException if the condition checking got canceled * * @see #checkInitialConditions(IProgressMonitor) * @see RefactoringStatus#FATAL */ public abstract RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException; //---- change creation ------------------------------------------------------ /** * Creates a {@link Change} object that performs the actual workspace transformation. * * @param pm a progress monitor to report progress * * @return the change representing the workspace modifications of the refactoring * * @throws CoreException if an error occurred while creating the change * * @throws OperationCanceledException if the condition checking got canceled */ public abstract Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException; /** * {@inheritDoc} */ public Object getAdapter(Class adapter) { if (adapter.isInstance(this)) return this; return super.getAdapter(adapter); } /* (non-Javadoc) * for debugging only */ public String toString() { return getName(); } ///////////////// //CODINGSPECTATOR ///////////////// //RefactoringWizardOpenOperation updates the state of the refactoring when it checks initial conditions. private boolean refWizOpenOpCheckedInitConds= false; public void unsetRefWizOpenOpCheckedInitConds() { refWizOpenOpCheckedInitConds= false; } public void setRefWizOpenOpCheckedInitConds() { refWizOpenOpCheckedInitConds= true; } public boolean isRefWizOpenOpCheckedInitConds() { return refWizOpenOpCheckedInitConds; } private boolean invokedByQuickAssist= false; public boolean isInvokedByQuickAssist() { return invokedByQuickAssist; } public void setInvokedByQuickAssist() { invokedByQuickAssist= true; } public void setInvokedByQuickAssist(boolean invokedByQuickAssist) { this.invokedByQuickAssist= invokedByQuickAssist; } }