/*******************************************************************************
* Copyright (c) 2000, 2008 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
* Oakland Software (Francis Upton) <francisu@ieee.org> -
* Fix for Bug 63149 [ltk] allow changes to be executed after the 'main' change during an undo [refactoring]
*******************************************************************************/
package org.eclipse.ltk.core.refactoring.participants;
import org.eclipse.core.runtime.Assert;
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.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextChange;
import org.eclipse.ltk.internal.core.refactoring.ParticipantDescriptor;
/**
* A refactoring participant can participate in the condition checking and
* change creation of a {@link RefactoringProcessor}.
* <p>
* If the severity of the condition checking result is {@link RefactoringStatus#FATAL}
* then the whole refactoring will not be carried out.
* </p>
* <p>
* The changes created by a participant <em>MUST</em> not conflict with any changes
* provided by other participants or the refactoring itself. To ensure this, a participant
* is only allowed to manipulate resources belonging to its domain. As of 3.1 this got
* relaxed for textual resources. A participant can now change a textual resource already
* manipulated by the processor as long as both are manipulating different regions in the
* file (see {@link #createChange(IProgressMonitor)} and {@link #getTextChange(Object)}).
* For example a rename type participant updating launch configuration is only allowed to
* update launch configurations or shared textual resources. If a change conflicts with
* another change during execution then the participant who created the change will be
* disabled for the rest of the eclipse session.
* </p>
* <p>
* A refactoring participant can not assume that all resources are saved before any
* methods are called on it. Therefore a participant must be able to deal with unsaved
* resources.
* </p>
* <p>
* A refactoring participant can implement {@link ISharableParticipant} in order to be
* shared for multiple elements to be refactored by the same processor.
* </p>
* <p>
* This class should be subclassed by clients wishing to provide special refactoring
* participants extension points.
* </p>
* <p>
* Since 3.4, a refactoring participant can also override {@link #createPreChange(IProgressMonitor)}
* to add changes that will be executed <em>before</em> the main refactoring changes
* are executed.
* </p>
*
* @see RefactoringProcessor
* @see ISharableParticipant
*
* @since 3.0
*/
public abstract class RefactoringParticipant extends PlatformObject {
private RefactoringProcessor fProcessor;
private ParticipantDescriptor fDescriptor;
/**
* Returns the processor that is associated with this participant.
*
* @return the processor that is associated with this participant
*/
public RefactoringProcessor getProcessor() {
return fProcessor;
}
/**
* Initializes the participant. This method is called by the framework when a
* participant gets instantiated.
* <p>
* This method isn't intended to be extended or reimplemented by clients.
* </p>
* @param processor the processor this participant is associated with
* @param element the element to be refactored
* @param arguments the refactoring arguments
*
* @return <code>true</code> if the participant could be initialized;
* otherwise <code>false</code> is returned. If <code>false</code> is
* returned then the participant will not be added to the refactoring.
*
* @see #initialize(Object)
*/
public boolean initialize(RefactoringProcessor processor, Object element, RefactoringArguments arguments) {
Assert.isNotNull(processor);
Assert.isNotNull(arguments);
fProcessor= processor;
initialize(arguments);
return initialize(element);
}
/**
* Initializes the participant with the element to be refactored.
* If this method returns <code>false</code> then the framework
* will consider the participant as not being initialized and the
* participant will be dropped by the framework.
*
* @param element the element to be refactored
*
* @return <code>true</code> if the participant could be initialized;
* otherwise <code>false</code> is returned.
*/
protected abstract boolean initialize(Object element);
/**
* Initializes the participant with the refactoring arguments
*
* @param arguments the refactoring arguments
*/
protected abstract void initialize(RefactoringArguments arguments);
/**
* Returns a human readable name of this participant.
*
* @return a human readable name
*/
public abstract String getName();
/**
* Checks the conditions of the refactoring participant.
* <p>
* The refactoring is considered as not being executable if the returned status
* has the severity of <code>RefactoringStatus#FATAL</code>. Note that this blocks
* the whole refactoring operation!
* </p>
* <p>
* Clients should use the passed {@link CheckConditionsContext} to validate the changes
* they generate. If the generated changes include workspace resource modifications,
* clients should call ...
*
* <pre> (ResourceChangeChecker) context.getChecker(ResourceChangeChecker.class);
* IResourceChangeDescriptionFactory deltaFactory= checker.getDeltaFactory();</pre>
*
* ... and use the delta factory to describe all resource modifications in advance.
* </p>
* <p>
* This method can be called more than once.
* </p>
*
* @param pm a progress monitor to report progress
* @param context a condition checking context to collect shared condition checks
*
* @return a refactoring status. If the status is <code>RefactoringStatus#FATAL</code>
* the refactoring is considered as not being executable.
*
* @throws OperationCanceledException if the condition checking got canceled
*
* @see org.eclipse.ltk.core.refactoring.Refactoring#checkInitialConditions(IProgressMonitor)
* @see RefactoringStatus
*/
public abstract RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context) throws OperationCanceledException;
/**
* Creates a {@link Change} object that contains the workspace modifications
* of this participant to be executed <em>before</em> the
* changes from the refactoring are executed. Note that this implies that the
* undo change of the returned Change object will be executed <em>after</em>
* the undo changes from the refactoring have been executed.
* <p>
* The changes provided
* by a participant <em>must</em> not conflict with any change provided by other
* participants or by the refactoring itself.
* <p>
* If the change conflicts with any change provided by other participants or
* by the refactoring itself, then change execution will fail and the
* participant will be disabled for the rest of the eclipse session.
* </p>
* <p>
* If an exception occurs while creating the change, the refactoring can not
* be carried out, and the participant will be disabled for the rest of the
* eclipse session.
* </p>
* <p>
* A participant can manipulate text resource already manipulated by
* the processor as long as the textual manipulations don't conflict (e.g.
* the participant manipulates a different region of the text resource).
* The method must not return those changes in its change tree since the change
* is already part of another change tree. If the participant only manipulates
* shared changes then it can return <code>null</code> to indicate that it didn't
* create own changes. A shared text change can be accessed via the method
* {@link #getTextChange(Object)}.
* </p>
* <p>
* The default implementation returns <code>null</code>. Subclasses can extend or override.
* </p>
* <p>
* Note that most refactorings will implement {@link #createChange(IProgressMonitor)}
* rather than this method.
* </p>
*
* @param pm a progress monitor to report progress
*
* @return the change representing the workspace modifications to be executed
* before the refactoring change or <code>null</code> if no changes are made
*
* @throws CoreException if an error occurred while creating the change
*
* @throws OperationCanceledException if the change creation got canceled
*
* @see #createChange(IProgressMonitor)
*
* @since 3.4
*/
public Change createPreChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
return null;
}
/**
* Creates a {@link Change} object that contains the workspace modifications
* of this participant to be executed <em>after</em> the
* changes from the refactoring are executed. Note that this implies that the
* undo change of the returned Change object will be executed <em>before</em>
* the undo changes from the refactoring have been executed.
* <p>
* The changes provided by a participant <em>must</em>
* not conflict with any change provided by other participants or by the
* refactoring itself.
* <p>
* If the change conflicts with any change provided by other participants or
* by the refactoring itself, then change execution will fail and the
* participant will be disabled for the rest of the eclipse session.
* </p>
* <p>
* If an exception occurs while creating the change, the refactoring can not
* be carried out, and the participant will be disabled for the rest of the
* eclipse session.
* </p>
* <p>
* As of 3.1, a participant can manipulate text resources already manipulated by
* the processor as long as the textual manipulations don't conflict (i.e.
* the participant manipulates a different region of the text resource).
* The method must not return those changes in its change tree since the change
* is already part of another change tree. If the participant only manipulates
* shared changes, then it can return <code>null</code> to indicate that it didn't
* create own changes. A shared text change can be accessed via the method
* {@link #getTextChange(Object)}.
* </p>
*
* @param pm a progress monitor to report progress
*
* @return the change representing the workspace modifications to be executed
* after the refactoring change or <code>null</code> if no changes are made
*
* @throws CoreException if an error occurred while creating the change
*
* @throws OperationCanceledException if the change creation got canceled
*
* @see #createPreChange(IProgressMonitor)
*/
public abstract Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException;
/**
* Returns the text change for the given element or <code>null</code>
* if a text change doesn't exist. This method only returns a valid
* result during change creation. Outside of change creation always
* <code>null</code> is returned.
*
* @param element the element to be modified for which a text change
* is requested
*
* @return the text change or <code>null</code> if no text change exists
* for the element
*
* @since 3.1
*/
public TextChange getTextChange(Object element) {
return getProcessor().getRefactoring().getTextChange(element);
}
//---- helper method ----------------------------------------------------
/* package */ void setDescriptor(ParticipantDescriptor descriptor) {
Assert.isNotNull(descriptor);
fDescriptor= descriptor;
}
/* package */ ParticipantDescriptor getDescriptor() {
return fDescriptor;
}
}