diff --git a/org.eclipse.ltk.core.refactoring.tests/.classpath b/org.eclipse.ltk.core.refactoring.tests/.classpath
new file mode 100644
index 00000000000..065ac06e197
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring.tests/.classpath
@@ -0,0 +1,7 @@
+
+
Change
object
+ * is typically created by calling Refactoring.createChange()
.
+ * + * Changes are best executed by using a {@link PerformChangeOperation}. If clients + * execute a change directly then the following life cycle has to be honored: + *
initializeValidationState
has to be called.isValid
can be used to determine if a change
+ * can still be applied to the work space. If the method returns a {@link
+ * RefactoringStatus} with a severity of FATAL then the change has to be
+ * treated as invalid. Performing an invalid change isn't allowed and
+ * results in an unspecified result. This method can be called multiple
+ * times.
+ * initializeValidationState
. There is no guarantee
+ * that initializeValidationState
, isValid
+ * or perform
has been called, before dispose
+ * is called.
+ * + * Change change= createChange(); + * try { + * change.initializeValidationState(pm); + * + * .... + * + * if (!change.isEnabled()) + * return; + * RefactoringStatus valid= change.isValid(new SubProgressMonitor(pm, 1)); + * if (valid.hasFatalError()) + * return; + * Change undo= change.perform(new SubProgressMonitor(pm, 1)); + * if (undo != null) { + * undo.initializeValidationState(new SubProgressMonitor(pm, 1)); + * // do something with the undo object + * } + * } finally { + * change.dispose(); + * } + *+ * + *
+ * It is important that implementors of this abstract class provide an adequat
+ * implementation of isValid
and that they provide an undo change
+ * via the return value of the method perform
. If no undo can be
+ * provided then the perform method is allowed to return null
. But
+ * implementors should be aware that not providing an undo object for a change
+ * object that is part of a larger change tree will result in the fact that for
+ * the whole change tree no undo object will be present.
+ *
null
.
+ *
+ * @return the human readable name of this change
+ */
+ public abstract String getName();
+
+ /**
+ * Returns whether this change is enabled or not. Disabled changes
+ * must not be executed.
+ *
+ * @return true
if the change is enabled; false
+ * otherwise.
+ */
+ public boolean isEnabled() {
+ return fIsEnabled;
+ }
+
+ /**
+ * Sets whether this change is enabled or not.
+ *
+ * @param enabled true
to enable this change;
+ * false
otherwise
+ */
+ public void setEnabled(boolean enabled) {
+ fIsEnabled= enabled;
+ }
+
+ /**
+ * Returns the parent change. Returns null
if no
+ * parent exists.
+ *
+ * @return the parent change
+ */
+ public Change getParent() {
+ return fParent;
+ }
+
+ /**
+ * Sets the parent of this change. Requires that this change isn't already
+ * connected to a parent. The parent can be null
to disconnect
+ * this change from a parent.
+ *
+ * @param parent the parent of this change or null
+ */
+ public void setParent(Change parent) {
+ if (parent != null)
+ Assert.isTrue(fParent == null);
+ fParent= parent;
+ }
+
+ /**
+ * Hook method to initialize some internal state to provide an adequat answer
+ * for the isValid
method. This method gets called after a change
+ * or a whole change tree has been created.
+ * + * Typically this method is implemented in one of the following ways: + *
dispose
.isValid
is called.
+ * For example, a change object that manipulates the content of an IFile
+ * could either listen to resource changes and detect that the file got changed or
+ * it could remember the time stamp and compare it with the actual time stamp when
+ * isValid
is called.
+ *
perform
. If a refactoring status with a severity of {@link
+ * RefactoringStatus#FATAL} is returned then the change has to be treated as invalid
+ * and can no longer be executed. Performing such a change produces an unspecified
+ * result and will very likely throw an exception.
+ * + * This method is also called by the {@link IUndoManager UndoManager} to decide if + * an undo or redo change is still valid and therefore can be executed. + *
+ *+ * This method can be called multiple times before a change gets executed. + *
+ * + * @param pm a progress monitor. + * + * @return a refactoring status describing the outcome of the validation check + * + * @throws CoreException if an error occurred during validation check. The change + * is to be treated as invalid if an exception occurs + */ + public abstract RefactoringStatus isValid(IProgressMonitor pm) throws CoreException; + + /** + * Performs this change. If this method is call on an invalid or disabled change + * object the result is unspecified. + * + * @param pm a progress monitor + * + * @return the undo change for this change object ornull
if no
+ * undo is provided
+ *
+ * @throws CoreException if an error occurred during change execution
+ */
+ public abstract Change perform(IProgressMonitor pm) throws CoreException;
+
+ /**
+ * Disposes this change. Subclasses that override this method typically
+ * unregister listeners which got registered during the call to
+ * initializeValidationState
.
+ * + * Subclasses may override this method. + *
+ */ + public void dispose() { + // empty default implementation + } + + /** + * Returns the element modified by thisChange
. The method may return
+ * null
if the change isn't related to a element.
+ *
+ * @return the element modified by this change
+ */
+ public abstract Object getModifiedElement();
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getAdapter(Class adapter) {
+ if (fParent == null)
+ return null;
+ return fParent.getAdapter(adapter);
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/ChangeContext.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/ChangeContext.java
new file mode 100644
index 00000000000..ce4a25f37d2
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/ChangeContext.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+
+/**
+ * @deprecated. Will not become API in 3.0. Is only here to make some
+ * old methods in Change final. Will go away for 3.0.
+ */
+/* package */ class ChangeContext {
+ private ChangeContext() {
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/CheckConditionsOperation.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/CheckConditionsOperation.java
new file mode 100644
index 00000000000..6d8575d0c22
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/CheckConditionsOperation.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-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.resources.IWorkspaceRunnable;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+/**
+ * Operation that, when run, check preconditions of the {@link Refactoring}
+ * passed on creation.
+ *
+ * @since 3.0
+ */
+public class CheckConditionsOperation implements IWorkspaceRunnable {
+
+ private Refactoring fRefactoring;
+ private int fStyle;
+ private RefactoringStatus fStatus;
+
+ public final static int NONE= 0;
+ public final static int INITIAL_CONDITONS= 1 << 1;
+ public final static int FINAL_CONDITIONS= 1 << 2;
+ public final static int ALL_CONDITIONS= INITIAL_CONDITONS | FINAL_CONDITIONS;
+ private final static int LAST= 1 << 3;
+
+ /**
+ * Creates a new CheckConditionsOperation
.
+ *
+ * @param refactoring the refactoring for which the preconditions are to
+ * be checked.
+ * @param style style to define which conditions to check. Must be one of
+ * ACTIVATION
, INPUT
or PRECONDITIONS
+ */
+ public CheckConditionsOperation(Refactoring refactoring, int style) {
+ Assert.isNotNull(refactoring);
+ fRefactoring= refactoring;
+ fStyle= style;
+ Assert.isTrue(checkStyle(fStyle));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run(IProgressMonitor pm) throws CoreException {
+ try {
+ fStatus= null;
+ if ((fStyle & ALL_CONDITIONS) == ALL_CONDITIONS)
+ fStatus= fRefactoring.checkAllConditions(pm);
+ else if ((fStyle & INITIAL_CONDITONS) == INITIAL_CONDITONS)
+ fStatus= fRefactoring.checkInitialConditions(pm);
+ else if ((fStyle & FINAL_CONDITIONS) == FINAL_CONDITIONS)
+ fStatus= fRefactoring.checkFinalConditions(pm);
+ } finally {
+ pm.done();
+ }
+ }
+
+ /**
+ * Returns the outcome of the operation or null
if an exception
+ * has occurred when performing the operation.
+ *
+ * @return the {@link RefactoringStatus} of the condition checking
+ */
+ public RefactoringStatus getStatus() {
+ return fStatus;
+ }
+
+ /**
+ * Returns the operation's refactoring
+ *
+ * @return the operation's refactoring
+ */
+ public Refactoring getRefactoring() {
+ return fRefactoring;
+ }
+
+ /**
+ * Returns the condition checking style.
+ *
+ * @return the condition checking style
+ */
+ public int getStyle() {
+ return fStyle;
+ }
+
+ private boolean checkStyle(int style) {
+ return style > NONE && style < LAST;
+ }
+
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/CompositeChange.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/CompositeChange.java
new file mode 100644
index 00000000000..850587cb3bb
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/CompositeChange.java
@@ -0,0 +1,359 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+import org.eclipse.ltk.internal.core.refactoring.RefactoringCoreMessages;
+import org.eclipse.ltk.internal.core.refactoring.RefactoringCorePlugin;
+
+/**
+ * Represents a composite change. Composite changes can be marked
+ * as generic. Generic composite changes will not be shown in the
+ * user interface. When rendering a change tree the children of
+ * a generic composite change will be shown as children of the
+ * parent change.
+ *
+ * @see Change
+ *
+ * @since 3.0
+ */
+public class CompositeChange extends Change {
+
+ private String fName;
+ private List fChanges;
+ private boolean fIsGeneric;
+ private Change fUndoUntilException;
+
+ /**
+ * Creates a new composite change with a generic name. The change
+ * is marked as generic and should therefore not be presented in
+ * the user interface.
+ */
+ public CompositeChange() {
+ this(RefactoringCoreMessages.getString("CompositeChange.name")); //$NON-NLS-1$
+ markAsGeneric();
+ }
+
+ /**
+ * Creates a new composite change with the given name.
+ *
+ * @param name the name of the composite change
+ */
+ public CompositeChange(String name) {
+ this(name, new ArrayList(5));
+ }
+
+ /**
+ * Creates a new composite change with the given name and array
+ * of children.
+ *
+ * @param name the change's name
+ * @param children the initialize array of children
+ */
+ public CompositeChange(String name, Change[] children) {
+ this(name, new ArrayList(children.length));
+ addAll(children);
+ }
+
+ private CompositeChange(String name, List changes) {
+ Assert.isNotNull(changes);
+ Assert.isNotNull(name);
+ fChanges= changes;
+ fName= name;
+ fIsGeneric= false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ return fName;
+ }
+
+ /**
+ * Returns whether this change is generic or not.
+ *
+ * @return true
if this change is generic; otherwise
+ * false
+ */
+ public boolean isGeneric() {
+ return fIsGeneric;
+ }
+
+ /**
+ * Marks this change as generic.
+ */
+ public void markAsGeneric() {
+ fIsGeneric= true;
+ }
+
+ /**
+ * Adds the given change to the list of children.
+ *
+ * @param change the change to add
+ */
+ public void add(Change change) {
+ if (change != null) {
+ Assert.isTrue(change.getParent() == null);
+ fChanges.add(change);
+ change.setParent(this);
+ }
+ }
+
+ /**
+ * Adds all changes in the given array to the list of children.
+ *
+ * @param changes the changes to add
+ */
+ public void addAll(Change[] changes) {
+ for (int i= 0; i < changes.length; i++) {
+ add(changes[i]);
+ }
+ }
+
+ /**
+ * Merges the children of the given composite change into this
+ * change. This means the changes are removed from the given
+ * composite change and added to this change.
+ *
+ * @param change the change to merge
+ */
+ public void merge(CompositeChange change) {
+ Change[] others= change.getChildren();
+ for (int i= 0; i < others.length; i++) {
+ Change other= others[i];
+ change.remove(other);
+ add(other);
+ }
+ }
+
+ /**
+ * Removes the given change from the list of children.
+ *
+ * @param change the change to remove
+ *
+ * @return true
if the change contained the given
+ * child; otherwise false
is returned
+ */
+ public boolean remove(Change change) {
+ Assert.isNotNull(change);
+ boolean result= fChanges.remove(change);
+ if (result) {
+ change.setParent(null);
+ }
+ return result;
+
+ }
+
+ /**
+ * Returns the children managed by this composite change.
+ *
+ * @return the children
+ */
+ public Change[] getChildren() {
+ if (fChanges == null)
+ return null;
+ return (Change[])fChanges.toArray(new Change[fChanges.size()]);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * The composite change sends setEnabled
to all its children.
+ *
+ * The composite change sends initializeValidationData
to all its
+ * children. If one of the children throws an exception the remaining children
+ * will not receive the initializeValidationData
call.
+ *
+ * The composite change sends isValid
to all its children
+ * until the first one returns a status with a severity of FATAL
+ *
. If one of the children throws an exception the remaining children
+ * will not receive the isValid
call.
+ *
+ * The composite change sends perform
to all its enabled
+ * children. If one of the children throws an exception the remaining children
+ * will not receive the perform
call. In this case the method
+ * getUndoUntilException
can be used to get an undo object containing the
+ * undos of all executed children.
+ *
+ * The composite change sends dispose
to all its children. It is guaranteed
+ * that all children receive the dispose
call.
+ *
null
if all changes were executed successfully.
+ *
+ * @return the undo object containing all undo changes of those children
+ * that got successfully executed while performing this change
+ */
+ public Change getUndoUntilException() {
+ return fUndoUntilException;
+ }
+
+ /**
+ * Hook to create an undo change.
+ *
+ * @param childUndos the child undo. The undos appear in the
+ * list in the reverse order of their execution. So the first
+ * change in the array is the undo change of the last change
+ * that got executed.
+ *
+ * @return the undo change
+ *
+ * @throws CoreException if an undo change can't be created
+ */
+ protected Change createUndoChange(Change[] childUndos) {
+ return new CompositeChange(getName(), childUndos);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getModifiedElement() {
+ return null;
+ }
+
+ public String toString() {
+ StringBuffer buff= new StringBuffer();
+ buff.append(getName());
+ buff.append("\n"); //$NON-NLS-1$
+ for (Iterator iter= fChanges.iterator(); iter.hasNext();) {
+ buff.append("<").append(iter.next().toString()).append("/>\n"); //$NON-NLS-2$ //$NON-NLS-1$
+ }
+ return buff.toString();
+ }
+
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/CreateChangeOperation.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/CreateChangeOperation.java
new file mode 100644
index 00000000000..fffaf1da899
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/CreateChangeOperation.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-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.SubProgressMonitor;
+
+import org.eclipse.core.resources.IWorkspaceRunnable;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+/**
+ * Operation that, when performed, creates a {@link Change} object for a given
+ * refactoring. If created with a refactoring object directly, no precondition
+ * checking is performed. If created with a {@link CheckConditionsOperation} the
+ * requested precondition checking is performed before creating the change.
+ * + * If the precondition checking returns a fatal error or the status's severity + * exceeds a certain threshold then no change will be created. + *
+ *+ * If a change has been created the operation calls {@link Change#initializeValidationData(IProgressMonitor)} + * to initialize the change's validation data. + *
+ * + * @since 3.0 + */ +public class CreateChangeOperation implements IWorkspaceRunnable { + + private Refactoring fRefactoring; + + private CheckConditionsOperation fCheckConditionOperation; + private int fCheckPassedSeverity; + + private Change fChange; + + /** + * Creates a new operation with the given refactoring. No condition checking + * is performed before creating the change object. It is assumed that the + * condition checking has already been performed outside of this operation. + * The operation might fail if the precondition checking has not been performed + * yet. + * + * @param refactoring the refactoring for which the change is to be created + * @param style style to define which conditions to check + */ + public CreateChangeOperation(Refactoring refactoring) { + Assert.isNotNull(refactoring); + fRefactoring= refactoring; + } + + /** + * Creates a new operation with the given {@link CheckConditionsOperation}. When + * performed the operation first checks the conditions as specified by the
+ * CheckConditionsOperation
. Depending on the result of the condition
+ * checking a change object is created or not.
+ *
+ * @param operation the condition checking operation
+ * @param checkPassedSeverity the check passed severity value. This value is used to
+ * decide whether the condition check is interpreted as passed or not. The condition
+ * check is considered to be passed if the refactoring status's severity is less or
+ * equal than the given severity value. The given value must be smaller than {@link
+ * RefactoringStatus.FATAL}.
+ *
+ * @see #setCheckPassedSeverity(int)
+ */
+ public CreateChangeOperation(CheckConditionsOperation operation, int checkPassedSeverity) {
+ Assert.isNotNull(operation);
+ fCheckConditionOperation= operation;
+ fRefactoring= operation.getRefactoring();
+ Assert.isTrue (checkPassedSeverity < RefactoringStatus.FATAL);
+ fCheckPassedSeverity= checkPassedSeverity;
+ }
+
+ /**
+ * Returns the check passed severity.
+ *
+ * @return the check passed severity
+ *
+ * @see RefactoringStatus
+ */
+ public int getCheckPassedSeverity() {
+ return fCheckPassedSeverity;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run(IProgressMonitor pm) throws CoreException {
+ fChange= null;
+ try {
+ fChange= null;
+ if (fCheckConditionOperation != null) {
+ pm.beginTask("", 7); //$NON-NLS-1$
+ pm.subTask(""); //$NON-NLS-1$
+ fCheckConditionOperation.run(new SubProgressMonitor(pm, 4));
+ RefactoringStatus status= fCheckConditionOperation.getStatus();
+ if (status != null && status.getSeverity() <= fCheckPassedSeverity) {
+ fChange= fRefactoring.createChange(new SubProgressMonitor(pm, 2));
+ fChange.initializeValidationData(new SubProgressMonitor(pm, 1));
+ } else {
+ pm.worked(3);
+ }
+ } else {
+ pm.beginTask("", 3); //$NON-NLS-1$
+ fChange= fRefactoring.createChange(new SubProgressMonitor(pm, 2));
+ fChange.initializeValidationData(new SubProgressMonitor(pm, 1));
+ }
+ } finally {
+ pm.done();
+ }
+ }
+
+ /**
+ * Returns the outcome of the operation or null
if an exception
+ * occurred when performing the operation.
+ *
+ * @return the created change or null
+ */
+ public Change getChange() {
+ return fChange;
+ }
+
+ /**
+ * Returns the status of the condition checking. Returns null
if
+ * no condition checking has been requested.
+ *
+ * @return the status of the condition checking
+ */
+ public RefactoringStatus getConditionCheckingStatus() {
+ if (fCheckConditionOperation != null)
+ return fCheckConditionOperation.getStatus();
+ return null;
+ }
+
+ /**
+ * Returns the condition checking style as set to the {@link CheckConditionsOperation}.
+ * If no condition checking operation is provided (e.g. the change is created directly
+ * by calling {@link Refactoring#createChange(IProgressMonitor)} then {@link
+ * CheckConditionsOperation.NONE} is returned.
+ *
+ * @return the condition checking style
+ */
+ public int getConditionCheckingStyle() {
+ if (fCheckConditionOperation != null)
+ return fCheckConditionOperation.getStyle();
+ return CheckConditionsOperation.NONE;
+
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/DocumentChange.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/DocumentChange.java
new file mode 100644
index 00000000000..2322656e621
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/DocumentChange.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+import org.eclipse.text.edits.UndoEdit;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.jface.text.IDocument;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+import org.eclipse.ltk.internal.core.refactoring.TextChanges;
+
+/**
+ * A text change that operates directly on instances of {@link IDocument}.
+ *
+ * @since 3.0
+ */
+public class DocumentChange extends TextChange {
+
+ private IDocument fDocument;
+ private int fLength;
+
+ /**
+ * Creates a new DocumentChange
for the given
+ * {@link IDocument}.
+ *
+ * @param name the change's name. Has to be a human readable name.
+ * @param document the document this change is working on
+ */
+ public DocumentChange(String name, IDocument document) {
+ super(name);
+ Assert.isNotNull(document);
+ fDocument= document;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getModifiedElement(){
+ return fDocument;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void initializeValidationData(IProgressMonitor pm) throws CoreException {
+ // as long as we don't have modification stamps on documents
+ // we can only remember its length.
+ fLength= fDocument.getLength();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public RefactoringStatus isValid(IProgressMonitor pm) throws CoreException {
+ pm.beginTask("", 1); //$NON-NLS-1$
+ RefactoringStatus result= TextChanges.isValid(fDocument, fLength);
+ pm.worked(1);
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected IDocument aquireDocument(IProgressMonitor pm) throws CoreException {
+ return fDocument;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void commit(IDocument document, IProgressMonitor pm) throws CoreException {
+ // do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void releaseDocument(IDocument document, IProgressMonitor pm) throws CoreException {
+ //do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected Change createUndoChange(UndoEdit edit) throws CoreException {
+ return new UndoDocumentChange(getName(), fDocument, edit);
+ }
+}
+
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/IDynamicValidationStateChange.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/IDynamicValidationStateChange.java
new file mode 100644
index 00000000000..5f2373c8891
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/IDynamicValidationStateChange.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+
+/**
+ * This is a tagging interface to indicate that the validation
+ * state of a change changes dynamically. This gives clients
+ * that rely on the change's validation state (the value returned
+ * form {@link org.eclipse.ltk.core.refactoring.Change#isValid(IProgressMonitor)
+ * IChange#isValid}) the opportunity to dynamically update their state
+ * as well. For example, the undo/redo stack listens to validation
+ * state changs and removes undo/redo changes from the undo/redo stack
+ * when a change becomes invalid.
+ *
+ * @since 3.0
+ */
+public interface IDynamicValidationStateChange {
+
+ /**
+ * Adds a validation state listener. Has no effect if an
+ * identical listener is already registered.
+ *
+ * @param listener the listener to add
+ */
+ public void addValidationStateListener(IValidationStateListener listener);
+
+ /**
+ * Removes the validation state listener. Has no effect if
+ * the listener isn't registered.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeValidationStateListener(IValidationStateListener listener);
+
+ /**
+ * Hook method that gets called when a different change is going
+ * to be executed. Implementors of this interface should postpone
+ * informing the registered IValidationStateListner
+ * until the method changePerformed
was called.
+ *
+ * @param change the change to be executed
+ */
+ public void aboutToPerformChange(Change change);
+
+ /**
+ * Hook method that gets called when the given change has been
+ * executed. Implementors of this interface should decide on the
+ * state of the passed parameters if validation state changes recorded
+ * between the call to aboutToPeformChange
and now should be
+ * flushed or should be notified to the registered listeners. For
+ * example, if the executed change is undoable then this change is still
+ * valid and the recorded validation state changes should be flushed.
+ *
+ * @param change the change that has been executed
+ * @param undo the corresponding undo change or null
if no
+ * undo exists
+ * @param e null
if the change has been executed
+ * successfully; otherwise the catched exception
+ */
+ public void changePerformed(Change change, Change undo, Exception e);
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/IRefactoringCoreStatusCodes.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/IRefactoringCoreStatusCodes.java
new file mode 100644
index 00000000000..b99d5344ec3
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/IRefactoringCoreStatusCodes.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+/**
+ * Status codes used by the refactoring core plug-in.
+ * + * This interface is not intended to be implemented by clients. + *
+ * + * @see org.eclipse.core.runtime.Status + * + * @since 3.0 + */ +public abstract class IRefactoringCoreStatusCodes { + + private IRefactoringCoreStatusCodes() { + // no instance + } + + /** + * Status code (value 10000) indicating an internal error. + */ + public static final int INTERNAL_ERROR= 10000; + + /** + * Status code (value 10001) indicating that a bad location exception has + * occurred during change execution. + */ + public static final int BAD_LOCATION= 10001; + + /** + * Status code (value 10002) indicating that an validateEdit call has changed the + * content of a file on disk. + */ + public static final int VALIDATE_EDIT_CHANGED_CONTENT= 10002; + + /** + * Status code (value 10003) indicating that a condition checker already exists + * in a shared condition checking context. + */ + public static final int CHECKER_ALREADY_EXISTS_IN_CONTEXT= 10003; + + +} diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/IUndoManager.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/IUndoManager.java new file mode 100644 index 00000000000..7acc77444bd --- /dev/null +++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/IUndoManager.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-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; + +/** + * An undo manager keeps track of performed changes. Use the methodaddUndo
+ * to add change objects to the undo stack and performUndo
and
+ * performRedo
to undo or redo changes.
+ *
+ * This interface is not intended to be implemented or extended. Use the method
+ * IUndoManager#createUndoManager
to create a new undo manager or the method
+ * RefactoringCore#getUndoManager()
to access the refactoring undo manager.
+ *
null
+ * if no undo has been created
+ * @param e null
if the change got executed
+ * successfully; otherwise the catched exception
+ */
+ public void changePerformed(Change change, Change undo, Exception e);
+
+ /**
+ * Adds a new undo change to this undo manager.
+ *
+ * @param name the name presented on the undo stack for the provided
+ * undo change. The name must be human readable
+ * @param change the undo change
+ */
+ public void addUndo(String name, Change change);
+
+ /**
+ * Returns true
if there is anything to undo, otherwise
+ * false
.
+ *
+ * @return true
if there is anything to undo, otherwise
+ * false
+ */
+ public boolean anythingToUndo();
+
+ /**
+ * Returns the name of the top most undo.
+ *
+ * @return the top most undo name. The main purpose of the name is to
+ * render it in the UI. Returns null
if there aren't any changes to undo
+ */
+ public String peekUndoName();
+
+ /**
+ * Undo the top most undo change.
+ *
+ * @param pm a progress monitor to report progress during performing
+ * the undo change. The progress monitor must not be null
+ * @return the validation status of the undone change.
+ */
+ public RefactoringStatus performUndo(IProgressMonitor pm) throws CoreException;
+
+ /**
+ * Returns true
if there is anything to redo, otherwise
+ * false
.
+ *
+ * @return true
if there is anything to redo, otherwise
+ * false
+ */
+ public boolean anythingToRedo();
+
+ /**
+ * Returns the name of the top most redo.
+ *
+ * @return the top most redo name. The main purpose of the name is to
+ * render it in the UI. Returns null
if there are no any changes to redo.
+ */
+ public String peekRedoName();
+
+ /**
+ * Redo the top most redo change.
+ *
+ * @param pm a progress monitor to report progress during performing
+ * the redo change. The progress monitor must not be null
+ * @return the validation status of the redone change.
+ */
+ public RefactoringStatus performRedo(IProgressMonitor pm) throws CoreException;
+
+ /**
+ * Flushes the undo manager's undo and redo stacks.
+ */
+ public void flush();
+
+ /**
+ * Shut down the undo manager.
+ */
+ public void shutdown();
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/IUndoManagerListener.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/IUndoManagerListener.java
new file mode 100644
index 00000000000..6bee98f8080
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/IUndoManagerListener.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+
+/**
+ * Listener to monitor state changes of an {@link IUndoManager}.
+ *
+ * @since 3.0
+ */
+public interface IUndoManagerListener {
+
+ /**
+ * This method is called by the undo manager if an undo change has been
+ * added.
+ *
+ * @param manager the manager that has changed
+ */
+ public void undoStackChanged(IUndoManager manager);
+
+ /**
+ * This method is called by the undo manager if a redo change has been
+ * added.
+ *
+ * @param manager the manager that has changed
+ */
+ public void redoStackChanged(IUndoManager manager);
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/IValidationStateListener.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/IValidationStateListener.java
new file mode 100644
index 00000000000..9f5ac0c4892
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/IValidationStateListener.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * A listener which is notified when a change's validation state
+ * changes.
+ *
+ * @see Change#isValid(IProgressMonitor)
+ *
+ * @since 3.0
+ */
+public interface IValidationStateListener {
+
+ /**
+ * Notifies that the validation state of a change
+ * has changed.
+ *
+ * @param event event object describing the change
+ */
+ public void stateChanged(ValidationStateChangedEvent event);
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/NullChange.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/NullChange.java
new file mode 100644
index 00000000000..89af3d12d2a
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/NullChange.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-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.ltk.internal.core.refactoring.Assert;
+import org.eclipse.ltk.internal.core.refactoring.RefactoringCoreMessages;
+
+/**
+ * A refactoring change that does nothing. The reverse change of a
+ * NullChange
is a NullChange
.
+ *
+ * @since 3.0
+ */
+public class NullChange extends Change {
+
+ private String fName;
+
+ /**
+ * Creates a new NullChange
with a default name.
+ */
+ public NullChange() {
+ this(RefactoringCoreMessages.getString("NullChange.name")); //$NON-NLS-1$
+ }
+
+ /**
+ * Creates a new NullChange
with the given name.
+ *
+ * @param name the human readable name of this change
+ */
+ public NullChange(String name) {
+ Assert.isNotNull(name);
+ fName= name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ return fName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void initializeValidationData(IProgressMonitor pm) throws CoreException {
+ // do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public RefactoringStatus isValid(IProgressMonitor pm) throws CoreException {
+ return new RefactoringStatus();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Change perform(IProgressMonitor pm) throws CoreException {
+ return new NullChange();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getModifiedElement() {
+ return null;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/PerformChangeOperation.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/PerformChangeOperation.java
new file mode 100644
index 00000000000..85f0e607b1c
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/PerformChangeOperation.java
@@ -0,0 +1,229 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-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.SubProgressMonitor;
+
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.core.resources.ResourcesPlugin;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+/**
+ * Operation that, when performed, performs a change to the workbench.
+ */
+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;
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Creates a new PerformChangeOperation
for the given {@link
+ * CreateChangeOperation}. The create change operation is used to create
+ * the actual change to execute.
+ *
+ * @param op the CreateChangeOperation
used to create the
+ * actual change object
+ */
+ public PerformChangeOperation(CreateChangeOperation op) {
+ Assert.isNotNull(op);
+ fCreateChangeOperation= op;
+ }
+
+ /**
+ * Returns true
if the change execution failed.
+ *
+ * @return true
if the change execution failed;
+ * false
otherwise
+ *
+ */
+ public boolean changeExecutionFailed() {
+ return fChangeExecutionFailed;
+ }
+
+ /**
+ * Returns true
if the change has been executed. Otherwise
+ * false
is returned.
+ *
+ * @return true
if the change has been executed, otherwise
+ * false
+ */
+ public boolean changeExecuted() {
+ return fChangeExecuted;
+ }
+
+ /**
+ * Returns the status of the condition checking. Returns null
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.
+ *
+ * @return the change used by this operation or null
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 or if the change
+ * doesn't provide a undo.
+ *
+ * @return the undo change of the performed change or null
+ */
+ public Change getUndoChange() {
+ return fUndoChange;
+ }
+
+ /**
+ * Returns the refactoring status returned from the call IChange#isValid()
.
+ * Returns null
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.
+ *
+ * @param manager the undo manager to use or null
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 null
+ * if manager is unequal null
+ */
+ public void setUndoManager(IUndoManager manager, String undoName) {
+ if (manager != null) {
+ Assert.isNotNull(undoName);
+ }
+ fUndoManager= manager;
+ fUndoName= undoName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run(IProgressMonitor pm) throws CoreException {
+ try {
+ fChangeExecuted= false;
+ if (createChange()) {
+ pm.beginTask("", 2); //$NON-NLS-1$
+ pm.subTask(""); //$NON-NLS-1$
+ fCreateChangeOperation.run(new SubProgressMonitor(pm, 1));
+ fChange= fCreateChangeOperation.getChange();
+ if (fChange != null) {
+ executeChange(new SubProgressMonitor(pm, 1));
+ } else {
+ pm.worked(1);
+ }
+ } else {
+ executeChange(pm);
+ }
+ } finally {
+ pm.done();
+ }
+ }
+
+ protected void executeChange(IProgressMonitor pm) throws CoreException {
+ fChangeExecuted= false;
+ if (!fChange.isEnabled())
+ return;
+ IWorkspaceRunnable runnable= new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ monitor.beginTask("", 10); //$NON-NLS-1$
+ Exception exception= null;
+ fValidationStatus= fChange.isValid(new SubProgressMonitor(monitor, 1));
+ if (fValidationStatus.hasFatalError())
+ return;
+ try {
+ if (fUndoManager != null) {
+ ResourcesPlugin.getWorkspace().checkpoint(false);
+ fUndoManager.aboutToPerformChange(fChange);
+ }
+ fChangeExecutionFailed= true;
+ fUndoChange= fChange.perform(new SubProgressMonitor(monitor, 9));
+ fChangeExecutionFailed= false;
+ fChangeExecuted= true;
+ try {
+ fChange.dispose();
+ } finally {
+ if (fUndoChange != null && fUndoManager != null)
+ fUndoChange.initializeValidationData(new SubProgressMonitor(monitor, 1));
+ }
+ } catch (CoreException e) {
+ exception= e;
+ throw e;
+ } catch (RuntimeException e) {
+ exception= e;
+ throw e;
+ } finally {
+ try {
+ if (fUndoManager != null) {
+ ResourcesPlugin.getWorkspace().checkpoint(false);
+ fUndoManager.changePerformed(fChange, fUndoChange, exception);
+ if (fUndoChange != null) {
+ fUndoManager.addUndo(fUndoName, fUndoChange);
+ } else {
+ fUndoManager.flush();
+ }
+ }
+ } catch (RuntimeException e) {
+ fUndoManager.flush();
+ throw e;
+ }
+ monitor.done();
+ }
+ }
+ };
+ ResourcesPlugin.getWorkspace().run(runnable, pm);
+ }
+
+ private boolean createChange() {
+ return fCreateChangeOperation != null;
+ }
+}
+
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/PerformRefactoringOperation.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/PerformRefactoringOperation.java
new file mode 100644
index 00000000000..2cb3cdd3354
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/PerformRefactoringOperation.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-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.SubProgressMonitor;
+
+import org.eclipse.core.resources.IWorkspaceRunnable;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+/**
+ * Creates a new operation to perform a refactoring.
+ *
+ * The undo change isn't initialized.
+ *
+ * @since 3.0
+ */
+public class PerformRefactoringOperation implements IWorkspaceRunnable {
+
+ private int fStyle;
+ private Refactoring fRefactoring;
+
+ private RefactoringStatus fPreconditionStatus;
+ private RefactoringStatus fValidationStatus;
+ private Change fUndo;
+
+ /**
+ *
+ * @param refactoring
+ * @param style either ACTIVATION, INPUT or PRECONDITIONS.
+ */
+ public PerformRefactoringOperation(Refactoring refactoring, int style) {
+ Assert.isNotNull(refactoring);
+ fRefactoring= refactoring;
+ fStyle= style;
+ }
+
+ public RefactoringStatus getConditionStatus() {
+ return fPreconditionStatus;
+ }
+
+ public RefactoringStatus getValidationStatus() {
+ return fValidationStatus;
+ }
+
+ public Change getUndoChange() {
+ return fUndo;
+ }
+
+ public void run(IProgressMonitor monitor) throws CoreException {
+ monitor.beginTask("", 10); //$NON-NLS-1$
+ CreateChangeOperation create= new CreateChangeOperation(
+ new CheckConditionsOperation(fRefactoring, fStyle),
+ RefactoringStatus.ERROR);
+ create.run(new SubProgressMonitor(monitor, 6));
+ fPreconditionStatus= create.getConditionCheckingStatus();
+ if (fPreconditionStatus.hasFatalError()) {
+ monitor.done();
+ return;
+ }
+ Change change= create.getChange();
+ PerformChangeOperation perform= new PerformChangeOperation(change);
+ perform.setUndoManager(RefactoringCore.getUndoManager(), fRefactoring.getName());
+ perform.run(new SubProgressMonitor(monitor, 2));
+ fValidationStatus= perform.getValidationStatus();
+ fUndo= perform.getUndoChange();
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/Refactoring.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/Refactoring.java
new file mode 100644
index 00000000000..5efc0573bd4
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/Refactoring.java
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-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.PlatformObject;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+/**
+ * Abstract super class for all refactorings.
+ * + * The life cycle of a refactoring is as follows: + *
null
+ */
+ public abstract String getName();
+
+ //---- Conditions ------------------------------------------------------------
+
+ /**
+ * Checks all conditions. This implementation calls checkInitialConditions
+ * and checkFinalConditions
.
+ * + * Subclasses may extend this method to provide additional condition checks. + *
+ * + * @see #checkInitialConditions(IProgressMonitor) + * @see #checkFinalConditions(IProgressMonitor) + */ + public RefactoringStatus checkAllConditions(IProgressMonitor pm) throws CoreException { + pm.beginTask("", 11); //$NON-NLS-1$ + RefactoringStatus result= new RefactoringStatus(); + result.merge(checkInitialConditions(new SubProgressMonitor(pm, 1))); + if (!result.hasFatalError()) + result.merge(checkFinalConditions(new SubProgressMonitor(pm, 10))); + 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 a initial checks after an + * action has been executed. + *
+ * The refactoring is considered as not being executable if the returned status
+ * has the severity RefactoringStatus#FATAL
.
+ *
+ *
+ * @param pm a progress monitor to report progress. Although availability 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 RefactoringStatus#FATAL
+ * the refactoring is considered as not being executable.
+ *
+ * @throws CoreException if an exception occurred during initial condition checking
+ *
+ * @see #checkFinalConditions(IProgressMonitor)
+ * @see RefactoringStatus#FATAL
+ */
+ public abstract RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException;
+
+ /**
+ * After checkInitialConditions
has been performed and the user has
+ * provided all input necessary to perform the refactoring this method is called
+ * to check the remaining preconditions.
+ *
+ * The refactoring is considered as not being executable if the returned status
+ * has the severity RefactoringStatus#FATAL
.
+ *
+ *
+ * @param pm a progress monitor to report progress. Although availability 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 RefactoringStatus#FATAL
+ * the refactoring is considered as not being executable.
+ *
+ * @throws CoreException if an exception occurred during final condition checking
+ *
+ * @see #checkInitialConditions(IProgressMonitor)
+ * @see RefactoringStatus#FATAL
+ */
+ public abstract RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException;
+
+ //---- change creation ------------------------------------------------------
+
+ /**
+ * Creates a {@link Change} object that performs the actual refactoring.
+ *
+ * @param pm a progress monitor to report progress
+ *
+ * @return the change representing the work space modifications of the
+ * refactoring
+ *
+ * @throws CoreException if an error occurred while creating the change
+ */
+ public abstract Change createChange(IProgressMonitor pm) throws CoreException;
+
+ /**
+ * Returns the scheduling rule associated with this refactoring element.
+ * This scheduling rule should be used whenever one of the refactoring's
+ * method is executed inside a {@linkplain org.eclipse.core.resources.IWorkspaceRunnable
+ * work space runnable} or when the change created by this refactoring is
+ * performed.
+ *
+ * @return the scheduling rule associated with this refactoring
+ */
+ /* public abstract ISchedulingRule getSchedulingRule(); */
+
+ /**
+ * {@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();
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringCore.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringCore.java
new file mode 100644
index 00000000000..f2494b5e7fd
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringCore.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+import org.eclipse.ltk.internal.core.refactoring.UndoManager;
+
+/**
+ * Central access point to access resources managed by the refactoring
+ * core plug-in.
+ *
+ * @since 3.0
+ */
+public class RefactoringCore {
+
+ private static IUndoManager fgUndoManager= null;
+
+ /**
+ * Creates a new empty undo manager.
+ *
+ * @return a new undo manager
+ */
+ public static IUndoManager createUndoManager() {
+ return new UndoManager();
+ }
+
+ /**
+ * Returns the singleton undo manager for the refactoring undo
+ * stack.
+ *
+ * @return the refactoring undo manager.
+ */
+ public static IUndoManager getUndoManager() {
+ if (fgUndoManager == null)
+ fgUndoManager= createUndoManager();
+ return fgUndoManager;
+ }
+
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringStatus.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringStatus.java
new file mode 100644
index 00000000000..b70874ca190
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringStatus.java
@@ -0,0 +1,644 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+/**
+ * A RefactoringStatus
object represents the outcome of a
+ * precondition checking operation. It manages a list of
+ * RefactoringStatusEntry
objects. Each RefactoringStatusEntry
+ *
object describes one particilar problem detected during
+ * precondition checking.
+ *
+ * Additionally a problem severityis managed. Severities are ordered as follows:
+ * OK
< INFO
< WARNING
<
+ * ERROR
. The status's problem severity is the maximum of the severities
+ * of all entries. If the status doesn't have any entry the status's severity
+ * is OK
.
+ *
+ * Note: this class is not intented to be subclassed by clients. + *
+ * + * @see RefactoringStatusEntry + * @see Refactoring#checkAllConditions(IProgressMonitor) + * + * @since 3.0 + */ +public class RefactoringStatus { + + /** + * Status severity constant (value 0) indicating this status represents the nominal case. + * @see #getSeverity + * @see #isOK + */ + public static final int OK= 0; + + /** + * Status severity constant (value 1) indicating this status is informational only. + * @see #getSeverity + */ + public static final int INFO= 1; + + /** + * Status severity constant (value 2) indicating this status represents a warning. + * This is used when the refactoring might cause confusion such as unintended overloading. + * @see #getSeverity + */ + public static final int WARNING= 2; + + /** + * Status severity constant (value 3) indicating this status represents an error. + * This is used when the refactoring will introduce compilation errors if executed. + * @see #getSeverity + */ + public static final int ERROR= 3; + + /** + * Status severity constant (value 4) indicating this status represents a fatal error. + * This is used when the refactoring can't be executed. + * @see #getSeverity + */ + public static final int FATAL= 4; + + /** + * List of refactoring status entries. + */ + private List fEntries; + + /** + * The status's severity. The following invariant holds for + *fSeverity
: OK
≤ fSeverity ≤
+ * FATAL
.
+ */
+ private int fSeverity= OK;
+
+ /**
+ * Creates a new refactoring status with an empty list of
+ * status entries and a severity of OK
.
+ */
+ public RefactoringStatus() {
+ fEntries= new ArrayList(0);
+ }
+
+ /**
+ * Returns the severity.
+ *
+ * @return the severity.
+ */
+ public int getSeverity() {
+ return fSeverity;
+ }
+
+ /**
+ * Returns the list of refactoring status entries.
+ *
+ * @return the list of refactoring status entries. Returns an empty array
+ * if not entries are managed.
+ */
+ public RefactoringStatusEntry[] getEntries() {
+ return (RefactoringStatusEntry[])fEntries.toArray(new RefactoringStatusEntry[fEntries.size()]);
+ }
+
+ /**
+ * Returns whether the status has entries or not.
+ *
+ * @return true
if the status as any entries; otherwise
+ * false
is returned.
+ */
+ public boolean hasEntries() {
+ return !fEntries.isEmpty();
+ }
+
+ /**
+ * Returns the RefactoringStatusEntry
at the specified index.
+ *
+ * @param index the indes of the entry to return
+ * @return the enrty at the specified index
+ *
+ * @throws IndexOutOfBoundsException if the index is out of range
+ */
+ public RefactoringStatusEntry getEntryAt(int index) {
+ return (RefactoringStatusEntry)fEntries.get(index);
+ }
+
+ /**
+ * Returns the first entry managed by this refactoring status that
+ * matches the given plug-in identifier and code. If more than one
+ * entry exists that matches the criteria the first one in the list
+ * of entries is returned. Returns null
if no entry
+ * matches.
+ *
+ * @param pluginId the entry's plug-in identifier
+ * @param code the entry's code
+ * @return the entry that matches the given plug-in identifier and
+ * code; null
otherwise
+ */
+ public RefactoringStatusEntry getEntryMatchingCode(String pluginId, int code) {
+ Assert.isTrue(pluginId != null);
+ for (Iterator iter= fEntries.iterator(); iter.hasNext(); ) {
+ RefactoringStatusEntry entry= (RefactoringStatusEntry)iter.next();
+ if (pluginId.equals(entry.getPluginId()) && entry.getCode() == code)
+ return entry;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the first entry which severity is equal or greater than the
+ * given severity. If more than one entry exists that matches the
+ * criteria the first one is returned. Returns null
if no
+ * entry matches.
+ *
+ * @param severity the severity to search for. Must be one of FATAL
+ *
, ERROR
, WARNING
or INFO
+ * @return the entry that matches the search criteria
+ */
+ public RefactoringStatusEntry getEntryMatchingSeverity(int severity) {
+ Assert.isTrue(severity >= OK && severity <= FATAL);
+ if (severity > fSeverity)
+ return null;
+ Iterator iter= fEntries.iterator();
+ while (iter.hasNext()) {
+ RefactoringStatusEntry entry= (RefactoringStatusEntry)iter.next();
+ if (entry.getSeverity() >= severity)
+ return entry;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the first message which severity is equal or greater than the
+ * given severity. If more than one entry exists that matches the criteria
+ * the first one is returned. Returns null
if no entry matches.
+ *
+ * @param severity the severity to search for. Must be one of FATAL
+ *
, ERROR
, WARNING
or INFO
+ * @return the message of the entry that matches the search criteria
+ */
+ public String getMessageMatchingSeverity(int severity) {
+ RefactoringStatusEntry entry= getEntryMatchingSeverity(severity);
+ if (entry == null)
+ return null;
+ return entry.getMessage();
+ }
+
+ /**
+ * Creates a new RefactoringStatus
with one entry filled with the given
+ * arguments.
+ *
+ * @param severity the severity
+ * @param msg the message
+ * @param context the context. Can be null
+ * @param pluginId the plug-in identifier. Can be null
if argument
+ * code
equals NO_CODE
+ * @param code the problem code. Must be either NO_CODE
or equals or greater
+ * than zero
+ * @param data application specific data
+ *
+ * @see RefactoringStatusEntry
+ */
+ public static RefactoringStatus createStatus(int severity, String msg, RefactoringStatusContext context, String pluginId, int code, Object data) {
+ RefactoringStatus result= new RefactoringStatus();
+ result.fEntries.add(new RefactoringStatusEntry(severity, msg, context, pluginId, code, data));
+ result.fSeverity= severity;
+ return result;
+ }
+
+ /**
+ * Creates a new RefactorngStatus
with one INFO
entry
+ * filled with the given message.
+ *
+ * @param msg the message of the info entry
+ * @return the refactoring status
+ *
+ * @see RefactoringStatusEntry
+ */
+ public static RefactoringStatus createInfoStatus(String msg) {
+ return createStatus(INFO, msg, null, null, RefactoringStatusEntry.NO_CODE, null);
+ }
+
+ /**
+ * Creates a new RefactorngStatus
with one INFO
entry
+ * filled with the given message and context.
+ *
+ * @param msg the message of the info entry
+ * @param context the context of the info entry
+ * @return the refactoring status
+ *
+ * @see RefactoringStatusEntry
+ */
+ public static RefactoringStatus createInfoStatus(String msg, RefactoringStatusContext context) {
+ return createStatus(INFO, msg, context, null, RefactoringStatusEntry.NO_CODE, null);
+ }
+
+ /**
+ * Creates a new RefactorngStatus
with one WARNING
entry
+ * filled with the given message.
+ *
+ * @param msg the message of the warning entry
+ * @return the refactoring status
+ *
+ * @see RefactoringStatusEntry
+ */
+ public static RefactoringStatus createWarningStatus(String msg) {
+ return createStatus(WARNING, msg, null, null, RefactoringStatusEntry.NO_CODE, null);
+ }
+
+ /**
+ * Creates a RefactorngStatus
with one WARNING
entry
+ * fill with the given message and context.
+ *
+ * @param msg the message of the warning entry
+ * @param context the context of the warning entry
+ * @return the refactoring status
+ *
+ * @see RefactoringStatusEntry
+ */
+ public static RefactoringStatus createWarningStatus(String msg, RefactoringStatusContext context) {
+ return createStatus(WARNING, msg, context, null, RefactoringStatusEntry.NO_CODE, null);
+ }
+
+ /**
+ * Creates a new RefactorngStatus
with one ERROR
entry
+ * filled with the given message.
+ *
+ * @param msg the message of the error entry
+ * @return the refactoring status
+ *
+ * @see RefactoringStatusEntry
+ */
+ public static RefactoringStatus createErrorStatus(String msg) {
+ return createStatus(ERROR, msg, null, null, RefactoringStatusEntry.NO_CODE, null);
+ }
+
+ /**
+ * Creates a RefactorngStatus
with one ERROR
entry
+ * fill with the given message and context.
+ *
+ * @param msg the message of the error entry
+ * @param context the context of the error entry
+ * @return the refactoring status
+ *
+ * @see RefactoringStatusEntry
+ */
+ public static RefactoringStatus createErrorStatus(String msg, RefactoringStatusContext context) {
+ return createStatus(ERROR, msg, context, null, RefactoringStatusEntry.NO_CODE, null);
+ }
+
+ /**
+ * Creates a new RefactorngStatus
with one FATAL
entry
+ * filled with the given message.
+ *
+ * @param msg the message of the fatal entry
+ * @return the refactoring status
+ *
+ * @see RefactoringStatusEntry
+ */
+ public static RefactoringStatus createFatalErrorStatus(String msg) {
+ return createStatus(FATAL, msg, null, null, RefactoringStatusEntry.NO_CODE, null);
+ }
+
+ /**
+ * Creates a RefactorngStatus
with one FATAL
entry
+ * fill with the given message and context.
+ *
+ * @param msg the message of the fatal entry
+ * @param context the context of the fatal entry
+ * @return the refactoring status
+ *
+ * @see RefactoringStatusEntry
+ */
+ public static RefactoringStatus createFatalErrorStatus(String msg, RefactoringStatusContext context) {
+ return createStatus(FATAL, msg, context, null, RefactoringStatusEntry.NO_CODE, null);
+ }
+
+ /**
+ * Creates a new RefactorngStatus
from the given IStatus
. An
+ * OK status is mapped to an OK refactoring status, an information status is mapped
+ * to a warning refactoring status, a warning status is mapped to an error refactoring
+ * status and an error status is mapped to a fatal refactoring status. If the status
+ * is a MultiStatus
the first level of children of the status will be added
+ * as refactoring status entries to the created refactoring status.
+ *
+ * @param status the status to create a refactoring status from
+ * @return the refactoring status
+ *
+ * @see IStatus
+ */
+ public static RefactoringStatus create(IStatus status) {
+ if (status.isOK())
+ return new RefactoringStatus();
+
+ if (!status.isMultiStatus()) {
+ switch (status.getSeverity()) {
+ case IStatus.INFO :
+ return RefactoringStatus.createWarningStatus(status.getMessage());
+ case IStatus.WARNING :
+ return RefactoringStatus.createErrorStatus(status.getMessage());
+ case IStatus.ERROR :
+ return RefactoringStatus.createFatalErrorStatus(status.getMessage());
+ default :
+ return new RefactoringStatus();
+ }
+ } else {
+ IStatus[] children= status.getChildren();
+ RefactoringStatus result= new RefactoringStatus();
+ for (int i= 0; i < children.length; i++) {
+ result.merge(RefactoringStatus.create(children[i]));
+ }
+ return result;
+ }
+ }
+
+ /**
+ * Merges the receiver and the parameter statuses. The resulting list of
+ * entries in the receiver will contain entries from both. The resuling
+ * severity in the reciver will be the more severe of its current severity
+ * and the parameter's severity. Merging with null
is
+ * allowed - it has no effect.
+ *
+ * @param other the refactoring status to merge with
+ *
+ * @see #getSeverity
+ */
+ public void merge(RefactoringStatus other) {
+ if (other == null)
+ return;
+ fEntries.addAll(other.fEntries);
+ fSeverity= Math.max(fSeverity, other.getSeverity());
+ }
+
+ /**
+ * Adds an INFO
entry filled with the given message to this status.
+ * If the current severity is OK
it will be changed to INFO
+ *
. It will remain unchanged otherwise.
+ *
+ * @param msg the message of the info entry
+ *
+ * @see RefactoringStatusEntry
+ */
+ public void addInfo(String msg) {
+ addInfo(msg, null);
+ }
+
+ /**
+ * Adds an INFO
entry filled with the given message and context to
+ * this status. If the current severity is OK
it will be changed to
+ * INFO
. It will remain unchanged otherwise.
+ *
+ * @param msg the message of the info entry
+ * @param context the context of the info entry
+ *
+ * @see RefactoringStatusEntry
+ */
+ public void addInfo(String msg, RefactoringStatusContext context) {
+ fEntries.add(new RefactoringStatusEntry(RefactoringStatus.INFO, msg, context));
+ fSeverity= Math.max(fSeverity, INFO);
+ }
+
+ /**
+ * Adds a WARNING
entry filled with the given message to this status.
+ * If the current severity is OK
or INFO
it will be
+ * changed to WARNING
. It will remain unchanged otherwise.
+ *
+ * @param msg the message of the warning entry
+ *
+ * @see RefactoringStatusEntry
+ */
+ public void addWarning(String msg) {
+ addWarning(msg, null);
+ }
+
+ /**
+ * Adds a WARNING
entry filled with the given message and context to
+ * this status. If the current severity is OK
or INFO
it
+ * will be changed to WARNING
. It will remain unchanged otherwise.
+ *
+ * @param msg the message of the warning entry
+ * @param context the context of the warning entry
+ *
+ * @see RefactoringStatusEntry
+ */
+ public void addWarning(String msg, RefactoringStatusContext context) {
+ fEntries.add(new RefactoringStatusEntry(RefactoringStatus.WARNING, msg, context));
+ fSeverity= Math.max(fSeverity, WARNING);
+ }
+
+ /**
+ * Adds an ERROR
entry filled with the given message to this status.
+ * If the current severity is OK
, INFO
or WARNING
+ *
it will be changed to ERROR
. It will remain unchanged
+ * otherwise.
+ *
+ * @param msg the message of the error entry
+ *
+ * @see RefactoringStatusEntry
+ */
+ public void addError(String msg) {
+ addError(msg, null);
+ }
+
+ /**
+ * Adds an ERROR
entry filled with the given message and context to
+ * this status. If the current severity is OK
, INFO
or
+ * WARNING
it will be changed to ERROR
. It will remain
+ * unchanged otherwise.
+ *
+ * @param msg the message of the error entry
+ * @param context the context of the error entry
+ *
+ * @see RefactoringStatusEntry
+ */
+ public void addError(String msg, RefactoringStatusContext context) {
+ fEntries.add(new RefactoringStatusEntry(RefactoringStatus.ERROR, msg, context));
+ fSeverity= Math.max(fSeverity, ERROR);
+ }
+
+ /**
+ * Adds a FATAL
entry filled with the given message to this status.
+ * The severity of this status will changed to FATAL
.
+ *
+ * @param msg the message of the fatal entry
+ *
+ * @see RefactoringStatusEntry
+ */
+ public void addFatalError(String msg) {
+ addFatalError(msg, null);
+ }
+
+ /**
+ * Adds a FATAL
entry filled with the given message and status to
+ * this status. The severity of this status will changed to FATAL
.
+ *
+ * @param msg the message of the fatal entry
+ * @param context the context of the fatal entry
+ *
+ * @see RefactoringStatusEntry
+ */
+ public void addFatalError(String msg, RefactoringStatusContext context) {
+ fEntries.add(new RefactoringStatusEntry(RefactoringStatus.FATAL, msg, context));
+ fSeverity= Math.max(fSeverity, FATAL);
+ }
+
+ /**
+ * Adds a new entry filled with the given arguments to this status. The severity
+ * of this status is set to the maximum of fSeverity
and
+ * severity
.
+ *
+ * @param severity the severity of the entry
+ * @param msg the message of the entry
+ * @param context the context of the entry. Can be null
+ * @param pluginId the plug-in identifier of the entry. Can be null
if
+ * argument code
equals NO_CODE
+ * @param code the problem code of the entry. Must be either NO_CODE
+ * or equals or greater than zero
+ */
+ public void addEntry(int severity, String msg, RefactoringStatusContext context, String pluginId, int code) {
+ fEntries.add(new RefactoringStatusEntry(severity, msg, context, pluginId, code));
+ fSeverity= Math.max(fSeverity, severity);
+ }
+
+ /**
+ * Adds a new entry filled with the given arguments to this status. The severity
+ * of this status is set to the maximum of fSeverity
and
+ * severity
.
+ *
+ * @param severity the severity of the entry
+ * @param msg the message of the entry
+ * @param context the context of the entry. Can be null
+ * @param pluginId the plug-in identifier of the entry. Can be null
if
+ * argument code
equals NO_CODE
+ * @param code the problem code of the entry. Must be either NO_CODE
+ * or equals or greater than zero
+ * @param data application specific data of the entry
+ */
+ public void addEntry(int severity, String msg, RefactoringStatusContext context, String pluginId, int code, Object data) {
+ fEntries.add(new RefactoringStatusEntry(severity, msg, context, pluginId, code, data));
+ fSeverity= Math.max(fSeverity, severity);
+ }
+
+ /**
+ * Adds the given RefactoringStatusEntry
. The severity of this
+ * status is set to the maximum of fSeverity
and the severity of
+ * the entry.
+ *
+ * @param entry the RefactoringStatusEntry
to be added
+ */
+ public void addEntry(RefactoringStatusEntry entry) {
+ Assert.isNotNull(entry);
+ fEntries.add(entry);
+ fSeverity= Math.max(fSeverity, entry.getSeverity());
+ }
+
+ /**
+ * Returns whether the status's severity is OK
or not.
+ *
+ * @return true
if the severity is OK
;
+ * otherwise false
is returned
+ */
+ public boolean isOK() {
+ return fSeverity == OK;
+ }
+
+ /**
+ * Returns true
if the current severity is
+ * FATAL
.
+ *
+ * @return true
if the current severity is
+ * FATAL
; otherwise false
is returned
+ */
+ public boolean hasFatalError() {
+ return fSeverity == FATAL;
+ }
+
+ /**
+ * Returns true
if the current severity is
+ * FATAL
or ERROR
.
+ *
+ * @return true
if the current severity is
+ * FATAL
or ERROR
; otherwise false
+ *
is returned
+ */
+ public boolean hasError() {
+ return fSeverity == FATAL || fSeverity == ERROR;
+ }
+
+ /**
+ * Returns true
if the current severity is
+ * FATAL
, ERROR
or WARNING
.
+ *
+ * @return true
if the current severity is
+ * FATAL
, ERROR
or WARNING
;
+ * otherwise false
is returned
+ */
+ public boolean hasWarning() {
+ return fSeverity == FATAL || fSeverity == ERROR || fSeverity == WARNING;
+ }
+
+ /**
+ * Returns true
if the current severity is
+ * FATAL
, ERROR
, WARNING
or
+ * INFO
.
+ *
+ * @return true
if the current severity is
+ * FATAL
, ERROR
, WARNING
or
+ * INFO
; otherwise false
is returned
+ */
+ public boolean hasInfo() {
+ return fSeverity == FATAL || fSeverity == ERROR || fSeverity == WARNING || fSeverity == INFO;
+ }
+
+ /*
+ * (non java-doc)
+ * for debugging only
+ */
+ public String toString() {
+ StringBuffer buff= new StringBuffer();
+ buff.append("<") //$NON-NLS-1$
+ .append(getSeverityString(fSeverity)).append("\n"); //$NON-NLS-1$
+ if (!isOK()) {
+ for (Iterator iter= fEntries.iterator(); iter.hasNext(); ) {
+ buff.append("\t") //$NON-NLS-1$
+ .append(iter.next()).append("\n"); //$NON-NLS-1$
+ }
+ }
+ buff.append(">"); //$NON-NLS-1$
+ return buff.toString();
+ }
+
+ /*
+ * non java-doc
+ * for debugging only not for nls
+ */
+ /* package */static String getSeverityString(int severity) {
+ Assert.isTrue(severity >= OK && severity <= FATAL);
+ if (severity == RefactoringStatus.OK)
+ return "OK"; //$NON-NLS-1$
+ if (severity == RefactoringStatus.INFO)
+ return "INFO"; //$NON-NLS-1$
+ if (severity == RefactoringStatus.WARNING)
+ return "WARNING"; //$NON-NLS-1$
+ if (severity == RefactoringStatus.ERROR)
+ return "ERROR"; //$NON-NLS-1$
+ if (severity == RefactoringStatus.FATAL)
+ return "FATALERROR"; //$NON-NLS-1$
+ return null;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringStatusContext.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringStatusContext.java
new file mode 100644
index 00000000000..cb69ecc69b7
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringStatusContext.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+/**
+ * A RefactoringStatusContext can be used to annotate a
+ * {@link RefactoringStatusEntry} with additional information
+ * typically presented in the UI.
+ *
+ * @since 3.0
+ */
+public abstract class RefactoringStatusContext {
+ /**
+ * Returns the element that corresponds directly to this context,
+ * or null
if there is no corresponding element.
+ *
+ * For example, the corresponding element of a context for a problem
+ * detected in an IResource
would the the resource itself.
+ *
+ *
+ * @return the corresponding element
+ */
+ public abstract Object getCorrespondingElement();
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringStatusEntry.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringStatusEntry.java
new file mode 100644
index 00000000000..2905621061a
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringStatusEntry.java
@@ -0,0 +1,234 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+/**
+ * An immutable object representing an entry in the list in RefactoringStatus
.
+ * A refactoring status entry consists of a severity, a message, a problem code
+ * (represented by a tuple(plug-in identifier and code number)), a context object and a
+ * generic data pointer. The context object is used to provide context information for
+ * the problem itself. An example context is a tuple consisting of the resource that contains
+ * the problem and a corresponding line number.
+ *
+ * Note: this class is not intented to be subclassed by clients.
+ *
+ *
+ * @since 3.0
+ */
+public class RefactoringStatusEntry {
+
+ /**
+ * A special problem code indicating that no problem code is provided. If
+ * NO_CODE
is used then the plug-in identifier can be
+ * null
+ */
+ public static final int NO_CODE= -1;
+
+ /** The severity */
+ private final int fSeverity;
+
+ /** The message */
+ private final String fMessage;
+
+ /** A plug-in specific problem code */
+ private final int fCode;
+
+ /** A plug-in identifier to make the problem code unique */
+ private final String fPluginId;
+
+ /** A context providing detailed information of where the problem occurred */
+ private final RefactoringStatusContext fContext;
+
+ /** A generic data pointer */
+ private final Object fData;
+
+ /**
+ * Creates a new refactoring status entry. The context is set to
+ * null
the problem code is set to NO_CODE
, the
+ * plug-in identifier is set to null
and the data pointer
+ * is set to null
as well.
+ *
+ * @param severity the severity
+ * @param msg the message
+ */
+ public RefactoringStatusEntry(int severity, String msg) {
+ this(severity, msg, null);
+ }
+
+ /**
+ * Creates a new refactoring status entry. The problem code is set to
+ * NO_CODE
, the plug-in identifier is set to null
and
+ * the data pointer is set to null
as well.
+ *
+ * @param severity the severity
+ * @param msg the message
+ * @param context the context. Can be null
+ */
+ public RefactoringStatusEntry(int severity, String msg, RefactoringStatusContext context) {
+ this(severity, msg, context, null, NO_CODE, null);
+ }
+
+ /**
+ * Creates a new refactoring status entry.
+ *
+ * @param severity the severity
+ * @param msg the message
+ * @param context the context. Can be null
+ * @param pluginId the plug-in identifier. Can be null
if argument
+ * code
equals NO_CODE
+ * @param code the problem code. Must be either NO_CODE
or equals or greater
+ * than zero
+ */
+ public RefactoringStatusEntry(int severity, String msg, RefactoringStatusContext context, String pluginId, int code) {
+ this(severity, msg, context, pluginId, code, null);
+ }
+
+ /**
+ * Creates a new refactoring status entry.
+ *
+ * @param severity the severity
+ * @param msg the message
+ * @param context the context. Can be null
+ * @param pluginId the plug-in identifier. Can be null
if argument
+ * code
equals NO_CODE
+ * @param code the problem code. Must be either NO_CODE
or equals or greater
+ * than zero
+ * @param data application specific data
+ */
+ public RefactoringStatusEntry(int severity, String msg, RefactoringStatusContext context, String pluginId, int code, Object data) {
+ Assert.isTrue(severity == RefactoringStatus.INFO || severity == RefactoringStatus.WARNING
+ || severity == RefactoringStatus.ERROR || severity == RefactoringStatus.FATAL);
+ Assert.isNotNull(msg);
+ Assert.isTrue(code == NO_CODE || code >= 0);
+ if (code != NO_CODE) Assert.isTrue(pluginId != null);
+ fMessage= msg;
+ fSeverity= severity;
+ fContext= context;
+ fPluginId= pluginId;
+ fCode= code;
+ fData= data;
+ }
+
+ /**
+ * Returns the message of the status entry.
+ *
+ * @return the message
+ */
+ public String getMessage() {
+ return fMessage;
+ }
+
+ /**
+ * Returns the severity level.
+ *
+ * @return the severity level
+ *
+ * @see RefactoringStatus#INFO
+ * @see RefactoringStatus#WARNING
+ * @see RefactoringStatus#ERROR
+ * @see RefactoringStatus#FATAL
+ */
+ public int getSeverity() {
+ return fSeverity;
+ }
+
+ /**
+ * Returns the context which can be used to show more detailed information regarding
+ * this status entry in the UI. The method may return null
indicating
+ * that no context is available.
+ *
+ * @return the status entry's context
+ */
+ public RefactoringStatusContext getContext() {
+ return fContext;
+ }
+
+ /**
+ * Returns the plug-in identifier associated with the
+ * problem code. Might return null
if the
+ * problem code equals NO_CODE
.
+ *
+ * @return the plug-in identifier
+ */
+ public String getPluginId() {
+ return fPluginId;
+ }
+
+ /**
+ * Returns the problem code.
+ *
+ * @return the problem code
+ */
+ public int getCode() {
+ return fCode;
+ }
+
+ /**
+ * Returns the application defined entry data associated
+ * with the receiver, or null
if it has not
+ * been set.
+ *
+ * @return the entry data
+ */
+ public Object getData() {
+ return fData;
+ }
+
+ /**
+ * Returns whether the entry represents a fatal error or not.
+ *
+ * @return true
iff (severity ==RefactoringStatus.FATAL
)
+ */
+ public boolean isFatalError() {
+ return fSeverity == RefactoringStatus.FATAL;
+ }
+
+ /**
+ * Returns whether the entry represents an error or not.
+ *
+ * @return true
iff (severity ==RefactoringStatus.ERROR
).
+ */
+ public boolean isError() {
+ return fSeverity == RefactoringStatus.ERROR;
+ }
+
+ /**
+ * Returns whether the entry represents a warning or not.
+ *
+ * @return true
iff (severity ==RefactoringStatus.WARNING
).
+ */
+ public boolean isWarning() {
+ return fSeverity == RefactoringStatus.WARNING;
+ }
+
+ /**
+ * Returns whether the entry represents an information or not.
+ *
+ * @return true
iff (severity ==RefactoringStatus.INFO
).
+ */
+ public boolean isInfo() {
+ return fSeverity == RefactoringStatus.INFO;
+ }
+
+ /*
+ * non java-doc for debugging only
+ */
+ public String toString() {
+ String contextString= fContext == null ? "" : fContext.toString(); //$NON-NLS-1$
+ return "\n" //$NON-NLS-1$
+ + RefactoringStatus.getSeverityString(fSeverity) + ": " + fMessage + //$NON-NLS-1$
+ "\nContext: " + contextString + //$NON-NLS-1$
+ (fCode == NO_CODE ? "\ncode: none" : "\nplug-in id: " + fPluginId + "code: " + fCode) + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ "\nData: " + fData; //$NON-NLS-1$
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/TextChange.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/TextChange.java
new file mode 100644
index 00000000000..d0dbf30d5e2
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/TextChange.java
@@ -0,0 +1,695 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.text.edits.MultiTextEdit;
+import org.eclipse.text.edits.TextEdit;
+import org.eclipse.text.edits.TextEditCopier;
+import org.eclipse.text.edits.TextEditGroup;
+import org.eclipse.text.edits.TextEditProcessor;
+import org.eclipse.text.edits.UndoEdit;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.Region;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+import org.eclipse.ltk.internal.core.refactoring.Changes;
+
+/**
+ * A text change is a special change object that applies a {@link TextEdit
+ * text edit tree} to a document. The text change manages the text edit tree.
+ * Access to the document must be provided by concrete subclasses via the method
+ * {@link #aquireDocument(IProgressMonitor) aquireDocument}, {@link
+ * #commitDocument(IDocument document, IProgressMonitor pm) commitDocument}, and
+ * {@link #releaseDocument(IDocument, IProgressMonitor) releaseDocument}.
+ *
+ * A text change offers the ability to access the original content of
+ * the document as well as creating a preview of the change. The edit
+ * tree gets copied when creating any king of preview. Therefore no region
+ * updating on the original edit tree takes place when requesting a preview
+ * (for more information on region updating see class {@link TextEdit TextEdit}.
+ * If region tracking is required for a preview it can be enabled via a call
+ * to the method {@link #setKeepPreviewEdits(boolean) setKeepPreviewEdits}.
+ * If enabled the text change keeps the copied edit tree executed for the
+ * preview allowing clients to map an original edit to an executed edit. The
+ * executed edit can then be used to determine its position in the preview.
+ *
+ *
+ * @since 3.0
+ */
+public abstract class TextChange extends Change {
+
+ private static class LocalTextEditProcessor extends TextEditProcessor {
+ public static final int EXCLUDE= 1;
+ public static final int INCLUDE= 2;
+
+ private TextEdit[] fExcludes;
+ private TextEdit[] fIncludes;
+
+ public LocalTextEditProcessor(IDocument document, TextEdit root, int flags) {
+ super(document, root, flags);
+ }
+ public void setIncludes(TextEdit[] includes) {
+ Assert.isNotNull(includes);
+ Assert.isTrue(fExcludes == null);
+ fIncludes= flatten(includes);
+ }
+ public void setExcludes(TextEdit[] excludes) {
+ Assert.isNotNull(excludes);
+ Assert.isTrue(fIncludes == null);
+ fExcludes= excludes;
+ }
+ protected boolean considerEdit(TextEdit edit) {
+ if (fExcludes != null) {
+ for (int i= 0; i < fExcludes.length; i++) {
+ if (edit.equals(fExcludes[i]))
+ return false;
+ }
+ return true;
+ }
+ if (fIncludes != null) {
+ for (int i= 0; i < fIncludes.length; i++) {
+ if (edit.equals(fIncludes[i]))
+ return true;
+ }
+ return false;
+ }
+ return true;
+ }
+ private TextEdit[] flatten(TextEdit[] edits) {
+ List result= new ArrayList(5);
+ for (int i= 0; i < edits.length; i++) {
+ flatten(result, edits[i]);
+ }
+ return (TextEdit[])result.toArray(new TextEdit[result.size()]);
+ }
+ private void flatten(List result, TextEdit edit) {
+ result.add(edit);
+ TextEdit[] children= edit.getChildren();
+ for (int i= 0; i < children.length; i++) {
+ flatten(result, children[i]);
+ }
+ }
+ }
+
+ private static class PreviewAndRegion {
+ public PreviewAndRegion(IDocument d, IRegion r) {
+ document= d;
+ region= r;
+ }
+ public IDocument document;
+ public IRegion region;
+ }
+
+ private String fName;
+ private List fTextEditChangeGroups;
+ private TextEditCopier fCopier;
+ private TextEdit fEdit;
+ private boolean fTrackEdits;
+ private String fTextType;
+
+ /**
+ * A special object denoting all edits managed by the text change. This even
+ * includes those edits not managed by a TextEditChangeGroup
+ */
+ private static final TextEditChangeGroup[] ALL_EDITS= new TextEditChangeGroup[0];
+
+ /**
+ * Creates a new text change with the specified name. The name is a
+ * human-readable value that is displayed to users. The name does not
+ * need to be unique, but it must not be null
.
+ *
+ * The text type of this text change is set to txt
.
+ *
+ *
+ * @param name the name of the text change
+ *
+ * @see #setTextType(String)
+ */
+ protected TextChange(String name) {
+ Assert.isNotNull(name);
+ fName= name;
+ fTextEditChangeGroups= new ArrayList(5);
+ fTextType= "txt"; //$NON-NLS-1$
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ return fName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+ for (Iterator iter= fTextEditChangeGroups.iterator(); iter.hasNext();) {
+ TextEditChangeGroup element= (TextEditChangeGroup) iter.next();
+ element.setEnabled(enabled);
+ }
+ }
+
+ /**
+ * Sets the text type. The text type is used to determine the content
+ * merge viewer used to present the difference between the original
+ * and the preview content in the user interface. Content merge viewers
+ * are defined via the extension point org.eclipse.compare.contentMergeViewers
.
+ *
+ * The default text type is txt
.
+ *
+ *
+ * @param type the text type. If null
is passed the text type is
+ * resetted to the default text type txt
.
+ */
+ public void setTextType(String type) {
+ if (type == null)
+ type= "txt"; //$NON-NLS-1$
+ fTextType= type;
+ }
+
+ /**
+ * Returns the text change's text type.
+ *
+ * @return the text change's text type
+ */
+ public String getTextType() {
+ return fTextType;
+ }
+
+ //---- Edit management -----------------------------------------------
+
+ /**
+ * Sets the root text edit that should be applied to the
+ * document represented by this text change.
+ *
+ * @param edit the root text edit. The root text edit
+ * can only be set once.
+ */
+ public void setEdit(TextEdit edit) {
+ Assert.isTrue(fEdit == null, "Root edit can only be set once"); //$NON-NLS-1$
+ Assert.isTrue(edit != null);
+ fEdit= edit;
+ }
+
+ /**
+ * Returns the root text edit.
+ *
+ * @return the root text edit
+ */
+ public TextEdit getEdit() {
+ return fEdit;
+ }
+
+ /**
+ * Adds a {@link TextEditGroup text edit group}. This method is a convenient
+ * method for calling change.addTextEditChangeGroup(new
+ * TextEditChangeGroup(change, group));
.
+ *
+ * @param group the text edit group to add
+ */
+ public void addTextEditGroup(TextEditGroup group) {
+ addTextEditChangeGroup(new TextEditChangeGroup(this, group));
+ }
+
+ /**
+ * Adds a {@link TextEditChangeGroup text edit change group}. Calling the methods
+ * requires that a root edit has been set via the method {@link #setEdit(TextEdit)
+ * setEdit}. The edits managed by the given text edit change group must be part of
+ * the change's root edit.
+ *
+ * @param group the text edit change group to add
+ */
+ public void addTextEditChangeGroup(TextEditChangeGroup group) {
+ Assert.isTrue(fEdit != null, "Can only add a description if a root edit exists"); //$NON-NLS-1$
+ Assert.isTrue(group != null);
+ fTextEditChangeGroups.add(group);
+ }
+
+ /**
+ * Returns the {@link TextEditChangeGroup text edit change groups} managed by this
+ * text change.
+ *
+ * @return the text edit change groups
+ */
+ public TextEditChangeGroup[] getTextEditChangeGroups() {
+ return (TextEditChangeGroup[])fTextEditChangeGroups.toArray(new TextEditChangeGroup[fTextEditChangeGroups.size()]);
+ }
+
+ /**
+ * Aquires a reference to the document to be changed by this text
+ * change. A document aquired by this call MUST be released
+ * via a call to {@link #releaseDocument(IDocument, IProgressMonitor)}.
+ *
+ * The method releaseDocument
must be call as many times as
+ * aquireDocument
has been called.
+ *
+ *
+ * @param pm a progress monitor
+ *
+ * @return a reference to the document to be changed
+ *
+ * @throws CoreException if the document can't be aquired
+ */
+ protected abstract IDocument aquireDocument(IProgressMonitor pm) throws CoreException;
+
+ /**
+ * Commits the document aquired via a call to {@link #aquireDocument(IProgressMonitor)
+ * aquireDocument}. It is up to the implementors of this method to decide what committing
+ * a document means. Typically, the content of the document is written back to the file
+ * system.
+ *
+ * This method can be called more than once and the number of calls doesn't have to match
+ * the number of calls to aquireDocument
or releaseDocument
.
+ *
+ *
+ * @param document the document to commit
+ * @param pm a progress monitor
+ *
+ * @throws CoreException if the document can't be committed
+ */
+ protected abstract void commit(IDocument document, IProgressMonitor pm) throws CoreException;
+
+ /**
+ * Releases the document aquired via a call to {@link #aquireDocument(IProgressMonitor)
+ * aquireDocument}.
+ *
+ * @param document the document to release
+ * @param pm a progress monitor
+ *
+ * @throws CoreException if the document can't be released
+ */
+ protected abstract void releaseDocument(IDocument document, IProgressMonitor pm) throws CoreException;
+
+ /**
+ * 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.
+ *
+ * @param edit the {@link UndoEdit} to create an undo change for
+ *
+ * @return the undo change
+ *
+ * @throws CoreException if an undo change can't be created
+ */
+ protected abstract Change createUndoChange(UndoEdit edit) throws CoreException;
+
+ /**
+ * {@inheritDoc}
+ */
+ public Change perform(IProgressMonitor pm) throws CoreException {
+ pm.beginTask("", 3); //$NON-NLS-1$
+ IDocument document= null;
+ try {
+ document= aquireDocument(new SubProgressMonitor(pm, 1));
+ TextEditProcessor processor= createTextEditProcessor(document, TextEdit.CREATE_UNDO, false);
+ UndoEdit undo= processor.performEdits();
+ commit(document, new SubProgressMonitor(pm, 1));
+ return createUndoChange(undo);
+ } catch (BadLocationException e) {
+ throw Changes.asCoreException(e);
+ } finally {
+ if (document != null)
+ releaseDocument(document, new SubProgressMonitor(pm, 1));
+ pm.done();
+ }
+ }
+
+ //---- Method to access the current content of the text change ---------
+
+ /**
+ * Returns the current content of the document this text
+ * change is applied to.
+ *
+ * @return the current content of the text change
+ *
+ * @exception CoreException if the content can't be accessed
+ */
+ public String getCurrentContent() throws CoreException {
+ return getDocument().get();
+ }
+
+ /**
+ * Returns the current content of the text change clipped to a specific
+ * region. The region is determined as follows:
+ *
+ * - if
expandRegionToFullLine
is false
+ * then the parameter region
determines the clipping.
+ *
+ * - if
expandRegionToFullLine
is true
+ * then the region determined by the parameter region
+ * is extended to cover full lines.
+ *
+ * - if
surroundingLines
> 0 then the given number
+ * of surrounding lines is added. The value of surroundingLines
+ *
is only considered if expandRegionToFullLine
+ * is true
+ *
+ *
+ *
+ * @param region the starting region for the clipping
+ * @param expandRegionToFullLine if true
is passed the region
+ * is extended to cover full lines
+ * @param surroundingLines the number of surrounding lines to be added to
+ * the clipping region. Is only considered if expandRegionToFullLine
+ *
is true
+ *
+ * @return the current content of the text change clipped to a region
+ * determined by the given parameters.
+ *
+ * @throws CoreException
+ */
+ public String getCurrentContent(IRegion region, boolean expandRegionToFullLine, int surroundLines) throws CoreException {
+ Assert.isNotNull(region);
+ Assert.isTrue(surroundLines >= 0);
+ IDocument document= getDocument();
+ Assert.isTrue(document.getLength() >= region.getOffset() + region.getLength());
+ return getContent(document, region, expandRegionToFullLine, surroundLines);
+ }
+
+ //---- Method to access the preview content of the text change ---------
+
+ /**
+ * Controls whether the text change should keep executed edits during
+ * preview generation.
+ *
+ * @param keep if true
executed preview edits are kept
+ */
+ public void setKeepPreviewEdits(boolean keep) {
+ fTrackEdits= keep;
+ if (!fTrackEdits)
+ fCopier= null;
+ }
+
+ /**
+ * Returns whether preview edits are remembered for further region
+ * tracking or not.
+ *
+ * @return true
if executed text edits are remembered
+ * during preview generation; otherwise false
+ */
+ public boolean getKeepPreviewEdits() {
+ return fTrackEdits;
+ }
+
+ /**
+ * Returns the edit that got executed during preview generation
+ * instead of the given orignial. The method requires that
+ * setKeepPreviewEdits
is set to true
and that
+ * a preview has been requested via one of the getPreview*
+ *
methods.
+ *
+ * The method returns null
if the original isn't managed
+ * by this text change.
+ *
+ *
+ * @param original the original edit managed by this text change
+ *
+ * @return the edit executed during preview generation
+ */
+ public TextEdit getPreviewEdit(TextEdit original) {
+ Assert.isTrue(fTrackEdits && fCopier != null && original != null);
+ return fCopier.getCopy(original);
+ }
+
+ /**
+ * Returns the edits that were executed during preview generation
+ * instead of the given array of orignial edits. The method requires
+ * that setKeepPreviewEdits
is set to true
+ * and that a preview has been requested via one of the
+ * getPreview*
methods.
+ *
+ * The method returns an empty array if none of the original edits
+ * is managed by this text change.
+ *
+ *
+ * @param original an array of original edits managed by this text
+ * change
+ *
+ * @return an array of edits containing the corresponding edits
+ * executed during preview generation
+ */
+ public TextEdit[] getPreviewEdits(TextEdit[] originals) {
+ Assert.isTrue(fTrackEdits && fCopier != null && originals != null);
+ if (originals.length == 0)
+ return new TextEdit[0];
+ List result= new ArrayList(originals.length);
+ for (int i= 0; i < originals.length; i++) {
+ TextEdit copy= fCopier.getCopy(originals[i]);
+ if (copy != null)
+ result.add(copy);
+ }
+ return (TextEdit[]) result.toArray(new TextEdit[result.size()]);
+ }
+
+ /**
+ * Returns a document containing a preview of the text change. The
+ * preview is computed by executing the all managed text edits. The
+ * method considers the active state of the added {@link TextEditChangeGroup
+ * text edit change groups}.
+ *
+ * @return a document containing the preview of the text change
+ *
+ * @throws CoreException if the preview can't be created
+ */
+ public IDocument getPreviewDocument() throws CoreException {
+ PreviewAndRegion result= getPreviewDocument(ALL_EDITS);
+ return result.document;
+ }
+
+ /**
+ * Returns the preview content as a string. This is a convenient
+ * method for calling getPreviewDocument().get()
.
+ *
+ * @return the preview
+ *
+ * @throws CoreException if the preview can't be created
+ */
+ public String getPreviewContent() throws CoreException {
+ return getPreviewDocument().get();
+ }
+
+ /**
+ * Returns a preview of the text change clipped to a specific region.
+ * The preview is created by appying the text edits managed by the
+ * given array of {@link TextEditChangeGroup text edit change groups}.
+ * The region is determined as follows:
+ *
+ * - if
expandRegionToFullLine
is false
+ * then the parameter region
determines the clipping.
+ *
+ * - if
expandRegionToFullLine
is true
+ * then the region determined by the parameter region
+ * is extended to cover full lines.
+ *
+ * - if
surroundingLines
> 0 then the given number
+ * of surrounding lines is added. The value of surroundingLines
+ *
is only considered if expandRegionToFullLine
+ * is true
+ *
+ *
+ *
+ * @param region the starting region for the clipping
+ * @param expandRegionToFullLine if true
is passed the region
+ * is extended to cover full lines
+ * @param surroundingLines the number of surrounding lines to be added to
+ * the clipping region. Is only considered if expandRegionToFullLine
+ *
is true
+ *
+ * @return the current content of the text change clipped to a region
+ * determined by the given parameters.
+ *
+ * @throws CoreException
+ *
+ * @see #getCurrentContent(IRegion, boolean, int)
+ */
+ public String getPreviewContent(TextEditChangeGroup[] changes, IRegion region, boolean expandRegionToFullLine, int surroundingLines) throws CoreException {
+ IRegion currentRegion= getRegion(changes);
+ Assert.isTrue(region.getOffset() <= currentRegion.getOffset() &&
+ currentRegion.getOffset() + currentRegion.getLength() <= region.getOffset() + region.getLength());
+ PreviewAndRegion result= getPreviewDocument(changes);
+ int delta= result.region.getLength() - currentRegion.getLength();
+ return getContent(result.document, new Region(region.getOffset(), region.getLength() + delta), expandRegionToFullLine, surroundingLines);
+
+ }
+
+ //---- private helper methods --------------------------------------------------
+
+ private PreviewAndRegion getPreviewDocument(TextEditChangeGroup[] changes) throws CoreException {
+ IDocument document= new Document(getDocument().get());
+ boolean trackChanges= fTrackEdits;
+ setKeepPreviewEdits(true);
+ TextEditProcessor processor= changes == ALL_EDITS
+ ? createTextEditProcessor(document, TextEdit.NONE, true)
+ : createTextEditProcessor(document, TextEdit.NONE, changes);
+ try {
+ processor.performEdits();
+ return new PreviewAndRegion(document, getNewRegion(changes));
+ } catch (BadLocationException e) {
+ throw Changes.asCoreException(e);
+ } finally {
+ setKeepPreviewEdits(trackChanges);
+ }
+ }
+
+ private TextEditProcessor createTextEditProcessor(IDocument document, int flags, boolean preview) throws CoreException {
+ if (fEdit == null)
+ return new TextEditProcessor(document, new MultiTextEdit(0,0), flags);
+ List excludes= new ArrayList(0);
+ for (Iterator iter= fTextEditChangeGroups.iterator(); iter.hasNext(); ) {
+ TextEditChangeGroup edit= (TextEditChangeGroup)iter.next();
+ if (!edit.isEnabled()) {
+ excludes.addAll(Arrays.asList(edit.getTextEditGroup().getTextEdits()));
+ }
+ }
+ if (preview) {
+ fCopier= new TextEditCopier(fEdit);
+ TextEdit copiedEdit= fCopier.perform();
+ if (fTrackEdits)
+ flags= flags | TextEdit.UPDATE_REGIONS;
+ LocalTextEditProcessor result= new LocalTextEditProcessor(document, copiedEdit, flags);
+ result.setExcludes(mapEdits(
+ (TextEdit[])excludes.toArray(new TextEdit[excludes.size()]),
+ fCopier));
+ if (!fTrackEdits)
+ fCopier= null;
+ return result;
+ } else {
+ LocalTextEditProcessor result= new LocalTextEditProcessor(document, fEdit, flags | TextEdit.UPDATE_REGIONS);
+ result.setExcludes((TextEdit[])excludes.toArray(new TextEdit[excludes.size()]));
+ return result;
+ }
+ }
+
+ private TextEditProcessor createTextEditProcessor(IDocument document, int flags, TextEditChangeGroup[] changes) throws CoreException {
+ if (fEdit == null)
+ return new TextEditProcessor(document, new MultiTextEdit(0,0), flags);
+ List includes= new ArrayList(0);
+ for (int c= 0; c < changes.length; c++) {
+ TextEditChangeGroup change= changes[c];
+ Assert.isTrue(change.getTextChange() == this);
+ if (change.isEnabled()) {
+ includes.addAll(Arrays.asList(change.getTextEditGroup().getTextEdits()));
+ }
+ }
+ fCopier= new TextEditCopier(fEdit);
+ TextEdit copiedEdit= fCopier.perform();
+ if (fTrackEdits)
+ flags= flags | TextEdit.UPDATE_REGIONS;
+ LocalTextEditProcessor result= new LocalTextEditProcessor(document, copiedEdit, flags);
+ result.setIncludes(mapEdits(
+ (TextEdit[])includes.toArray(new TextEdit[includes.size()]),
+ fCopier));
+ if (!fTrackEdits)
+ fCopier= null;
+ return result;
+ }
+
+ private IDocument getDocument() throws CoreException {
+ IDocument result= null;
+ try{
+ result= aquireDocument(new NullProgressMonitor());
+ } finally {
+ if (result != null)
+ releaseDocument(result, new NullProgressMonitor());
+ }
+ return result;
+ }
+
+ private TextEdit[] mapEdits(TextEdit[] edits, TextEditCopier copier) {
+ if (edits == null)
+ return null;
+ for (int i= 0; i < edits.length; i++) {
+ edits[i]= copier.getCopy(edits[i]);
+ }
+ return edits;
+ }
+
+ private String getContent(IDocument document, IRegion region, boolean expandRegionToFullLine, int surroundingLines) throws CoreException {
+ try {
+ if (expandRegionToFullLine) {
+ int startLine= Math.max(document.getLineOfOffset(region.getOffset()) - surroundingLines, 0);
+ int endLine;
+ if (region.getLength() == 0) {
+ endLine= Math.min(
+ document.getLineOfOffset(region.getOffset()) + surroundingLines,
+ document.getNumberOfLines() - 1);
+ } else {
+ endLine= Math.min(
+ document.getLineOfOffset(region.getOffset() + region.getLength() - 1) + surroundingLines,
+ document.getNumberOfLines() - 1);
+ }
+
+ int offset= document.getLineInformation(startLine).getOffset();
+ IRegion endLineRegion= document.getLineInformation(endLine);
+ int length = endLineRegion.getOffset() + endLineRegion.getLength() - offset;
+ return document.get(offset, length);
+
+ } else {
+ return document.get(region.getOffset(), region.getLength());
+ }
+ } catch (BadLocationException e) {
+ throw Changes.asCoreException(e);
+ }
+ }
+
+ private IRegion getRegion(TextEditChangeGroup[] changes) {
+ if (changes == ALL_EDITS) {
+ if (fEdit == null)
+ return null;
+ return fEdit.getRegion();
+ } else {
+ List edits= new ArrayList();
+ for (int i= 0; i < changes.length; i++) {
+ edits.addAll(Arrays.asList(changes[i].getTextEditGroup().getTextEdits()));
+ }
+ if (edits.size() == 0)
+ return null;
+ return TextEdit.getCoverage((TextEdit[]) edits.toArray(new TextEdit[edits.size()]));
+ }
+ }
+
+ private IRegion getNewRegion(TextEditChangeGroup[] changes) {
+ if (changes == ALL_EDITS) {
+ if (fEdit == null)
+ return null;
+ return fCopier.getCopy(fEdit).getRegion();
+ } else {
+ List result= new ArrayList();
+ for (int c= 0; c < changes.length; c++) {
+ TextEdit[] edits= changes[c].getTextEditGroup().getTextEdits();
+ for (int e= 0; e < edits.length; e++) {
+ TextEdit copy= fCopier.getCopy(edits[e]);
+ if (copy != null)
+ result.add(copy);
+ }
+ }
+ if (result.size() == 0)
+ return null;
+ return TextEdit.getCoverage((TextEdit[]) result.toArray(new TextEdit[result.size()]));
+ }
+ }
+}
+
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/TextEditChangeGroup.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/TextEditChangeGroup.java
new file mode 100644
index 00000000000..380d59f3f54
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/TextEditChangeGroup.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+import org.eclipse.text.edits.TextEdit;
+import org.eclipse.text.edits.TextEditGroup;
+
+import org.eclipse.jface.text.IRegion;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+/**
+ * This class is a wrapper around a {@link TextEditGroup TextEditGroup}
+ * adding support for marking a group as active and inactive.
+ *
+ * @see TextEditGroup
+ *
+ * @since 3.0
+ */
+public class TextEditChangeGroup {
+
+ private boolean fIsEnabled;
+ private TextChange fTextChange;
+ private TextEditGroup fTextEditGroup;
+
+ /**
+ * Creates new TextEditChangeGroup
for the given
+ * TextChange
and TextEditGroup
.
+ *
+ * @param change the change owning this text edit change group
+ * @param group the underlying text edit group
+ */
+ public TextEditChangeGroup(TextChange change, TextEditGroup group) {
+ Assert.isNotNull(change);
+ Assert.isNotNull(group);
+ fTextChange= change;
+ fIsEnabled= true;
+ fTextEditGroup= group;
+ }
+
+ /**
+ * Returns the groups's name by forwarding the method
+ * to the underlying text edit group.
+ *
+ * @return the group's name
+ */
+ public String getName() {
+ return fTextEditGroup.getName();
+ }
+
+ /**
+ * Marks the group as enabled or disabled. If a group
+ * is marked as disabled the text edits managed by the
+ * underlying text edit group aren't executed when
+ * performing the text change that owns this group.
+ *
+ * @param enabled true
to mark this group
+ * as enabled, false
to mark it as disabled
+ */
+ public void setEnabled(boolean enabled) {
+ fIsEnabled= enabled;
+ }
+
+ /**
+ * Returns whether the group is enabled or not.
+ *
+ * @return true
if the group is marked as
+ * enabled; false
otherwise
+ */
+ public boolean isEnabled() {
+ return fIsEnabled;
+ }
+
+ /**
+ * Returns the text change this group belongs to.
+ *
+ * @return the text change this group belongs to
+ */
+ public TextChange getTextChange() {
+ return fTextChange;
+ }
+
+ /**
+ * Returns the underlying text edit group.
+ *
+ * @return the underlying text edit group
+ */
+ public TextEditGroup getTextEditGroup() {
+ return fTextEditGroup;
+ }
+
+ /**
+ * Returns the region covered by the underlying
+ * text edit group.
+ *
+ * @return the region covered by the underlying
+ * text edit group
+ */
+ public IRegion getRegion() {
+ return fTextEditGroup.getRegion();
+ }
+
+ /**
+ * Returns the text edits managed by the underlying
+ * text edit group.
+ *
+ * @return the text edits managed by the underlying
+ * text edit group
+ */
+ public TextEdit[] getTextEdits() {
+ return fTextEditGroup.getTextEdits();
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/TextFileChange.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/TextFileChange.java
new file mode 100644
index 00000000000..91c75e93521
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/TextFileChange.java
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+import org.eclipse.text.edits.UndoEdit;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+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.jface.text.IDocument;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+import org.eclipse.ltk.internal.core.refactoring.BufferValidationState;
+import org.eclipse.ltk.internal.core.refactoring.Changes;
+
+/**
+ * A special {@link TextChange} that operates on IFile
s.
+ *
+ * @since 3.0
+ */
+public class TextFileChange extends TextChange {
+
+ /** Flag indicating that the file's save state has to be kept. This means an unsaved file is still
+ * unsaved after performing the change and a saved one will be saved. */
+ public static final int KEEP_SAVE_STATE= 1 << 0;
+ /** Flag indicating that the file is to be saved after the change has been applied. */
+ public static final int FORCE_SAVE= 1 << 1;
+ /** Flag indicating that the file will not be saved after the change has been applied. */
+ public static final int LEAVE_DIRTY= 1 << 2;
+
+
+ // the file to change
+ private IFile fFile;
+ private int fSaveMode= KEEP_SAVE_STATE;
+
+ // the mapped text buffer
+ private int fAquireCount;
+ private ITextFileBuffer fBuffer;
+
+ private boolean fDirty;
+ private BufferValidationState fValidationState;
+
+ /**
+ * Creates a new TextFileChange
for the given file.
+ * s
+ * @param name the change's name mainly used to render the change in the UI
+ * @param file the file this text change operates on
+ */
+ public TextFileChange(String name, IFile file) {
+ super(name);
+ Assert.isNotNull(file);
+ fFile= file;
+ }
+
+ /**
+ * Sets the save state. If set to true
the change will save the
+ * content of the file back to disk.
+ *
+ * @param save whether or not the changes should be saved to disk
+ */
+ public void setSaveMode(int saveMode) {
+ fSaveMode= saveMode;
+ }
+
+ /**
+ * Returns whether the change saves the changes back to disk.
+ *
+ * @return true
if the change saves the modified
+ * content back to disk; otherwise false
is
+ * returned
+ */
+ public int getSaveMode() {
+ return fSaveMode;
+ }
+
+ /**
+ * Returns the IFile
this change is working on.
+ *
+ * @return the file this change is working on
+ */
+ public IFile getFile() {
+ return fFile;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getModifiedElement(){
+ return fFile;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void initializeValidationData(IProgressMonitor pm) throws CoreException {
+ pm.beginTask("", 1); //$NON-NLS-1$
+ fValidationState= BufferValidationState.create(fFile);
+ ITextFileBuffer buffer= FileBuffers.getTextFileBufferManager().getTextFileBuffer(fFile.getFullPath());
+ fDirty= buffer != null && buffer.isDirty();
+ pm.worked(1);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public RefactoringStatus isValid(IProgressMonitor pm) throws CoreException {
+ pm.beginTask("", 1); //$NON-NLS-1$
+ RefactoringStatus result= fValidationState.isValid();
+ if (needsSaving()) {
+ result.merge(Changes.validateModifiesFiles(new IFile[] {fFile}));
+ }
+ pm.worked(1);
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void dispose() {
+ fValidationState.dispose();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected IDocument aquireDocument(IProgressMonitor pm) throws CoreException {
+ if (fAquireCount > 0)
+ return fBuffer.getDocument();
+
+ ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
+ IPath path= fFile.getFullPath();
+ manager.connect(path, pm);
+ fAquireCount++;
+ fBuffer= manager.getTextFileBuffer(path);
+ return fBuffer.getDocument();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void commit(IDocument document, IProgressMonitor pm) throws CoreException {
+ if (needsSaving()) {
+ fBuffer.commit(pm, false);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void releaseDocument(IDocument document, IProgressMonitor pm) throws CoreException {
+ Assert.isTrue(fAquireCount > 0);
+ if (fAquireCount == 1) {
+ ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
+ manager.disconnect(fFile.getFullPath(), pm);
+ }
+ fAquireCount--;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected Change createUndoChange(UndoEdit edit) throws CoreException {
+ return new UndoTextFileChange(getName(), fFile, edit, fSaveMode);
+ }
+
+ private boolean needsSaving() {
+ return (fSaveMode & FORCE_SAVE) != 0 || (!fDirty && (fSaveMode & KEEP_SAVE_STATE) != 0);
+ }
+}
+
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/UndoDocumentChange.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/UndoDocumentChange.java
new file mode 100644
index 00000000000..342b3e56a75
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/UndoDocumentChange.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+import org.eclipse.text.edits.TextEdit;
+import org.eclipse.text.edits.UndoEdit;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+
+import org.eclipse.ltk.internal.core.refactoring.Changes;
+import org.eclipse.ltk.internal.core.refactoring.TextChanges;
+
+/**
+ * TODO
+ * @since 3.0
+ */
+public class UndoDocumentChange extends Change {
+
+ private String fName;
+ private UndoEdit fUndo;
+ private IDocument fDocument;
+ private int fLength;
+
+ public UndoDocumentChange(String name, IDocument document, UndoEdit undo) {
+ fName= name;
+ fUndo= undo;
+ fDocument= document;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ return fName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getModifiedElement() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void initializeValidationData(IProgressMonitor pm) throws CoreException {
+ fLength= fDocument.getLength();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public RefactoringStatus isValid(IProgressMonitor pm) throws CoreException {
+ pm.beginTask("", 1); //$NON-NLS-1$
+ RefactoringStatus result= TextChanges.isValid(fDocument, fLength);
+ pm.worked(1);
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Change perform(IProgressMonitor pm) throws CoreException {
+ try {
+ UndoEdit redo= fUndo.apply(fDocument, TextEdit.CREATE_UNDO);
+ Change result= new UndoDocumentChange(getName(), fDocument, redo);
+ return result;
+ } catch (BadLocationException e) {
+ throw Changes.asCoreException(e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/UndoManagerAdapter.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/UndoManagerAdapter.java
new file mode 100644
index 00000000000..28229190ad4
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/UndoManagerAdapter.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+/**
+ * This adapter class provides default implementations for the
+ * methods described by the {@link IUndoManagerListener} interface.
+ *
+ * @since 3.0
+ */
+public class UndoManagerAdapter implements IUndoManagerListener {
+
+ /* (non-Javadoc)
+ * Method declared in IUndoManagerListener
+ */
+ public void undoStackChanged(IUndoManager manager) {
+ }
+
+ /* (non-Javadoc)
+ * Method declared in IUndoManagerListener
+ */
+ public void redoStackChanged(IUndoManager manager) {
+ }
+}
+
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/UndoTextFileChange.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/UndoTextFileChange.java
new file mode 100644
index 00000000000..c546d7beceb
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/UndoTextFileChange.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+import org.eclipse.text.edits.TextEdit;
+import org.eclipse.text.edits.UndoEdit;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+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.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+import org.eclipse.ltk.internal.core.refactoring.BufferValidationState;
+import org.eclipse.ltk.internal.core.refactoring.Changes;
+
+/**
+ * A change to perform the reverse change of a {@link TextFileChange}.
+ *
+ * This class is not intended to be instantiated by clients. It is
+ * usually created by a TextFileChange
object.
+ *
+ *
+ * @since 3.0
+ */
+public class UndoTextFileChange extends Change {
+
+ private String fName;
+ private UndoEdit fUndo;
+ private IFile fFile;
+ private int fSaveMode;
+
+ private boolean fDirty;
+ private BufferValidationState fValidationState;
+
+ protected UndoTextFileChange(String name, IFile file, UndoEdit undo, int saveMode) {
+ Assert.isNotNull(name);
+ Assert.isNotNull(undo);
+ fName= name;
+ fFile= file;
+ fUndo= undo;
+ fSaveMode= saveMode;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ return fName;
+ }
+
+ public int getSaveMode() {
+ return fSaveMode;
+ }
+
+ /**
+ * 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.
+ *
+ *
+ * @param edit the {@link UndoEdit undo edit} to create a undo change for
+ *
+ * @return the undo change
+ *
+ * @throws CoreException if an undo change can't be created
+ */
+ protected Change createUndoChange(UndoEdit edit) throws CoreException {
+ return new UndoTextFileChange(getName(), fFile, edit, fSaveMode);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getModifiedElement() {
+ return fFile;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void initializeValidationData(IProgressMonitor pm) throws CoreException {
+ pm.beginTask("", 1); //$NON-NLS-1$
+ fValidationState= BufferValidationState.create(fFile);
+ ITextFileBuffer buffer= FileBuffers.getTextFileBufferManager().getTextFileBuffer(fFile.getFullPath());
+ fDirty= buffer != null && buffer.isDirty();
+ pm.worked(1);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public RefactoringStatus isValid(IProgressMonitor pm) throws CoreException {
+ pm.beginTask("", 1); //$NON-NLS-1$
+ RefactoringStatus result= fValidationState.isValid();
+ pm.worked(1);
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Change perform(IProgressMonitor pm) throws CoreException {
+ ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
+ pm.beginTask("", 2); //$NON-NLS-1$
+ ITextFileBuffer buffer= null;
+ try {
+ manager.connect(fFile.getFullPath(), new SubProgressMonitor(pm, 1));
+ buffer= manager.getTextFileBuffer(fFile.getFullPath());
+ IDocument document= buffer.getDocument();
+ UndoEdit redo= fUndo.apply(document, TextEdit.CREATE_UNDO);
+ if (needsSaving())
+ buffer.commit(pm, false);
+ return createUndoChange(redo);
+ } catch (BadLocationException e) {
+ throw Changes.asCoreException(e);
+ } finally {
+ if (buffer != null)
+ manager.disconnect(fFile.getFullPath(), new SubProgressMonitor(pm, 1));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void dispose() {
+ fValidationState.dispose();
+ }
+
+ private boolean needsSaving() {
+ return (fSaveMode & TextFileChange.FORCE_SAVE) != 0 || (!fDirty && (fSaveMode & TextFileChange.KEEP_SAVE_STATE) != 0);
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/ValidationStateChangedEvent.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/ValidationStateChangedEvent.java
new file mode 100644
index 00000000000..29a80c1575f
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/ValidationStateChangedEvent.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+import java.util.EventObject;
+
+
+
+/**
+ * Event object describing a validation state change. The source of
+ * an event is the change object which validation state changed. This
+ * is not necessarily the change event on which a client registered
+ * a listener via IDynamicValidationStateChange.addValidationStateListener(listener)
+ *
. It might be one of its direct or indirect children.
+ *
+ * @since 3.0
+ */
+public class ValidationStateChangedEvent extends EventObject {
+
+ /**
+ * Creates a new validation state change event.
+ *
+ * @param source the change which validation state changed
+ */
+ public ValidationStateChangedEvent(Change source) {
+ super(source);
+ }
+
+ /**
+ * Returns the change that triggered this event.
+ *
+ * @return the change that triggered this event
+ */
+ public Change getChange() {
+ return (Change)getSource();
+ }
+
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/CheckConditionsContext.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/CheckConditionsContext.java
new file mode 100644
index 00000000000..960d0a005cf
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/CheckConditionsContext.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+import org.eclipse.ltk.core.refactoring.IRefactoringCoreStatusCodes;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+import org.eclipse.ltk.internal.core.refactoring.RefactoringCoreMessages;
+import org.eclipse.ltk.internal.core.refactoring.RefactoringCorePlugin;
+
+/**
+ * A context that is shared between the refactoring processor and
+ * all its associated participants during condition checking.
+ *
+ * The context manages a set of {@link IConditionChecker} objects
+ * to collect condition checks that should be perform across all
+ * participants and the processor. For example validating if a
+ * file can be changed (see {@link org.eclipse.core.resources.IWorkspace#validateEdit(org.eclipse.core.resources.IFile[], java.lang.Object)}
+ * should only be called once for all files modified by the processor
+ * and all participants.
+ *
+ *
+ * @since 3.0
+ */
+public class CheckConditionsContext {
+
+ private Map fCheckers= new HashMap();
+
+ /**
+ * Returns the condition checker of the given type.
+ *
+ * @param clazz the type of the condition checker
+ *
+ * @return the condition checker or null
if
+ * no checker is registered for the given type
+ */
+ public IConditionChecker getChecker(Class clazz) {
+ return (IConditionChecker)fCheckers.get(clazz);
+ }
+
+ /**
+ * Adds the given condition checker. An assertion will be
+ * thrown if a checker of the same type already exists in
+ * this context.
+ *
+ * @param checker the checker to add
+ * @throws CoreException if a checker of the same type already
+ * exists.
+ */
+ public void add(IConditionChecker checker) throws CoreException {
+ Object old= fCheckers.put(checker.getClass(), checker);
+ if (old != null) {
+ fCheckers.put(checker.getClass(), old);
+ throw new CoreException(new Status(IStatus.ERROR, RefactoringCorePlugin.getPluginId(),
+ IRefactoringCoreStatusCodes.CHECKER_ALREADY_EXISTS_IN_CONTEXT,
+ RefactoringCoreMessages.getFormattedString("CheckConditionContext.error.checker_exists", checker.getClass().toString()), //$NON-NLS-1$
+ null));
+ }
+ }
+
+ /**
+ * Checks the condition of all registered condition checkers and returns a
+ * merge status result.
+ *
+ * @param pm a progress monitor
+ *
+ * @return the combined status result
+ *
+ * @throws CoreException if an error occurs during condition checking
+ */
+ public RefactoringStatus check(IProgressMonitor pm) throws CoreException {
+ RefactoringStatus result= new RefactoringStatus();
+ for (Iterator iter= fCheckers.values().iterator(); iter.hasNext();) {
+ IConditionChecker checker= (IConditionChecker)iter.next();
+ result.merge(checker.check(new SubProgressMonitor(pm, 1)));
+ }
+ return result;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/CopyArguments.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/CopyArguments.java
new file mode 100644
index 00000000000..10da578dd08
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/CopyArguments.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+/**
+ * Copy arguments describes the data that a processor
+ * provides to its copy participants.
+ *
+ * @since 3.0
+ */
+public class CopyArguments {
+
+ private Object fTarget;
+
+ /**
+ * Creates new copy arguments.
+ *
+ * @param target the target location of the copy operation
+ */
+ public CopyArguments(Object target) {
+ Assert.isNotNull(target);
+ fTarget= target;
+ }
+
+ /**
+ * Returns the target location of the copy operation
+ *
+ * @return the copy's target location
+ */
+ public Object getTargetLocation() {
+ return fTarget;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/CopyParticipant.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/CopyParticipant.java
new file mode 100644
index 00000000000..66fe7a7fc92
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/CopyParticipant.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2003 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+public abstract class CopyParticipant extends RefactoringParticipant {
+
+ private CopyArguments fArguments;
+
+ /**
+ * Sets the copy arguments as provided by the corresponding
+ * refactoring processor.
+ *
+ * @param arguments the copy arguments
+ */
+ public void setArguments(CopyArguments arguments) {
+ Assert.isNotNull(arguments);
+ fArguments= arguments;
+ }
+
+ /**
+ * Returns the copy arguments or null
if the arguments
+ * haven't been initialized yet.
+ *
+ * @return the copy arguments or null
+ */
+ public CopyArguments getArguments() {
+ return fArguments;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/CreateArguments.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/CreateArguments.java
new file mode 100644
index 00000000000..784ebe553f7
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/CreateArguments.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+/**
+ * Create arguments describes the data that a processor provides to its
+ * create participants.
+ *
+ * As of version 3.0 there aren't any special arguments passed to a create
+ * participant. This may change in the future.
+ *
+ *
+ * @since 3.0
+ */
+public class CreateArguments {
+
+ /**
+ * Creates empty create arguments.
+ */
+ public CreateArguments() {
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/CreateParticipant.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/CreateParticipant.java
new file mode 100644
index 00000000000..ba0b6512098
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/CreateParticipant.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2003 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+
+public abstract class CreateParticipant extends RefactoringParticipant {
+
+ private CreateArguments fArguments;
+
+ /**
+ * Sets the create arguments as provided by the corresponding
+ * refactoring processor.
+ *
+ * @param arguments the create arguments
+ */
+ public void setArguments(CreateArguments arguments) {
+ Assert.isNotNull(arguments);
+ fArguments= arguments;
+ }
+
+ /**
+ * Returns the create arguments or null
if the arguments
+ * haven't been initialized yet.
+ *
+ * @return the create arguments or null
+ */
+ public CreateArguments getArguments() {
+ return fArguments;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/DeleteArguments.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/DeleteArguments.java
new file mode 100644
index 00000000000..757fe928a67
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/DeleteArguments.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+/**
+ * Delete arguments describes the data that a processor provides to its
+ * delete participants.
+ *
+ * As of version 3.0 there aren't any special arguments passed to a delete
+ * participant. This may change in the future.
+ *
+ *
+ * @since 3.0
+ */
+public class DeleteArguments {
+
+ /**
+ * Creates empty create arguments.
+ */
+ public DeleteArguments() {
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/DeleteParticipant.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/DeleteParticipant.java
new file mode 100644
index 00000000000..1877292b69f
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/DeleteParticipant.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2003 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+/**
+ * TODO Write Java doc
+ * @since 3.0
+ */
+public abstract class DeleteParticipant extends RefactoringParticipant {
+
+ private DeleteArguments fArguments;
+
+ /**
+ * Sets the delete arguments as provided by the corresponding
+ * refactoring processor.
+ *
+ * @param arguments the delete arguments
+ */
+ public void setArguments(DeleteArguments arguments) {
+ Assert.isNotNull(arguments);
+ fArguments= arguments;
+ }
+
+ /**
+ * Returns the delete arguments or null
if the arguments
+ * haven't been initialized yet.
+ *
+ * @return the delete arguments or null
+ */
+ public DeleteArguments getArguments() {
+ return fArguments;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/DeleteProcessor.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/DeleteProcessor.java
new file mode 100644
index 00000000000..850ca7dee40
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/DeleteProcessor.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2003 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.core.runtime.CoreException;
+
+public abstract class DeleteProcessor extends RefactoringProcessor {
+
+ private SharableParticipants fSharedParticipants= new SharableParticipants();
+
+ public abstract DeleteParticipant[] loadElementParticipants() throws CoreException;
+
+ public void setArgumentsTo(DeleteParticipant participant) throws CoreException {
+ participant.setArguments(getArguments());
+ }
+
+ protected DeleteArguments getArguments() {
+ return new DeleteArguments();
+ }
+
+ protected SharableParticipants getSharedParticipants() {
+ return fSharedParticipants;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/DeleteRefactoring.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/DeleteRefactoring.java
new file mode 100644
index 00000000000..e6027bc16b2
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/DeleteRefactoring.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+/**
+ * A generic delete refactoring. The actual refactoring is done
+ * by the delete processor passed to the constructor.
+ *
+ * @since 3.0
+ */
+public class DeleteRefactoring extends ProcessorBasedRefactoring {
+
+ private DeleteProcessor fProcessor;
+ private DeleteParticipant[] fElementParticipants;
+
+ /**
+ * Constructs a new delete refactoring for the given processor.
+ *
+ * @param processor the delete processor
+ */
+ public DeleteRefactoring(DeleteProcessor processor) throws CoreException {
+ Assert.isNotNull(processor);
+ fProcessor= processor;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public RefactoringProcessor getProcessor() {
+ return fProcessor;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected RefactoringParticipant[] getElementParticipants(boolean setArguments) throws CoreException {
+ if (fElementParticipants == null)
+ fElementParticipants= fProcessor.loadElementParticipants();
+ if (setArguments) {
+ for (int i= 0; i < fElementParticipants.length; i++) {
+ fProcessor.setArgumentsTo(fElementParticipants[i]);
+ }
+ }
+ RefactoringParticipant[]result= new RefactoringParticipant[fElementParticipants.length];
+ for (int i= 0; i < result.length; i++) {
+ result[i]= fElementParticipants[i];
+ }
+ return result;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ExtensionManager.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ExtensionManager.java
new file mode 100644
index 00000000000..7334052e38e
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ExtensionManager.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2003 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IPluginRegistry;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+
+import org.eclipse.core.expressions.EvaluationContext;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+import org.eclipse.ltk.internal.core.refactoring.RefactoringCorePlugin;
+
+/* package */ class ExtensionManager {
+
+ private String fName;
+
+ private String fParticipantID;
+ private List fParticipants;
+
+ //---- debuging----------------------------------------
+ /*
+ private static final boolean EXIST_TRACING;
+ static {
+ String value= Platform.getDebugOption("org.eclipse.jdt.ui/processor/existTracing"); //$NON-NLS-1$
+ EXIST_TRACING= value != null && value.equalsIgnoreCase("true"); //$NON-NLS-1$
+ }
+
+ private void printTime(long start) {
+ System.out.println("[" + fName + //$NON-NLS-1$
+ " extension manager] - existing test: " + //$NON-NLS-1$
+ (System.currentTimeMillis() - start) + " ms"); //$NON-NLS-1$
+ }
+ */
+
+ public ExtensionManager(String name, String participantId) {
+ Assert.isNotNull(name);
+ Assert.isNotNull(participantId);
+ fName= name;
+ fParticipantID= participantId;
+ }
+
+ public String getName() {
+ return fName;
+ }
+
+ public RefactoringParticipant[] getParticipants2(RefactoringProcessor processor, Object element, String[] affectedNatures, SharableParticipants shared) throws CoreException {
+ if (fParticipants == null)
+ init();
+
+ EvaluationContext evalContext= createEvaluationContext(processor, element, affectedNatures);
+ List result= new ArrayList();
+ for (Iterator iter= fParticipants.iterator(); iter.hasNext();) {
+ ParticipantDescriptor descriptor= (ParticipantDescriptor)iter.next();
+ try {
+ if (descriptor.matches(evalContext)) {
+ RefactoringParticipant participant= shared.get(descriptor);
+ if (participant != null) {
+ ((ISharableParticipant)participant).addElement(element);
+ } else {
+ participant= descriptor.createParticipant();
+ participant.initialize(processor, element);
+ if (participant.isApplicable()) {
+ result.add(participant);
+ if (participant instanceof ISharableParticipant)
+ shared.put(descriptor, participant);
+ }
+ }
+ }
+ } catch (CoreException e) {
+ RefactoringCorePlugin.log(e.getStatus());
+ iter.remove();
+ }
+ }
+
+ return (RefactoringParticipant[])result.toArray(new RefactoringParticipant[result.size()]);
+ }
+
+ private void init() {
+ IPluginRegistry registry= Platform.getPluginRegistry();
+ IConfigurationElement[] ces= registry.getConfigurationElementsFor(
+ RefactoringCorePlugin.getPluginId(),
+ fParticipantID);
+ fParticipants= new ArrayList(ces.length);
+ for (int i= 0; i < ces.length; i++) {
+ ParticipantDescriptor descriptor= new ParticipantDescriptor(ces[i]);
+ IStatus status= descriptor.checkSyntax();
+ switch (status.getSeverity()) {
+ case IStatus.ERROR:
+ RefactoringCorePlugin.log(status);
+ break;
+ case IStatus.WARNING:
+ case IStatus.INFO:
+ RefactoringCorePlugin.log(status);
+ // fall through
+ default:
+ fParticipants.add(descriptor);
+ }
+ }
+ }
+
+ //---- Helper methods ------------------------------------------------------------------
+
+ private static EvaluationContext createEvaluationContext(RefactoringProcessor processor, Object element, String[] affectedNatures) throws CoreException {
+ EvaluationContext result= new EvaluationContext(null, element);
+ result.addVariable("element", element); //$NON-NLS-1$
+ result.addVariable("affectedNatures", Arrays.asList(affectedNatures)); //$NON-NLS-1$
+ result.addVariable("processorIdentifier", processor.getIdentifier()); //$NON-NLS-1$
+ return result;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/IConditionChecker.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/IConditionChecker.java
new file mode 100644
index 00000000000..6465da6a457
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/IConditionChecker.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+
+/**
+ * A condition checker can be used to share condition checks
+ * across the main processor and all its associated participants.
+ *
+ * @see org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext
+ *
+ * @since 3.0
+ */
+public interface IConditionChecker {
+
+ /**
+ * Performs the actual condition checking.
+ *
+ * @param monitor a progress monitor to report progress
+ * @return the outcome of the condition check
+ *
+ * @throws CoreException if an error occurred during condition
+ * checking
+ */
+ public RefactoringStatus check(IProgressMonitor monitor) throws CoreException;
+
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ISharableParticipant.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ISharableParticipant.java
new file mode 100644
index 00000000000..a317af2e168
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ISharableParticipant.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2003 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+
+public interface ISharableParticipant {
+
+ public void addElement(Object element);
+
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/MoveArguments.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/MoveArguments.java
new file mode 100644
index 00000000000..3d9d3575d14
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/MoveArguments.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+/**
+ * Move arguments describes the data that a processor
+ * provides to its move participants.
+ *
+ * @since 3.0
+ */
+public class MoveArguments {
+
+ private Object fDestination;
+ private boolean fUpdateReferences;
+
+ /**
+ * Creates new rename arguments.
+ *
+ * @param destination the destination of the move
+ * @param updateReferences true
if reference
+ * updating is requested; false
otherwise
+ */
+ public MoveArguments(Object destination, boolean updateReferences) {
+ Assert.isNotNull(destination);
+ fDestination= destination;
+ fUpdateReferences= updateReferences;
+ }
+
+ /**
+ * Returns the destination of the move
+ *
+ * @return the move's destination
+ */
+ public Object getDestination() {
+ return fDestination;
+ }
+
+ /**
+ * Returns whether reference updating is requested or not.
+ *
+ * @return returns true
if reference
+ * updating is requested; false
otherwise
+ */
+ public boolean getUpdateReferences() {
+ return fUpdateReferences;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/MoveParticipant.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/MoveParticipant.java
new file mode 100644
index 00000000000..2a0d1253c0a
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/MoveParticipant.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2003 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+public abstract class MoveParticipant extends RefactoringParticipant {
+
+ private MoveArguments fArguments;
+
+ /**
+ * Sets the move arguments as provided by the corresponding
+ * refactoring processor.
+ *
+ * @param arguments the move arguments
+ */
+ public void setArguments(MoveArguments arguments) {
+ Assert.isNotNull(arguments);
+ fArguments= arguments;
+ }
+
+ /**
+ * Returns the move arguments or null
if the arguments
+ * haven't been initialized yet.
+ *
+ * @return the move arguments or null
+ */
+ public MoveArguments getArguments() {
+ return fArguments;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/MoveProcessor.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/MoveProcessor.java
new file mode 100644
index 00000000000..3fe4289610b
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/MoveProcessor.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2003 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * A rename processor is a special refactoring processor to support
+ * participating in rename refactorings. A rename processor is responsible
+ * for actual renaming the element to be refactored. Additionally the
+ * processor can update reference which are part of the same domain as the
+ * element to be renamed. For example a processor to rename a Java field
+ * can also update all references to that field found in Java files.
+ *
+ * A rename processor is also responsible to load participants that want
+ * to participate in a rename refactoring.
+ *
+ *
+ * @since 3.0
+ */
+public abstract class MoveProcessor extends RefactoringProcessor {
+
+ private int fStyle;
+ private SharableParticipants fSharedParticipants= new SharableParticipants();
+
+ protected MoveProcessor() {
+ fStyle= RefactoringStyles.NEEDS_PREVIEW;
+ }
+
+ protected MoveProcessor(int style) {
+ fStyle= style;
+ }
+
+ public int getStyle() {
+ return fStyle;
+ }
+
+ /**
+ * Forwards the current rename arguments to the passed participant.
+ *
+ * @param participant the participant to set the arguments to
+ *
+ * @throws CoreException if the arguments can't be set
+ */
+ public void setArgumentsTo(MoveParticipant participant) throws CoreException {
+ participant.setArguments(getArguments());
+ }
+
+ /**
+ * Returns the participants that participate in the rename of the element. The
+ * method is called after {@link #checkInitialConditions} has been called on the
+ * processor itself.
+ *
+ * The arguments are set to the participants by the processor via the call
+ * {@link RenameParticipant#setArguments(RenameArguments)}. They are set
+ * before {@link #checkFinalConditions}is called on the participants.
+ *
+ * @return an array of rename participants
+ *
+ * @throws CoreException if creating or loading of the participants failed
+ */
+ public abstract MoveParticipant[] loadElementParticipants() throws CoreException;
+
+ /**
+ * Returns the shared participants. ????
+ *
+ * @return
+ */
+ protected SharableParticipants getSharedParticipants() {
+ return fSharedParticipants;
+ }
+
+ /**
+ * Returns the arguments of the move.
+ *
+ * @return the move arguments
+ */
+ protected MoveArguments getArguments() {
+ return new MoveArguments(getDestination(), getUpdateReferences());
+ }
+
+ /**
+ * Returns the destination of the move.
+ *
+ * @return the target location of the move
+ */
+ protected abstract Object getDestination();
+
+ /**
+ * Returns whether reference updating is requested or not.
+ *
+ * @return whether reference updating is requested or not
+ */
+ protected abstract boolean getUpdateReferences();
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/MoveRefactoring.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/MoveRefactoring.java
new file mode 100644
index 00000000000..b3ec4ce727f
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/MoveRefactoring.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+/**
+ * A generic move refactoring. The actual refactoring is done
+ * by the move processor passed to the constructor.
+ *
+ * @since 3.0
+ */
+public class MoveRefactoring extends ProcessorBasedRefactoring {
+
+ private MoveProcessor fProcessor;
+ private MoveParticipant[] fElementParticipants;
+
+ /**
+ * Creates a new move refactoring with the given move processor.
+ *
+ * @param processor the move processor
+ */
+ public MoveRefactoring(MoveProcessor processor) {
+ Assert.isNotNull(processor);
+ fProcessor= processor;
+ }
+
+ /**
+ * Returns the move processor associated with this move refactoring.
+ *
+ * @return
+ */
+ public MoveProcessor getMoveProcessor() {
+ return fProcessor;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public RefactoringProcessor getProcessor() {
+ return fProcessor;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected RefactoringParticipant[] getElementParticipants(boolean setArguments) throws CoreException {
+ if (fElementParticipants == null)
+ fElementParticipants= fProcessor.loadElementParticipants();
+ if (setArguments) {
+ for (int i= 0; i < fElementParticipants.length; i++) {
+ fProcessor.setArgumentsTo(fElementParticipants[i]);
+ }
+ }
+ RefactoringParticipant[]result= new RefactoringParticipant[fElementParticipants.length];
+ for (int i= 0; i < result.length; i++) {
+ result[i]= fElementParticipants[i];
+ }
+ return result;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ParticipantDescriptor.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ParticipantDescriptor.java
new file mode 100644
index 00000000000..c799eb6d725
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ParticipantDescriptor.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2003 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionConverter;
+import org.eclipse.core.expressions.ExpressionTagNames;
+import org.eclipse.core.expressions.IEvaluationContext;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+import org.eclipse.ltk.internal.core.refactoring.RefactoringCorePlugin;
+
+public class ParticipantDescriptor {
+
+ private IConfigurationElement fConfigurationElement;
+
+ private static final String ID= "id"; //$NON-NLS-1$
+ private static final String CLASS= "class"; //$NON-NLS-1$
+
+ public ParticipantDescriptor(IConfigurationElement element) {
+ fConfigurationElement= element;
+ }
+
+ public String getId() {
+ return fConfigurationElement.getAttribute(ID);
+ }
+
+ public IStatus checkSyntax() {
+// IConfigurationElement[] children= fConfigurationElement.getChildren(SCOPE_STATE);
+// switch(children.length) {
+// case 0:
+// return new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.ERROR,
+// "Mandantory element missing. Disabling rename participant " + getId(), null);
+// case 1:
+// break;
+// default:
+// return new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.ERROR,
+// "Only one element allowed. Disabling rename participant " + getId(), null);
+// }
+// children= fConfigurationElement.getChildren(OBJECT_STATE);
+// if (children.length > 1) {
+// return new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.ERROR,
+// "Only one element allowed. Disabling rename participant " + getId(), null);
+// }
+ return new Status(IStatus.OK, RefactoringCorePlugin.getPluginId(), IStatus.OK,
+ "Syntactically correct rename participant element", null);
+ }
+
+ public boolean matches(IEvaluationContext context) throws CoreException {
+ IConfigurationElement[] elements= fConfigurationElement.getChildren(ExpressionTagNames.ENABLEMENT);
+ if (elements.length == 0)
+ return false;
+ Assert.isTrue(elements.length == 1);
+ Expression exp= ExpressionConverter.getDefault().perform(elements[0]);
+ return convert(exp.evaluate(context));
+ }
+
+ public RefactoringParticipant createParticipant() throws CoreException {
+ return (RefactoringParticipant)fConfigurationElement.createExecutableExtension(CLASS);
+ }
+
+ private boolean convert(EvaluationResult eval) {
+ if (eval == EvaluationResult.FALSE)
+ return false;
+ return true;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ParticipantManager.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ParticipantManager.java
new file mode 100644
index 00000000000..ce7f82c3719
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ParticipantManager.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Facade to access the rename, move, delete, create and copy participant
+ * extension point provided by the org.eclipse.ltk.core.refactoring plug-in.
+ *
+ * @since 3.0
+ */
+public class ParticipantManager {
+
+ //---- Move participants ----------------------------------------------------------------
+
+ private static final String MOVE_PARTICIPANT_EXT_POINT= "moveParticipants"; //$NON-NLS-1$
+ private static ExtensionManager fgMoveExtensions= new ExtensionManager("Move", MOVE_PARTICIPANT_EXT_POINT); //$NON-NLS-1$
+
+ public static MoveParticipant[] getMoveParticipants(RefactoringProcessor processor, Object element, String[] affectedNatures, SharableParticipants shared) throws CoreException {
+ RefactoringParticipant[] participants= fgMoveExtensions.getParticipants2(processor, element, affectedNatures, shared);
+ MoveParticipant[] result= new MoveParticipant[participants.length];
+ System.arraycopy(participants, 0, result, 0, participants.length);
+ return result;
+ }
+
+ //---- Copy participants ----------------------------------------------------------------
+
+ private static final String COPY_PARTICIPANT_EXT_POINT= "copyParticipants"; //$NON-NLS-1$
+ private static ExtensionManager fgCopyInstance= new ExtensionManager("Copy", COPY_PARTICIPANT_EXT_POINT); //$NON-NLS-1$
+
+ public static CopyParticipant[] getCopyParticipants(RefactoringProcessor processor, Object element, String[] affectedNatures, SharableParticipants shared) throws CoreException {
+ RefactoringParticipant[] participants= fgCopyInstance.getParticipants2(processor, element, affectedNatures, shared);
+ CopyParticipant[] result= new CopyParticipant[participants.length];
+ System.arraycopy(participants, 0, result, 0, participants.length);
+ return result;
+ }
+
+ //---- Delete participants ----------------------------------------------------------------
+
+ private static final String DELETE_PARTICIPANT_EXT_POINT= "deleteParticipants"; //$NON-NLS-1$
+ private static ExtensionManager fgDeleteInstance= new ExtensionManager("Delete", DELETE_PARTICIPANT_EXT_POINT); //$NON-NLS-1$
+
+ public static DeleteParticipant[] getDeleteParticipants(RefactoringProcessor processor, Object element, String[] affectedNatures, SharableParticipants shared) throws CoreException {
+ RefactoringParticipant[] participants= fgDeleteInstance.getParticipants2(processor, element, affectedNatures, shared);
+ DeleteParticipant[] result= new DeleteParticipant[participants.length];
+ System.arraycopy(participants, 0, result, 0, participants.length);
+ return result;
+ }
+
+ //---- Create participants ----------------------------------------------------------------
+
+ private static final String CREATE_PARTICIPANT_EXT_POINT= "createParticipants"; //$NON-NLS-1$
+ private static ExtensionManager fgCreateInstance= new ExtensionManager("Create", CREATE_PARTICIPANT_EXT_POINT); //$NON-NLS-1$
+
+ public static CreateParticipant[] getCreateParticipants(RefactoringProcessor processor, Object element, String affectedNatures[], SharableParticipants shared) throws CoreException {
+ RefactoringParticipant[] participants= fgCreateInstance.getParticipants2(processor, element, affectedNatures, shared);
+ CreateParticipant[] result= new CreateParticipant[participants.length];
+ System.arraycopy(participants, 0, result, 0, participants.length);
+ return result;
+ }
+
+ //---- Rename participants ----------------------------------------------------------------
+
+ private static final String RENAME_PARTICIPANT_EXT_POINT= "renameParticipants"; //$NON-NLS-1$
+ private static ExtensionManager fgRenameInstance= new ExtensionManager("Rename", RENAME_PARTICIPANT_EXT_POINT); //$NON-NLS-1$
+
+ public static RenameParticipant[] getRenameParticipants(RefactoringProcessor processor, Object element, String[] affectedNatures, SharableParticipants shared) throws CoreException {
+ RefactoringParticipant[] participants= fgRenameInstance.getParticipants2(processor, element, affectedNatures, shared);
+ RenameParticipant[] result= new RenameParticipant[participants.length];
+ System.arraycopy(participants, 0, result, 0, participants.length);
+ return result;
+ }
+
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ProcessorBasedRefactoring.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ProcessorBasedRefactoring.java
new file mode 100644
index 00000000000..526314e2501
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ProcessorBasedRefactoring.java
@@ -0,0 +1,200 @@
+/*******************************************************************************
+ * Copyright (c) 2003 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+import org.eclipse.ltk.core.refactoring.Change;
+import org.eclipse.ltk.core.refactoring.Refactoring;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+import org.eclipse.ltk.internal.core.refactoring.DelegatingValidationStateChange;
+
+public abstract class ProcessorBasedRefactoring extends Refactoring {
+
+ private RefactoringParticipant[] fDerivedParticipants;
+
+ /**
+ * Creates a new processor based refactoring.
+ */
+ protected ProcessorBasedRefactoring() {
+ }
+
+ /**
+ * Return the processor associated with this refactoring. The
+ * method must not return null
.
+ *
+ * @return the processor associated with this refactoring
+ */
+ public abstract RefactoringProcessor getProcessor();
+
+ protected abstract RefactoringParticipant[] getElementParticipants(boolean setArguments) throws CoreException;
+
+ public boolean isAvailable() throws CoreException {
+ return getProcessor().isApplicable();
+ }
+
+ public int getStyle() {
+ return getProcessor().getStyle();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ return getProcessor().getProcessorName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
+ RefactoringStatus result= new RefactoringStatus();
+ CheckConditionsContext context= createCheckConditionsContext();
+ pm.beginTask("", 5); //$NON-NLS-1$
+ result.merge(getProcessor().checkInitialConditions(new SubProgressMonitor(pm, 3), context));
+ if (result.hasFatalError()) {
+ pm.done();
+ return result;
+ }
+ RefactoringParticipant[] elementParticipants= getElementParticipants(false);
+ IProgressMonitor sm= new SubProgressMonitor(pm, 1);
+ sm.beginTask("", elementParticipants.length); //$NON-NLS-1$
+ for (int i= 0; i < elementParticipants.length; i++) {
+ result.merge(elementParticipants[i].checkInitialConditions(new SubProgressMonitor(sm, 1), context));
+ }
+ sm.done();
+ if (result.hasFatalError()) {
+ pm.done();
+ return result;
+ }
+ result.merge(context.check(new SubProgressMonitor(pm, 1)));
+ pm.done();
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException {
+ RefactoringStatus result= new RefactoringStatus();
+ CheckConditionsContext context= createCheckConditionsContext();
+
+ pm.beginTask("", 9); //$NON-NLS-1$
+
+ result.merge(getProcessor().checkFinalConditions(new SubProgressMonitor(pm, 5), context));
+ if (result.hasFatalError()) {
+ pm.done();
+ return result;
+ }
+
+ RefactoringParticipant[] elementParticipants= getElementParticipants(true);
+ IProgressMonitor sm= new SubProgressMonitor(pm, 1);
+ sm.beginTask("", elementParticipants.length); //$NON-NLS-1$
+ for (int i= 0; i < elementParticipants.length; i++) {
+ result.merge(elementParticipants[i].checkFinalConditions(new SubProgressMonitor(sm, 1), context));
+ }
+ sm.done();
+ if (result.hasFatalError()) {
+ pm.done();
+ return result;
+ }
+
+ fDerivedParticipants= getProcessor().loadDerivedParticipants();
+ sm= new SubProgressMonitor(pm, 1);
+ sm.beginTask("", fDerivedParticipants.length); //$NON-NLS-1$
+ for (int i= 0; i < fDerivedParticipants.length; i++) {
+ result.merge(fDerivedParticipants[i].checkInitialConditions(new SubProgressMonitor(sm, 1), context));
+ }
+ sm.done();
+ if (result.hasFatalError()) {
+ pm.done();
+ return result;
+ }
+
+ sm= new SubProgressMonitor(pm, 1);
+ sm.beginTask("", fDerivedParticipants.length); //$NON-NLS-1$
+ for (int i= 0; i < fDerivedParticipants.length; i++) {
+ result.merge(fDerivedParticipants[i].checkFinalConditions(new SubProgressMonitor(sm, 1), context));
+ }
+ sm.done();
+ if (result.hasFatalError()) {
+ pm.done();
+ return result;
+ }
+
+ result.merge(context.check(new SubProgressMonitor(pm, 1)));
+ pm.done();
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Change createChange(IProgressMonitor pm) throws CoreException {
+ RefactoringParticipant[] elementParticipants= getElementParticipants(false);
+
+ pm.beginTask("", elementParticipants.length + fDerivedParticipants.length + 1); //$NON-NLS-1$
+ List changes= new ArrayList();
+ changes.add(getProcessor().createChange(new SubProgressMonitor(pm, 1)));
+
+ for (int i= 0; i < elementParticipants.length; i++) {
+ changes.add(elementParticipants[i].createChange(new SubProgressMonitor(pm, 1)));
+ }
+ for (int i= 0; i < fDerivedParticipants.length; i++) {
+ changes.add(fDerivedParticipants[i].createChange(new SubProgressMonitor(pm, 1)));
+ }
+ return new DelegatingValidationStateChange((Change[]) changes.toArray(new Change[changes.size()]));
+ }
+
+ /**
+ * Adapts the refactoring to the given type. The adapter is resolved
+ * as follows:
+ *
+ * - the refactoring itself is checked whether it is an instance
+ * of the requested type.
+ * - its processor is checked whether it is an instance of the
+ * requested type.
+ * - the request is delegated to the super class.
+ *
+ *
+ * @return the requested adapter or null
if no adapter
+ * exists.
+ */
+ public Object getAdapter(Class clazz) {
+ if (clazz.isInstance(this))
+ return this;
+ if (clazz.isInstance(getProcessor()))
+ return getProcessor();
+ return super.getAdapter(clazz);
+ }
+
+ /* non java-doc
+ * for debugging only
+ */
+ public String toString() {
+ return getName();
+ }
+
+ //---- Helper methods ---------------------------------------------------------------------
+
+ private CheckConditionsContext createCheckConditionsContext() throws CoreException {
+ CheckConditionsContext result= new CheckConditionsContext();
+ IConditionChecker checker= new ValidateEditChecker(null);
+ result.add(checker);
+ return result;
+
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ProcessorDescriptor.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ProcessorDescriptor.java
new file mode 100644
index 00000000000..e7068710bd4
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ProcessorDescriptor.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2003 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionConverter;
+import org.eclipse.core.expressions.ExpressionTagNames;
+import org.eclipse.core.expressions.IEvaluationContext;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+public class ProcessorDescriptor {
+
+ private IConfigurationElement fConfigurationElement;
+
+ private static final String ID= "id"; //$NON-NLS-1$
+ private static final String OVERRIDE= "override"; //$NON-NLS-1$
+ private static final String CLASS= "class"; //$NON-NLS-1$
+
+ public ProcessorDescriptor(IConfigurationElement element) {
+ fConfigurationElement= element;
+ }
+
+ public String getId() {
+ return fConfigurationElement.getAttribute(ID);
+ }
+
+ public boolean overrides() {
+ return fConfigurationElement.getAttribute(OVERRIDE) != null;
+ }
+
+ public String getOverrideId() {
+ return fConfigurationElement.getAttribute(OVERRIDE);
+ }
+
+ public boolean matches(IEvaluationContext context) throws CoreException {
+ Assert.isNotNull(context);
+ IConfigurationElement[] configElements= fConfigurationElement.getChildren(ExpressionTagNames.ENABLEMENT);
+ IConfigurationElement enablement= configElements.length > 0 ? configElements[0] : null;
+ if (enablement != null) {
+ Expression exp= ExpressionConverter.getDefault().perform(enablement);
+ return (convert(exp.evaluate(context)));
+ }
+ return false;
+ }
+
+ public RefactoringProcessor createProcessor() throws CoreException {
+ return (RefactoringProcessor)fConfigurationElement.createExecutableExtension(CLASS);
+ }
+
+ private boolean convert(EvaluationResult eval) {
+ if (eval == EvaluationResult.FALSE)
+ return false;
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ * For debugging purpose only
+ */
+ public String toString() {
+ return "Processor: " + getId(); //$NON-NLS-1$
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RefactoringParticipant.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RefactoringParticipant.java
new file mode 100644
index 00000000000..0ea253d2599
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RefactoringParticipant.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.ltk.core.refactoring.Change;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+
+public abstract class RefactoringParticipant {
+
+ private RefactoringProcessor fProcessor;
+
+ /**
+ * Sets the copy participant with the given processor. The processor
+ * can only be set ones. If this method is called a second time an assertion
+ * failure will be generated.
+ *
+ * @param processor the processor that is associated with this
+ * participant
+ */
+ protected void setProcessor(RefactoringProcessor processor) {
+ Assert.isNotNull(processor);
+ Assert.isTrue(fProcessor == null);
+ fProcessor= processor;
+ }
+
+ /**
+ * Returns the processor that is associated with this participant.
+ *
+ * @return the processor that is associated with this participant
+ */
+ public RefactoringProcessor getProcessor() {
+ return fProcessor;
+ }
+
+ public abstract void initialize(RefactoringProcessor processor, Object element) throws CoreException;
+
+ public abstract boolean isApplicable() throws CoreException;
+
+ public abstract RefactoringStatus checkInitialConditions(IProgressMonitor pm, CheckConditionsContext context) throws CoreException;
+
+ public abstract RefactoringStatus checkFinalConditions(IProgressMonitor pm, CheckConditionsContext context) throws CoreException;
+
+ public abstract Change createChange(IProgressMonitor pm) throws CoreException;
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RefactoringProcessor.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RefactoringProcessor.java
new file mode 100644
index 00000000000..8eb6889543e
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RefactoringProcessor.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2003 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.PlatformObject;
+
+import org.eclipse.ltk.core.refactoring.Change;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+
+public abstract class RefactoringProcessor extends PlatformObject {
+
+ private static final RefactoringParticipant[] EMPTY_PARTICIPANT_ARRAY= new RefactoringParticipant[0];
+
+ public abstract Object[] getElements();
+
+ public abstract String getIdentifier();
+
+ public abstract String getProcessorName();
+
+ public abstract int getStyle();
+
+ public abstract boolean isApplicable() throws CoreException;
+
+ public abstract RefactoringStatus checkInitialConditions(IProgressMonitor pm, CheckConditionsContext context) throws CoreException;
+
+ public abstract RefactoringStatus checkFinalConditions(IProgressMonitor pm, CheckConditionsContext context) throws CoreException;
+
+ public abstract Change createChange(IProgressMonitor pm) throws CoreException;
+
+ /**
+ * Returns an array of derived participants. There are two different flavours of
+ * derived participants that should be added via this hook method:
+ *
+ * - participants listening to changes of derived elements. For example if
+ * a Java field gets renamed corresponding setter and getters methods are
+ * renamed as well. The setter and getter methods are considered as
+ * derived elements and the corresponding participants should be added
+ * via this hook.
+ * - participants listening to changes of a domain model different than the
+ * one that gets manipulated, but changed as a "side effect" of the
+ * refactoring. For example, renaming a package moves all its files to a
+ * different folder. If the package contains a HTML file then the rename
+ * package processor is supposed to load all move HTML file participants
+ * via this hook.
+ *
+ *
+ * Implementors are responsible to initialize the created participants with the
+ * right arguments. The method is called after {@link #checkFinalConditions} has
+ * been called on the processor itself.
+ *
+ *
+ * This default implementation returns an empty array.
+ *
+ *
+ * @return an array of derived participants
+ *
+ * @throws CoreException if creating or loading of the participants failed
+ */
+ public RefactoringParticipant[] loadDerivedParticipants() throws CoreException {
+ return EMPTY_PARTICIPANT_ARRAY;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RefactoringStyles.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RefactoringStyles.java
new file mode 100644
index 00000000000..a22fc346033
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RefactoringStyles.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2003 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+
+public final class RefactoringStyles {
+
+ public static final int NONE= 0;
+ public static final int NEEDS_PREVIEW= 1 << 0;
+ public static final int FORCE_PREVIEW= 1 << 1;
+ public static final int NEEDS_PROGRESS= 1 << 2;
+
+ private RefactoringStyles() {
+ // no instance
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RenameArguments.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RenameArguments.java
new file mode 100644
index 00000000000..4d2ec50490f
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RenameArguments.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+/**
+ * Rename arguments describes the data that a processor
+ * provides to its rename participants.
+ *
+ * @since 3.0
+ */
+public class RenameArguments {
+
+ private String fNewName;
+ private boolean fUpdateReferences;
+
+ /**
+ * Creates new rename arguments.
+ *
+ * @param newName the new name of the element to be renamed
+ * @param updateReferences true
if reference
+ * updating is requested; false
otherwise
+ */
+ public RenameArguments(String newName, boolean updateReferences) {
+ Assert.isNotNull(newName);
+ fNewName= newName;
+ fUpdateReferences= updateReferences;
+ }
+
+ /**
+ * Returns the new element name.
+ *
+ * @return the new element name
+ */
+ public String getNewName() {
+ return fNewName;
+ }
+
+ /**
+ * Returns whether reference updating is requested or not.
+ *
+ * @return returns true
if reference
+ * updating is requested; false
otherwise
+ */
+ public boolean getUpdateReferences() {
+ return fUpdateReferences;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RenameParticipant.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RenameParticipant.java
new file mode 100644
index 00000000000..06aac613f05
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RenameParticipant.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2003 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+public abstract class RenameParticipant extends RefactoringParticipant {
+
+ private RenameArguments fArguments;
+
+ public void setArguments(RenameArguments arguments) {
+ Assert.isNotNull(arguments);
+ fArguments= arguments;
+ }
+
+ public RenameArguments getArguments() {
+ return fArguments;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RenameProcessor.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RenameProcessor.java
new file mode 100644
index 00000000000..4946042665b
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RenameProcessor.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2003 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * A rename processor is a special refactoring processor to support
+ * participating in rename refactorings. A rename processor is responsible
+ * for actual renaming the element to be refactored. Additionally the
+ * processor can update reference which are part of the same domain as the
+ * element to be renamed. For example a processor to rename a Java field
+ * can also update all references to that field found in Java files.
+ *
+ * A rename processor is also responsible to load participants that want
+ * to participate in a rename refactoring.
+ *
+ *
+ * @since 3.0
+ */
+public abstract class RenameProcessor extends RefactoringProcessor {
+
+ private int fStyle;
+ private SharableParticipants fSharedParticipants= new SharableParticipants();
+
+ protected RenameProcessor() {
+ fStyle= RefactoringStyles.NEEDS_PREVIEW;
+ }
+
+ protected RenameProcessor(int style) {
+ fStyle= style;
+ }
+
+ public int getStyle() {
+ return fStyle;
+ }
+
+ /**
+ * Forwards the current rename arguments to the passed participant.
+ *
+ * @param participant the participant to set the arguments to
+ *
+ * @throws CoreException if the arguments can't be set
+ */
+ public void setArgumentsTo(RenameParticipant participant) throws CoreException {
+ participant.setArguments(getArguments());
+ }
+
+ /**
+ * Returns the participants that participate in the rename of the element. The
+ * method is called after {@link #checkInitialConditions} has been called on the
+ * processor itself.
+ *
+ * The arguments are set to the participants by the processor via the call
+ * {@link RenameParticipant#setArguments(RenameArguments)}. They are set
+ * before {@link #checkFinalConditions}is called on the participants.
+ *
+ * @return an array of rename participants
+ *
+ * @throws CoreException if creating or loading of the participants failed
+ */
+ public abstract RenameParticipant[] loadElementParticipants() throws CoreException;
+
+ /**
+ * Returns the shared participants. ????
+ *
+ * @return
+ */
+ protected SharableParticipants getSharedParticipants() {
+ return fSharedParticipants;
+ }
+
+ /**
+ * Returns the arguments of the rename.
+ *
+ * @return the rename arguments
+ */
+ protected RenameArguments getArguments() {
+ return new RenameArguments(getNewElementName(), getUpdateReferences());
+ }
+
+ /**
+ * Returns the new name of the element to be renamed. The
+ * method must not return null
.
+ *
+ * @return the new element name.
+ */
+ protected abstract String getNewElementName();
+
+ /**
+ * Returns whether reference updating is requested or not.
+ *
+ * @return whether reference updating is requested or not
+ */
+ protected abstract boolean getUpdateReferences();
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RenameRefactoring.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RenameRefactoring.java
new file mode 100644
index 00000000000..97fa6ec59f3
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/RenameRefactoring.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2003 International Business Machines Corp. and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+
+/**
+ * A generic rename refactoring. The actual refactoring is done
+ * by the rename processor passed to the constructor.
+ *
+ * @since 3.0
+ */
+public class RenameRefactoring extends ProcessorBasedRefactoring {
+
+ private RenameProcessor fProcessor;
+ private RenameParticipant[] fElementParticipants;
+
+ /**
+ * Creates a new rename refactoring with the given rename processor.
+ *
+ * @param processor the rename processor
+ */
+ public RenameRefactoring(RenameProcessor processor) {
+ Assert.isNotNull(processor);
+ fProcessor= processor;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public RefactoringProcessor getProcessor() {
+ return fProcessor;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected RefactoringParticipant[] getElementParticipants(boolean setArguments) throws CoreException {
+ if (fElementParticipants == null)
+ fElementParticipants= fProcessor.loadElementParticipants();
+ if (setArguments) {
+ for (int i= 0; i < fElementParticipants.length; i++) {
+ fProcessor.setArgumentsTo(fElementParticipants[i]);
+ }
+ }
+ RefactoringParticipant[]result= new RefactoringParticipant[fElementParticipants.length];
+ for (int i= 0; i < result.length; i++) {
+ result[i]= fElementParticipants[i];
+ }
+ return result;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/SharableParticipants.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/SharableParticipants.java
new file mode 100644
index 00000000000..06173b74946
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/SharableParticipants.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SharableParticipants {
+
+ private Map fMap= new HashMap();
+
+ /* package */ void put(ParticipantDescriptor descriptor, RefactoringParticipant participant) {
+ fMap.put(descriptor, participant);
+ }
+ /* package */ RefactoringParticipant get(ParticipantDescriptor descriptor) {
+ return (RefactoringParticipant)fMap.get(descriptor);
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ToDo.txt b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ToDo.txt
new file mode 100644
index 00000000000..5cf8a53b9a5
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ToDo.txt
@@ -0,0 +1,107 @@
+- remove getElement from participant interface.
+- allow sharing of participants for different element types.
+
+- object state. Implement bean object state interface.
+- how to implement special web type rename that renames interface and implementation.
+ o provide a special processor that overrides normal Java processor if project
+ nature is webnature. This means processor gets scopeState as well.
+
+- package rename. At end we delete an empty folder. Should we sent out a folder delete
+ modification. If so participants have to know that the folder doesn't have any children
+ upon deletion, but it might have some upon precondition checking. So for resource
+ modifications we have to describe some sort of postcondition. For example: folder
+ will be empty on deletion. Can be derived from the ResourceModifications object.
+
+- IRefactoringProcessor should not have a method getResourceModification since there
+ might be refactorings which don't modifiy resources. For example a database only
+ application might want to describe high level database operations as low level
+ SQL ops.
+
+- what happens if a web plug-in for some reason registers on resource move and on
+ package rename. Then it might clash if the package rename also tries to handle
+ the move. One argument is that the plug-in knows about its participants and can
+ avoid this in code. Another option is that a participant can specify if it is
+ interested in the comupted resource modifications. Can be a property for some
+ state XML element.
+
+- handling of UNKNOWN paroperty:
+ o throw exception
+ o pass to caller
+ currently it is turned into true which is the incorrect thing to do. It must be
+ false anyway.
+
+- ISharedParticipant and propagating data to participant. That doesn't wortk for the
+ current implementation. SetNewName and other methods must have an additional object
+ parameter. Best is to split this into IShared and INonShared participants.
+
+- Source folder and compilation unit processors object state attribute can be simplified
+ in the following way:
+
+
+
+
+- XML expression must support arrays of elements. For example we want to be able
+ to move more than one method to a different class. This effects the objectState
+ XML element.
+
+- more than one processor is available: The preferred processor can't be remembered
+ based on the type of the element, since the XML expression can be more complex. So
+ the registry must store the preferred user processor based on the list of picked
+ processors. If it is the same has been computed for the element in question than
+ the preferred one can be used. Otherwise the user has to be asked.
+
+- property tester must assumes that projects with no nature have a fake simple nature
+ called "org.eclipse.core.resource.simpleNature". Otherwise the user has to specify the
+ empty nature string in XML.
+
+- THE LRU optimazation only works for elements which have a processor. If no processor
+ is available we always check all rename processor which can be many. We need some
+ other optimazations as well.
+
+- determining the participants must be delegated to the processor. Otherwise it is not
+ possible to chain processor. Nor is it possible to introduce a JavaModification object
+ (similar to ResourceModifications) since the refactoring itself can't be extended.
+
+- processors and participants should derive from PlatformObject if the implement IAdaptable
+
+- we should remove the affected project test from the participants and force them to
+ specify a language the are working on. The language computer then takes a set of
+ projects and computes the effected languages. This will be consistent with what we do
+ for processors.
+
+- rename processor: how do we handle rename polymorphical for renaming temps. This might
+ be a special editor problem. May be we don't allow contributing to temp renames.
+
+======================================= UI ===============================================
+
+- UI: Label and image of preview viewer. Must be determined by the change element
+ structor creator.
+
+- NeedsPane flag on previewer ??
+
+- Make pane handling consistent in Error and Preview. In error the pane is for free
+ in preview the viewer has to provide the pane.
+
+- Composite change in preview tree. Strip away root composite that have only one child.
+
+- Error and Preview page need customizable help id.
+
+- Refactoring Wizard Page: can't provide dialog settings. Too high up in the hierarchy.
+
+- Wizard should be able to disbale preview. To do so processors and participants must
+ signal if they want to show a preview. Problem is that we don't know all participants
+ upfront. So the processor has to decide this.
+
+- RenameRefactoringAction has a hard cast to rename method processor to check for the
+ virtual method case.
+
+- Currently all refactorings require a save of modiifed resources before the get executed.
+ This is necessary due to undo and search infrastructure. We have to find a better solution
+ for this since we can't assume that saving resources is the right thing to do.
+
+=================================== Rename ================================================
+- rename a Java project must be a participant since a project can have more than
+ one nature. This means we double code from core and there will be different deltas.
\ No newline at end of file
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ValidateEditChecker.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ValidateEditChecker.java
new file mode 100644
index 00000000000..59c6fbe8c12
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/participants/ValidateEditChecker.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring.participants;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+import org.eclipse.ltk.internal.core.refactoring.Assert;
+import org.eclipse.ltk.internal.core.refactoring.Resources;
+
+/**
+ * A validate edit checker is a shared checker to collect files
+ * to be validated all at once.
+ *
+ * @since 3.0
+ */
+public class ValidateEditChecker implements IConditionChecker {
+
+ private List fFiles= new ArrayList();
+ private Object fContext;
+
+ /**
+ * The context passed to the validate edit call.
+ *
+ * @param context the context passed to the validate edit call
+ */
+ public ValidateEditChecker(Object context) {
+ fContext= context;
+ }
+
+ /**
+ * Adds the given file to this checker.
+ *
+ * @param file the file to add
+ */
+ public void addFile(IFile file) {
+ Assert.isNotNull(file);
+ fFiles.add(file);
+ }
+
+ /**
+ * Adds the given array of files.
+ *
+ * @param files the array of files to add
+ */
+ public void addFiles(IFile[] files) {
+ Assert.isNotNull(files);
+ fFiles.addAll(Arrays.asList(files));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public RefactoringStatus check(IProgressMonitor monitor) throws CoreException {
+ return RefactoringStatus.create(
+ Resources.makeCommittable(
+ (IResource[]) fFiles.toArray(new IResource[fFiles.size()]), fContext));
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/Assert.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/Assert.java
new file mode 100644
index 00000000000..c08778009a3
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/Assert.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.internal.core.refactoring;
+
+/**
+ * Assert
is useful for for embedding runtime sanity checks
+ * in code.
+ * The predicate methods all test a condition and throw some
+ * type of unchecked exception if the condition does not hold.
+ *
+ * Assertion failure exceptions, like most runtime exceptions, are
+ * thrown when something is misbehaving. Assertion failures are invariably
+ * unspecified behavior; consequently, clients should never rely on
+ * these being thrown (and certainly should not being catching them
+ * specifically).
+ *
+ */
+public final class Assert {
+
+ /* This class is not intended to be instantiated. */
+ private Assert() {
+ // not allowed
+ }
+ /** Asserts that an argument is legal. If the given boolean is
+ * not true
, an IllegalArgumentException
+ * is thrown.
+ *
+ * @param expression the outcode of the check
+ * @return true
if the check passes (does not return
+ * if the check fails)
+ * @exception IllegalArgumentException if the legality test failed
+ */
+ public static boolean isLegal(boolean expression) {
+ return isLegal(expression, ""); //$NON-NLS-1$
+ }
+ /** Asserts that an argument is legal. If the given boolean is
+ * not true
, an IllegalArgumentException
+ * is thrown.
+ * The given message is included in that exception, to aid debugging.
+ *
+ * @param expression the outcode of the check
+ * @param message the message to include in the exception
+ * @return true
if the check passes (does not return
+ * if the check fails)
+ * @exception IllegalArgumentException if the legality test failed
+ */
+ public static boolean isLegal(boolean expression, String message) {
+ if (!expression)
+ throw new IllegalArgumentException(message);
+ return expression;
+ }
+ /** Asserts that the given object is not null
. If this
+ * is not the case, some kind of unchecked exception is thrown.
+ *
+ * @param object the value to test
+ * @exception IllegalArgumentException if the object is null
+ */
+ public static void isNotNull(Object object) {
+ isNotNull(object, ""); //$NON-NLS-1$
+ }
+ /** Asserts that the given object is not null
. If this
+ * is not the case, some kind of unchecked exception is thrown.
+ * The given message is included in that exception, to aid debugging.
+ *
+ * @param object the value to test
+ * @param message the message to include in the exception
+ * @exception IllegalArgumentException if the object is null
+ */
+ public static void isNotNull(Object object, String message) {
+ if (object == null)
+ throw new AssertionFailedException("null argument:" + message); //$NON-NLS-1$
+ }
+ /** Asserts that the given boolean is true
. If this
+ * is not the case, some kind of unchecked exception is thrown.
+ *
+ * @param expression the outcode of the check
+ * @return true
if the check passes (does not return
+ * if the check fails)
+ */
+ public static boolean isTrue(boolean expression) {
+ return isTrue(expression, ""); //$NON-NLS-1$
+ }
+ /** Asserts that the given boolean is true
. If this
+ * is not the case, some kind of unchecked exception is thrown.
+ * The given message is included in that exception, to aid debugging.
+ *
+ * @param expression the outcode of the check
+ * @param message the message to include in the exception
+ * @return true
if the check passes (does not return
+ * if the check fails)
+ */
+ public static boolean isTrue(boolean expression, String message) {
+ if (!expression)
+ throw new AssertionFailedException("assertion failed: " + message); //$NON-NLS-1$
+ return expression;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/AssertionFailedException.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/AssertionFailedException.java
new file mode 100644
index 00000000000..86a39c42eeb
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/AssertionFailedException.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.internal.core.refactoring;
+
+/**
+ * AssertionFailedException
is a runtime exception thrown
+ * by some of the methods in Assert
.
+ *
+ * This class is not declared public to prevent some misuses; programs that catch
+ * or otherwise depend on assertion failures are susceptible to unexpected
+ * breakage when assertions in the code are added or removed.
+ *
+ */
+/* package */
+class AssertionFailedException extends RuntimeException {
+ /**
+ * Constructs a new exception.
+ */
+ public AssertionFailedException() {
+ super();
+ }
+ /** Constructs a new exception with the given message.
+ */
+ public AssertionFailedException(String detail) {
+ super(detail);
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/BufferValidationState.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/BufferValidationState.java
new file mode 100644
index 00000000000..21a89068e17
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/BufferValidationState.java
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.internal.core.refactoring;
+
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+
+import org.eclipse.core.filebuffers.FileBuffers;
+import org.eclipse.core.filebuffers.IFileBuffer;
+import org.eclipse.core.filebuffers.IFileBufferListener;
+import org.eclipse.core.filebuffers.ITextFileBuffer;
+import org.eclipse.core.filebuffers.ITextFileBufferManager;
+
+import org.eclipse.jface.text.DocumentEvent;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentListener;
+
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+
+
+public abstract class BufferValidationState {
+
+ protected IFile fFile;
+ protected boolean fExisted;
+
+ public static BufferValidationState create(IFile file) {
+ ITextFileBuffer buffer= getBuffer(file);
+ if (buffer == null) {
+ return new SavedBufferValidationState(file);
+ } else if (buffer.isDirty()) {
+ return new DirtyBufferValidationState(file);
+ } else {
+ return new SavedBufferValidationState(file);
+ }
+ }
+
+ public RefactoringStatus isValid() {
+ if (!fExisted) {
+ if (fFile.exists())
+ return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.getFormattedString(
+ "TextChanges.error.existing", //$NON-NLS-1$
+ fFile.getFullPath().toString()
+ ));
+ } else {
+ if (!fFile.exists())
+ return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.getFormattedString(
+ "TextChanges.error.not_existing", //$NON-NLS-1$
+ fFile.getFullPath().toString()
+ ));
+ }
+ return new RefactoringStatus();
+ }
+
+ public void dispose() {
+ }
+
+
+ protected BufferValidationState(IFile file) {
+ fFile= file;
+ fExisted= file.exists();
+ }
+
+ protected IDocument getDocument() {
+ ITextFileBuffer buffer= getBuffer(fFile);
+ if (buffer == null)
+ return null;
+ return buffer.getDocument();
+
+ }
+
+ protected static boolean isDirty(IFile file) {
+ ITextFileBuffer buffer= getBuffer(file);
+ if (buffer == null)
+ return false;
+ return buffer.isDirty();
+ }
+
+ protected static ITextFileBuffer getBuffer(IFile file) {
+ ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
+ IPath path= file.getFullPath();
+ ITextFileBuffer buffer= manager.getTextFileBuffer(path);
+ return buffer;
+ }
+}
+
+class DirtyBufferValidationState extends BufferValidationState {
+
+ private IDocumentListener fDocumentListener;
+ private FileBufferListener fFileBufferListener;
+ private boolean fChanged;
+ private long fModificationStamp= IResource.NULL_STAMP;
+
+ class DocumentChangedListener implements IDocumentListener {
+ public void documentAboutToBeChanged(DocumentEvent event) {
+ }
+ public void documentChanged(DocumentEvent event) {
+ DirtyBufferValidationState.this.documentChanged();
+ }
+ }
+
+ class FileBufferListener implements IFileBufferListener {
+ public void bufferCreated(IFileBuffer buffer) {
+ if (buffer.equals(getBuffer(fFile))) {
+ if (fDocumentListener == null)
+ fDocumentListener= new DocumentChangedListener();
+ getDocument().addDocumentListener(fDocumentListener);
+ }
+ }
+ public void bufferDisposed(IFileBuffer buffer) {
+ if (fDocumentListener != null && buffer.equals(getBuffer(fFile))) {
+ getDocument().removeDocumentListener(fDocumentListener);
+ fDocumentListener= null;
+ fModificationStamp= fFile.getModificationStamp();
+ }
+ }
+ public void bufferContentAboutToBeReplaced(IFileBuffer buffer) {
+ }
+ public void bufferContentReplaced(IFileBuffer buffer) {
+ }
+ public void stateChanging(IFileBuffer buffer) {
+ }
+ public void dirtyStateChanged(IFileBuffer buffer, boolean isDirty) {
+ }
+ public void stateValidationChanged(IFileBuffer buffer, boolean isStateValidated) {
+ }
+ public void underlyingFileMoved(IFileBuffer buffer, IPath path) {
+ }
+ public void underlyingFileDeleted(IFileBuffer buffer) {
+ }
+ public void stateChangeFailed(IFileBuffer buffer) {
+ }
+ }
+
+
+ public DirtyBufferValidationState(IFile file) {
+ super(file);
+ fFileBufferListener= new FileBufferListener();
+ FileBuffers.getTextFileBufferManager().addFileBufferListener(fFileBufferListener);
+ fDocumentListener= new DocumentChangedListener();
+ getDocument().addDocumentListener(fDocumentListener);
+ }
+
+ public RefactoringStatus isValid() {
+ RefactoringStatus result= super.isValid();
+ if (result.hasFatalError())
+ return result;
+ if (fChanged || (fModificationStamp != IResource.NULL_STAMP && fModificationStamp != fFile.getModificationStamp())) {
+ result.addFatalError(RefactoringCoreMessages.getFormattedString(
+ "TextChanges.error.conent_changed", //$NON-NLS-1$
+ fFile.getFullPath().toString()
+ ));
+ }
+ return result;
+ }
+
+ public void dispose() {
+ if (fFileBufferListener != null) {
+ FileBuffers.getTextFileBufferManager().removeFileBufferListener(fFileBufferListener);
+ }
+ if (fDocumentListener != null) {
+ getDocument().removeDocumentListener(fDocumentListener);
+ }
+ }
+
+ private void documentChanged() {
+ fChanged= true;
+ getDocument().removeDocumentListener(fDocumentListener);
+ FileBuffers.getTextFileBufferManager().removeFileBufferListener(fFileBufferListener);
+ fFileBufferListener= null;
+ fDocumentListener= null;
+ }
+}
+
+class SavedBufferValidationState extends BufferValidationState {
+ private long fModificationStamp;
+
+ public SavedBufferValidationState(IFile file) {
+ super(file);
+ fModificationStamp= file.getModificationStamp();
+ }
+
+ public RefactoringStatus isValid() {
+ RefactoringStatus result= super.isValid();
+ if (result.hasFatalError())
+ return result;
+ if (fModificationStamp != fFile.getModificationStamp()) {
+ result.addFatalError(RefactoringCoreMessages.getFormattedString(
+ "TextChanges.error.conent_changed", //$NON-NLS-1$
+ fFile.getFullPath().toString()
+ ));
+ } else if (fFile.isReadOnly()) {
+ result.addFatalError(RefactoringCoreMessages.getFormattedString(
+ "TextChanges.error.read_only", //$NON-NLS-1$
+ fFile.getFullPath().toString()
+ ));
+ } else if (!fFile.isSynchronized(IResource.DEPTH_ZERO)) {
+ result.addFatalError(RefactoringCoreMessages.getFormattedString(
+ "TextChanges.error.outOfSync", //$NON-NLS-1$
+ fFile.getFullPath().toString()
+ ));
+ } else if (isDirty(fFile)){
+ result.addFatalError(RefactoringCoreMessages.getFormattedString(
+ "TextChanges.error.unsaved_changes", //$NON-NLS-1$
+ fFile.getFullPath().toString()
+ ));
+ }
+ return result;
+ }
+}
+
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/Changes.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/Changes.java
new file mode 100644
index 00000000000..89517fbd2c7
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/Changes.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.internal.core.refactoring;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.core.resources.IFile;
+
+import org.eclipse.jface.text.BadLocationException;
+
+import org.eclipse.ltk.core.refactoring.IRefactoringCoreStatusCodes;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+
+public class Changes {
+
+ public static RefactoringStatus validateModifiesFiles(IFile[] filesToModify) {
+ RefactoringStatus result= new RefactoringStatus();
+ IStatus status= Resources.checkInSync(filesToModify);
+ if (!status.isOK())
+ result.merge(RefactoringStatus.create(status));
+ status= Resources.makeCommittable(filesToModify, null);
+ if (!status.isOK())
+ result.merge(RefactoringStatus.create(status));
+ return result;
+ }
+
+ public static CoreException asCoreException(BadLocationException e) {
+ String message= e.getMessage();
+ if (message == null)
+ message= "BadLocationException"; //$NON-NLS-1$
+ return new CoreException(new Status(IStatus.ERROR, RefactoringCorePlugin.getPluginId(), IRefactoringCoreStatusCodes.BAD_LOCATION, message, e));
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/DelegatingValidationStateChange.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/DelegatingValidationStateChange.java
new file mode 100644
index 00000000000..f81136b685b
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/DelegatingValidationStateChange.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.internal.core.refactoring;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.Platform;
+
+import org.eclipse.ltk.core.refactoring.Change;
+import org.eclipse.ltk.core.refactoring.CompositeChange;
+import org.eclipse.ltk.core.refactoring.IDynamicValidationStateChange;
+import org.eclipse.ltk.core.refactoring.IValidationStateListener;
+
+public class DelegatingValidationStateChange extends CompositeChange implements IDynamicValidationStateChange {
+
+ private IDynamicValidationStateChange[] fDynamicChanges;
+
+ public DelegatingValidationStateChange(Change[] changes) {
+ List dynamic= new ArrayList();
+ addAll(changes);
+ for (int i= 0; i < changes.length; i++) {
+ if (changes[i] instanceof IDynamicValidationStateChange) {
+ dynamic.add(changes[i]);
+ }
+ }
+ fDynamicChanges= (IDynamicValidationStateChange[]) dynamic.toArray(new IDynamicValidationStateChange[dynamic.size()]);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected Change createUndoChange(Change[] childUndos) {
+ return new DelegatingValidationStateChange(childUndos);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void addValidationStateListener(final IValidationStateListener listener) {
+ for (int i= 0; i < fDynamicChanges.length; i++) {
+ final int index= i;
+ final IDynamicValidationStateChange dc= fDynamicChanges[i];
+ Platform.run(new ISafeRunnable() {
+ public void run() throws Exception {
+ if (dc != null)
+ dc.addValidationStateListener(listener);
+ }
+ public void handleException(Throwable e) {
+ fDynamicChanges[index]= null;
+ RefactoringCorePlugin.logRemovedListener(e);
+ }
+ });
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removeValidationStateListener(final IValidationStateListener listener) {
+ for (int i= 0; i < fDynamicChanges.length; i++) {
+ final int index= i;
+ final IDynamicValidationStateChange dc= fDynamicChanges[i];
+ Platform.run(new ISafeRunnable() {
+ public void run() throws Exception {
+ if (dc != null)
+ dc.removeValidationStateListener(listener);
+ }
+ public void handleException(Throwable e) {
+ fDynamicChanges[index]= null;
+ RefactoringCorePlugin.logRemovedListener(e);
+ }
+ });
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void aboutToPerformChange(final Change change) {
+ for (int i= 0; i < fDynamicChanges.length; i++) {
+ final int index= i;
+ final IDynamicValidationStateChange dc= fDynamicChanges[i];
+ Platform.run(new ISafeRunnable() {
+ public void run() throws Exception {
+ if (dc != null)
+ dc.aboutToPerformChange(change);
+ }
+ public void handleException(Throwable e) {
+ fDynamicChanges[index]= null;
+ RefactoringCorePlugin.logRemovedListener(e);
+ }
+ });
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void changePerformed(final Change change, final Change undo, final Exception e) {
+ for (int i= 0; i < fDynamicChanges.length; i++) {
+ final int index= i;
+ final IDynamicValidationStateChange dc= fDynamicChanges[i];
+ Platform.run(new ISafeRunnable() {
+ public void run() throws Exception {
+ if (dc != null)
+ dc.changePerformed(change, undo, e);
+ }
+ public void handleException(Throwable e) {
+ fDynamicChanges[index]= null;
+ RefactoringCorePlugin.logRemovedListener(e);
+ }
+ });
+ }
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/ListenerList.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/ListenerList.java
new file mode 100644
index 00000000000..d5066a2104f
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/ListenerList.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.internal.core.refactoring;
+
+/**
+ * Local copy of org.eclipse.jface.ListenerList
+ */
+public class ListenerList {
+
+ static {
+ //XXX: 1GCQD0A: ITPVCM:WIN2000 - ListenerList should be part of a core project
+ }
+
+ /**
+ * The initial capacity of the list. Always >= 1.
+ */
+ private int capacity;
+
+ /**
+ * The current number of listeners.
+ * Maintains invariant: 0 <= size <= listeners.length.
+ */
+ private int size;
+
+ /**
+ * The list of listeners. Initially null
but initialized
+ * to an array of size capacity the first time a listener is added.
+ * Maintains invariant: listeners != null IFF size != 0
+ */
+ private Object[] listeners= null;
+
+ /**
+ * The empty array singleton instance, returned by getListeners()
+ * when size == 0.
+ */
+ private static final Object[] EmptyArray= new Object[0];
+
+ /**
+ * Creates a listener list with an initial capacity of 3.
+ */
+ public ListenerList() {
+ this(3);
+ }
+
+ /**
+ * Creates a listener list with the given initial capacity.
+ *
+ * @param capacity the number of listeners which this list can initially accept
+ * without growing its internal representation; must be at least 1
+ */
+ public ListenerList(int capacity) {
+ Assert.isTrue(capacity >= 1);
+ this.capacity= capacity;
+ }
+
+ /**
+ * Adds the given listener to this list. Has no effect if an identical listener
+ * is already registered.
+ *
+ * @param listener the listener
+ */
+ public void add(Object listener) {
+ Assert.isNotNull(listener);
+ if (size == 0) {
+ listeners= new Object[capacity];
+ } else {
+ // check for duplicates using identity
+ for (int i= 0; i < size; ++i) {
+ if (listeners[i] == listener) {
+ return;
+ }
+ }
+ // grow array if necessary
+ if (size == listeners.length) {
+ System.arraycopy(listeners, 0, listeners= new Object[size * 2 + 1], 0, size);
+ }
+ }
+ listeners[size++]= listener;
+ }
+
+ /**
+ * Returns an array containing all the registered listeners.
+ * The resulting array is unaffected by subsequent adds or removes.
+ * If there are no listeners registered, the result is an empty array
+ * singleton instance (no garbage is created).
+ * Use this method when notifying listeners, so that any modifications
+ * to the listener list during the notification will have no effect on the
+ * notification itself.
+ *
+ * @return the list of registered listeners
+ */
+ public Object[] getListeners() {
+ if (size == 0)
+ return EmptyArray;
+ Object[] result= new Object[size];
+ System.arraycopy(listeners, 0, result, 0, size);
+ return result;
+ }
+
+ /**
+ * Returns whether this listener list is empty.
+ *
+ * @return true
if there are no registered listeners, and
+ * false
otherwise
+ */
+ public boolean isEmpty() {
+ return size == 0;
+ }
+
+ /**
+ * Removes the given listener from this list. Has no effect if an identical
+ * listener was not already registered.
+ *
+ * @param listener the listener
+ */
+ public void remove(Object listener) {
+ Assert.isNotNull(listener);
+ for (int i= 0; i < size; ++i) {
+ if (listeners[i] == listener) {
+ if (--size == 0) {
+ listeners= new Object[1];
+ } else {
+ if (i < size) {
+ listeners[i]= listeners[size];
+ }
+ listeners[size]= null;
+ }
+ return;
+ }
+ }
+ }
+
+ /**
+ * Returns the number of registered listeners.
+ *
+ * @return the number of registered listeners
+ */
+ public int size() {
+ return size;
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/RefactoringCoreMessages.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/RefactoringCoreMessages.java
new file mode 100644
index 00000000000..093f8cb20ab
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/RefactoringCoreMessages.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.internal.core.refactoring;
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class RefactoringCoreMessages {
+
+ private static final String BUNDLE_NAME= "org.eclipse.ltk.internal.core.refactoring.RefactoringCoreMessages";//$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE= ResourceBundle.getBundle(BUNDLE_NAME);
+
+ private RefactoringCoreMessages() {
+ }
+
+ public static String getString(String key) {
+ try {
+ return RESOURCE_BUNDLE.getString(key);
+ } catch (MissingResourceException e) {
+ return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$
+ }
+ }
+
+ public static String getFormattedString(String key, String arg) {
+ try{
+ return MessageFormat.format(RESOURCE_BUNDLE.getString(key), new String[] { arg });
+ } catch (MissingResourceException e) {
+ return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$
+ }
+ }
+
+ public static String getFormattedString(String key, Object arg) {
+ try{
+ return MessageFormat.format(RESOURCE_BUNDLE.getString(key), new Object[] { arg });
+ } catch (MissingResourceException e) {
+ return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$
+ }
+ }
+
+ public static String getFormattedString(String key, String[] args) {
+ try{
+ return MessageFormat.format(RESOURCE_BUNDLE.getString(key), args);
+ } catch (MissingResourceException e) {
+ return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$
+ }
+ }
+
+ public static String getFormattedString(String key, Object[] args) {
+ try{
+ return MessageFormat.format(RESOURCE_BUNDLE.getString(key), args);
+ } catch (MissingResourceException e) {
+ return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/RefactoringCoreMessages.properties b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/RefactoringCoreMessages.properties
new file mode 100644
index 00000000000..393404ebe60
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/RefactoringCoreMessages.properties
@@ -0,0 +1,32 @@
+###############################################################################
+# Copyright (c) 2000, 2004 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Common Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/cpl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+
+RefactoringCorePlugin.internal_error=Internal Error
+RefactoringCorePlugin.listener_removed=Listener removed due to the following exception
+
+Resources.outOfSyncResources= Some resources are out of sync
+Resources.outOfSync= Resource ''{0}'' is out of sync with file system.
+Resources.modifiedResources= There are modified resources
+Resources.fileModified= File ''{0}'' has been modified since the beginning of the operation
+
+NullChange.name= No operation change
+
+TextChanges.error.existing=The file ''{1}'' exists but it should not.
+TextChanges.error.not_existing=''{0}'' does not exist anymore
+TextChanges.error.conent_changed=The content of ''{0}'' has changed
+TextChanges.error.unsaved_changes=The file ''{0}'' has unsaved changes
+TextChanges.error.read_only=The file ''{0}'' is read-only
+TextChanges.error.outOfSync= The file ''{0}'' is out of sync with the underlying file system
+TextChanges.error.document_content_changed= The content of the document has changed
+
+CheckConditionContext.error.checker_exists= A checker of type ''{0}'' already exists
+
+CompositeChange.name=Composite Change
\ No newline at end of file
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/RefactoringCorePlugin.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/RefactoringCorePlugin.java
new file mode 100644
index 00000000000..1eb9a5e4e54
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/RefactoringCorePlugin.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.internal.core.refactoring;
+
+import org.eclipse.core.runtime.IPluginDescriptor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.core.resources.ResourcesPlugin;
+
+import org.eclipse.ltk.core.refactoring.IRefactoringCoreStatusCodes;
+
+public class RefactoringCorePlugin extends Plugin {
+
+ private static RefactoringCorePlugin fgDefault;
+
+ public RefactoringCorePlugin(IPluginDescriptor descriptor) {
+ super(descriptor);
+ fgDefault= this;
+ }
+
+ public static RefactoringCorePlugin getDefault() {
+ return fgDefault;
+ }
+
+ public static String getPluginId() {
+ return getDefault().getDescriptor().getUniqueIdentifier();
+ }
+
+ public static void log(IStatus status) {
+ getDefault().getLog().log(status);
+ }
+
+ public static void log(Throwable t) {
+ IStatus status= new Status(
+ IStatus.ERROR, getPluginId(),
+ IRefactoringCoreStatusCodes.INTERNAL_ERROR,
+ RefactoringCoreMessages.getString("RefactoringCorePlugin.internal_error"), //$NON-NLS-1$
+ t);
+ ResourcesPlugin.getPlugin().getLog().log(status);
+ }
+
+ public static void logRemovedListener(Throwable t) {
+ IStatus status= new Status(
+ IStatus.ERROR, getPluginId(),
+ IRefactoringCoreStatusCodes.INTERNAL_ERROR,
+ RefactoringCoreMessages.getString("RefactoringCorePlugin.listener_removed"), //$NON-NLS-1$
+ t);
+ ResourcesPlugin.getPlugin().getLog().log(status);
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/Resources.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/Resources.java
new file mode 100644
index 00000000000..92a93477109
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/Resources.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.internal.core.refactoring;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceStatus;
+import org.eclipse.core.resources.ResourcesPlugin;
+
+import org.eclipse.ltk.core.refactoring.IRefactoringCoreStatusCodes;
+
+public class Resources {
+
+ private Resources() {
+ }
+
+ /**
+ * Checks if the given resource is in sync with the underlying file system.
+ *
+ * @param resource the resource to be checked
+ * @return IStatus status describing the check's result. If status.
+ * isOK()
returns true
then the resource is in sync
+ */
+ public static IStatus checkInSync(IResource resource) {
+ return checkInSync(new IResource[] {resource});
+ }
+
+ /**
+ * Checks if the given resources are in sync with the underlying file
+ * system.
+ *
+ * @param resources the resources to be checked
+ * @return IStatus status describing the check's result. If status.
+ * isOK()
returns true
then the resources are in sync
+ */
+ public static IStatus checkInSync(IResource[] resources) {
+ IStatus result= null;
+ for (int i= 0; i < resources.length; i++) {
+ IResource resource= resources[i];
+ if (!resource.isSynchronized(IResource.DEPTH_INFINITE)) {
+ result= addOutOfSync(result, resource);
+ }
+ }
+ if (result != null)
+ return result;
+ return new Status(IStatus.OK, RefactoringCorePlugin.getPluginId(), IStatus.OK, "", null); //$NON-NLS-1$
+ }
+
+ /**
+ * Makes the given resource committable. Committable means that it is
+ * writeable and that its content hasn't changed by calling
+ * validateEdit
for the given resource on IWorkspace.
+ *
+ * @param resource the resource to be checked
+ * @param context the context passed to validateEdit
+ * @return status describing the method's result. If status.isOK()
returns true
then the resources are committable.
+ *
+ * @see org.eclipse.core.resources.IWorkspace#validateEdit(org.eclipse.core.resources.IFile[], java.lang.Object)
+ */
+ public static IStatus makeCommittable(IResource resource, Object context) {
+ return makeCommittable(new IResource[] { resource }, context);
+ }
+
+ /**
+ * Makes the given resources committable. Committable means that all
+ * resources are writeable and that the content of the resources hasn't
+ * changed by calling validateEdit
for a given file on
+ * IWorkspace.
+ *
+ * @param resources the resources to be checked
+ * @param context the context passed to validateEdit
+ * @return IStatus status describing the method's result. If status.
+ * isOK()
returns true
then the add resources are
+ * committable
+ *
+ * @see org.eclipse.core.resources.IWorkspace#validateEdit(org.eclipse.core.resources.IFile[], java.lang.Object)
+ */
+ public static IStatus makeCommittable(IResource[] resources, Object context) {
+ List readOnlyFiles= new ArrayList();
+ for (int i= 0; i < resources.length; i++) {
+ IResource resource= resources[i];
+ if (resource.getType() == IResource.FILE && resource.isReadOnly())
+ readOnlyFiles.add(resource);
+ }
+ if (readOnlyFiles.size() == 0)
+ return new Status(IStatus.OK, RefactoringCorePlugin.getPluginId(), IStatus.OK, "", null); //$NON-NLS-1$
+
+ Map oldTimeStamps= createModificationStampMap(readOnlyFiles);
+ IStatus status= ResourcesPlugin.getWorkspace().validateEdit(
+ (IFile[]) readOnlyFiles.toArray(new IFile[readOnlyFiles.size()]), context);
+ if (!status.isOK())
+ return status;
+
+ IStatus modified= null;
+ Map newTimeStamps= createModificationStampMap(readOnlyFiles);
+ for (Iterator iter= oldTimeStamps.keySet().iterator(); iter.hasNext();) {
+ IFile file= (IFile) iter.next();
+ if (!oldTimeStamps.get(file).equals(newTimeStamps.get(file)))
+ modified= addModified(modified, file);
+ }
+ if (modified != null)
+ return modified;
+ return new Status(IStatus.OK, RefactoringCorePlugin.getPluginId(), IStatus.OK, "", null); //$NON-NLS-1$
+ }
+
+ private static Map createModificationStampMap(List files){
+ Map map= new HashMap();
+ for (Iterator iter= files.iterator(); iter.hasNext(); ) {
+ IFile file= (IFile)iter.next();
+ map.put(file, new Long(file.getModificationStamp()));
+ }
+ return map;
+ }
+
+ private static IStatus addModified(IStatus status, IFile file) {
+ IStatus entry= new Status(
+ IStatus.ERROR, RefactoringCorePlugin.getPluginId(),
+ IRefactoringCoreStatusCodes.VALIDATE_EDIT_CHANGED_CONTENT,
+ RefactoringCoreMessages.getFormattedString("Resources.fileModified", file.getFullPath().toString()), //$NON-NLS-1$
+ null);
+ if (status == null) {
+ return entry;
+ } else if (status.isMultiStatus()) {
+ ((MultiStatus)status).add(entry);
+ return status;
+ } else {
+ MultiStatus result= new MultiStatus(RefactoringCorePlugin.getPluginId(),
+ IRefactoringCoreStatusCodes.VALIDATE_EDIT_CHANGED_CONTENT,
+ RefactoringCoreMessages.getString("Resources.modifiedResources"), null); //$NON-NLS-1$
+ result.add(status);
+ result.add(entry);
+ return result;
+ }
+ }
+
+ private static IStatus addOutOfSync(IStatus status, IResource resource) {
+ IStatus entry= new Status(
+ IStatus.ERROR,
+ ResourcesPlugin.getPlugin().getDescriptor().getUniqueIdentifier(),
+ IResourceStatus.OUT_OF_SYNC_LOCAL,
+ RefactoringCoreMessages.getFormattedString("Resources.outOfSync", resource.getFullPath().toString()), //$NON-NLS-1$
+ null);
+ if (status == null) {
+ return entry;
+ } else if (status.isMultiStatus()) {
+ ((MultiStatus)status).add(entry);
+ return status;
+ } else {
+ MultiStatus result= new MultiStatus(
+ ResourcesPlugin.getPlugin().getDescriptor().getUniqueIdentifier(),
+ IResourceStatus.OUT_OF_SYNC_LOCAL,
+ RefactoringCoreMessages.getString("Resources.outOfSyncResources"), null); //$NON-NLS-1$
+ result.add(status);
+ result.add(entry);
+ return result;
+ }
+ }
+
+ public static String[] getLocationOSStrings(IResource[] resources) {
+ List result= new ArrayList(resources.length);
+ for (int i= 0; i < resources.length; i++) {
+ IPath location= resources[i].getLocation();
+ if (location != null)
+ result.add(location.toOSString());
+ }
+ return (String[]) result.toArray(new String[result.size()]);
+ }
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/TextChanges.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/TextChanges.java
new file mode 100644
index 00000000000..dee903ea1ca
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/TextChanges.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.internal.core.refactoring;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+
+import org.eclipse.core.filebuffers.FileBuffers;
+import org.eclipse.core.filebuffers.ITextFileBuffer;
+import org.eclipse.core.filebuffers.ITextFileBufferManager;
+
+import org.eclipse.jface.text.IDocument;
+
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+
+/**
+ * Helper class for text file changes.
+ */
+public class TextChanges {
+
+ private TextChanges() {
+ // no instance
+ }
+
+ public static IDocument getDocument(IFile file) throws CoreException {
+ ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
+ IPath path= file.getFullPath();
+ ITextFileBuffer buffer= manager.getTextFileBuffer(path);
+ if (buffer == null)
+ return null;
+ return buffer.getDocument();
+
+ }
+
+ public static RefactoringStatus isValid(IFile file, boolean existed, long lastModificationStamp, boolean fSave) throws CoreException {
+ // the file did not exist anymore when initializing the
+ // validation state. In this case we must ensure that it
+ // still doesn't exist.
+ if (!existed) {
+ if (file.exists())
+ return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.getFormattedString(
+ "TextChanges.error.existing", //$NON-NLS-1$
+ file.getFullPath().toString()
+ ));
+ } else {
+ if (!file.exists())
+ return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.getFormattedString(
+ "TextChanges.error.not_existing", //$NON-NLS-1$
+ file.getFullPath().toString()
+ ));
+ if (lastModificationStamp != file.getModificationStamp())
+ return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.getFormattedString(
+ "TextChanges.error.conent_changed", //$NON-NLS-1$
+ file.getFullPath().toString()
+ ));
+ if (file.isReadOnly())
+ return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.getFormattedString(
+ "TextChanges.error.read_only", //$NON-NLS-1$
+ file.getFullPath().toString()
+ ));
+ if (!file.isSynchronized(IResource.DEPTH_ZERO))
+ return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.getFormattedString(
+ "TextChanges.error.outOfSync", //$NON-NLS-1$
+ file.getFullPath().toString()
+ ));
+
+ if (fSave) {
+ ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
+ // Don't connect. We want to check if the file is under modification right now
+ ITextFileBuffer buffer= manager.getTextFileBuffer(file.getFullPath());
+ if (buffer != null && buffer.isDirty()) {
+ return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.getFormattedString(
+ "TextChanges.error.unsaved_changes", //$NON-NLS-1$
+ file.getFullPath().toString()
+ ));
+ }
+ }
+ }
+ return new RefactoringStatus();
+ }
+
+ public static RefactoringStatus isValid(IDocument document, int length) throws CoreException {
+ RefactoringStatus result= new RefactoringStatus();
+ if (length != document.getLength()) {
+ result.addFatalError(RefactoringCoreMessages.getString("TextChanges.error.document_content_changed")); //$NON-NLS-1$
+ }
+ return result;
+ }
+
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/UndoManager.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/UndoManager.java
new file mode 100644
index 00000000000..691b93fa964
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/internal/core/refactoring/UndoManager.java
@@ -0,0 +1,370 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.internal.core.refactoring;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Stack;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.core.resources.ResourcesPlugin;
+
+import org.eclipse.ltk.core.refactoring.Change;
+import org.eclipse.ltk.core.refactoring.IDynamicValidationStateChange;
+import org.eclipse.ltk.core.refactoring.IUndoManager;
+import org.eclipse.ltk.core.refactoring.IUndoManagerListener;
+import org.eclipse.ltk.core.refactoring.IValidationStateListener;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+import org.eclipse.ltk.core.refactoring.ValidationStateChangedEvent;
+
+/**
+ * Default implementation of IUndoManager.
+ */
+public class UndoManager implements IUndoManager {
+
+ private class ValidationStateListener implements IValidationStateListener {
+ public void stateChanged(ValidationStateChangedEvent event) {
+ validationStateChanged(event.getChange());
+ }
+ }
+
+ private Stack fUndoChanges;
+ private Stack fRedoChanges;
+ private Stack fUndoNames;
+ private Stack fRedoNames;
+
+ private ListenerList fListeners;
+
+ private ValidationStateListener fValidationListener;
+
+ /**
+ * Creates a new undo manager with an empty undo and redo stack.
+ */
+ public UndoManager() {
+ flush();
+ fValidationListener= new ValidationStateListener();
+ }
+
+ /*
+ * (Non-Javadoc) Method declared in IUndoManager.
+ */
+ public void addListener(IUndoManagerListener listener) {
+ if (fListeners == null)
+ fListeners= new ListenerList();
+ fListeners.add(listener);
+ }
+
+ /*
+ * (Non-Javadoc) Method declared in IUndoManager.
+ */
+ public void removeListener(IUndoManagerListener listener) {
+ if (fListeners == null)
+ return;
+ fListeners.remove(listener);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void aboutToPerformChange(Change change) {
+ sendAboutToPerformChange(fUndoChanges, change);
+ sendAboutToPerformChange(fRedoChanges, change);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void changePerformed(Change change, Change undo, Exception e) {
+ sendChangePerformed(fUndoChanges, undo, change, e);
+ sendChangePerformed(fRedoChanges, undo, change, e);
+ }
+
+ /*
+ * (Non-Javadoc) Method declared in IUndoManager.
+ */
+ public void aboutToPerformRefactoring() {
+ }
+
+ /*
+ * (Non-Javadoc) Method declared in IUndoManager.
+ */
+ public void refactoringPerformed(boolean success) {
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see IUndoManager#shutdown()
+ */
+ public void shutdown() {
+ }
+
+ /*
+ * (Non-Javadoc) Method declared in IUndoManager.
+ */
+ public void flush() {
+ flushUndo();
+ flushRedo();
+ }
+
+ private void flushUndo() {
+ if (fUndoChanges != null) {
+ removeValidationStateListener(fUndoChanges);
+ sendDispose(fUndoChanges);
+ }
+ fUndoChanges= new Stack();
+ fUndoNames= new Stack();
+ fireUndoStackChanged();
+ }
+
+ private void flushRedo() {
+ if (fRedoChanges != null) {
+ removeValidationStateListener(fRedoChanges);
+ sendDispose(fRedoChanges);
+ }
+ fRedoChanges= new Stack();
+ fRedoNames= new Stack();
+ fireRedoStackChanged();
+ }
+
+ /*
+ * (Non-Javadoc) Method declared in IUndoManager.
+ */
+ public void addUndo(String refactoringName, Change change) {
+ Assert.isNotNull(refactoringName, "refactoring"); //$NON-NLS-1$
+ Assert.isNotNull(change, "change"); //$NON-NLS-1$
+ fUndoNames.push(refactoringName);
+ fUndoChanges.push(change);
+ flushRedo();
+ addValidationStateListener(change);
+ fireUndoStackChanged();
+ }
+
+ /*
+ * (Non-Javadoc) Method declared in IUndoManager.
+ */
+ public RefactoringStatus performUndo(IProgressMonitor pm) throws CoreException {
+ RefactoringStatus result= new RefactoringStatus();
+
+ if (fUndoChanges.empty())
+ return result;
+
+ Change change= (Change)fUndoChanges.pop();
+ removeValidationStateListener(change);
+
+ Change redo= executeChange(result, change, pm);
+
+ if (!result.hasFatalError()) {
+ if (redo != null && !fUndoNames.isEmpty()) {
+ addValidationStateListener(redo);
+ fRedoNames.push(fUndoNames.pop());
+ fRedoChanges.push(redo);
+ fireUndoStackChanged();
+ fireRedoStackChanged();
+ } else {
+ flush();
+ }
+ } else {
+ flush();
+ }
+ return result;
+ }
+
+ /*
+ * (Non-Javadoc) Method declared in IUndoManager.
+ */
+ public RefactoringStatus performRedo(IProgressMonitor pm) throws CoreException {
+ RefactoringStatus result= new RefactoringStatus();
+
+ if (fRedoChanges.empty())
+ return result;
+
+ Change change= (Change)fRedoChanges.pop();
+ removeValidationStateListener(change);
+
+ Change undo= executeChange(result, change, pm);
+
+ if (!result.hasFatalError()) {
+ if (undo != null && !fRedoNames.isEmpty()) {
+ addValidationStateListener(undo);
+ fUndoNames.push(fRedoNames.pop());
+ fUndoChanges.push(undo);
+ fireRedoStackChanged();
+ fireUndoStackChanged();
+ }
+ } else {
+ flush();
+ }
+
+ return result;
+ }
+
+ private Change executeChange(final RefactoringStatus status, final Change change, IProgressMonitor pm) throws CoreException {
+ final Change[] undo= new Change[1];
+ IWorkspaceRunnable runnable= new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ Exception exception= null;
+ try {
+ monitor.beginTask("", 11); //$NON-NLS-1$
+ status.merge(change.isValid(new SubProgressMonitor(monitor, 2)));
+ if (status.hasFatalError()) {
+ return;
+ }
+
+ ResourcesPlugin.getWorkspace().checkpoint(false);
+ aboutToPerformChange(change);
+ undo[0]= change.perform(new SubProgressMonitor(monitor, 8));
+ try {
+ change.dispose();
+ } finally {
+ if (undo[0] != null) {
+ undo[0].initializeValidationData(new SubProgressMonitor(monitor, 1));
+ }
+ }
+ } catch (RuntimeException e) {
+ exception= e;
+ throw e;
+ } catch (CoreException e) {
+ exception= e;
+ throw e;
+ } finally {
+ ResourcesPlugin.getWorkspace().checkpoint(false);
+ changePerformed(change, undo[0], exception);
+ monitor.done();
+ }
+ }
+ };
+ ResourcesPlugin.getWorkspace().run(runnable, pm);
+ return undo[0];
+ }
+
+ /*
+ * (Non-Javadoc) Method declared in IUndoManager.
+ */
+ public boolean anythingToRedo() {
+ return !fRedoChanges.empty();
+ }
+
+ /*
+ * (Non-Javadoc) Method declared in IUndoManager.
+ */
+ public boolean anythingToUndo() {
+ return !fUndoChanges.empty();
+ }
+
+ /*
+ * (Non-Javadoc) Method declared in IUndoManager.
+ */
+ public String peekUndoName() {
+ if (fUndoNames.size() > 0)
+ return (String)fUndoNames.peek();
+ return null;
+ }
+
+ /*
+ * (Non-Javadoc) Method declared in IUndoManager.
+ */
+ public String peekRedoName() {
+ if (fRedoNames.size() > 0)
+ return (String)fRedoNames.peek();
+ return null;
+ }
+
+ private void fireUndoStackChanged() {
+ if (fListeners == null)
+ return;
+ Object[] listeners= fListeners.getListeners();
+ for (int i= 0; i < listeners.length; i++) {
+ ((IUndoManagerListener)listeners[i]).undoStackChanged(this);
+ }
+ }
+
+ private void fireRedoStackChanged() {
+ if (fListeners == null)
+ return;
+ Object[] listeners= fListeners.getListeners();
+ for (int i= 0; i < listeners.length; i++) {
+ ((IUndoManagerListener)listeners[i]).redoStackChanged(this);
+ }
+ }
+
+ private void sendAboutToPerformChange(Collection collection, Change change) {
+ for (Iterator iter= collection.iterator(); iter.hasNext();) {
+ Object element= iter.next();
+ if (element instanceof IDynamicValidationStateChange) {
+ ((IDynamicValidationStateChange)element).aboutToPerformChange(change);
+ }
+
+ }
+ }
+
+ private void sendChangePerformed(Collection collection, Change change, Change undo, Exception e) {
+ for (Iterator iter= collection.iterator(); iter.hasNext();) {
+ Object element= iter.next();
+ if (element instanceof IDynamicValidationStateChange) {
+ ((IDynamicValidationStateChange)element).changePerformed(change, undo, e);
+ }
+
+ }
+ }
+
+ private void sendDispose(Collection collection) {
+ for (Iterator iter= collection.iterator(); iter.hasNext();) {
+ Change change= (Change)iter.next();
+ change.dispose();
+ }
+ }
+
+ private void removeValidationStateListener(Change change) {
+ if (change instanceof IDynamicValidationStateChange)
+ ((IDynamicValidationStateChange)change).removeValidationStateListener(fValidationListener);
+ }
+
+ private void addValidationStateListener(Change change) {
+ if (change instanceof IDynamicValidationStateChange)
+ ((IDynamicValidationStateChange)change).addValidationStateListener(fValidationListener);
+ }
+
+ private void removeValidationStateListener(Collection collection) {
+ for (Iterator iter= collection.iterator(); iter.hasNext();) {
+ Object element= iter.next();
+ if (element instanceof IDynamicValidationStateChange) {
+ ((IDynamicValidationStateChange)element).removeValidationStateListener(fValidationListener);
+ }
+
+ }
+ }
+
+ private void validationStateChanged(Change change) {
+ try {
+ if (!change.isValid(new NullProgressMonitor()).isOK())
+ flush();
+ } catch (CoreException e) {
+ flush();
+ }
+ }
+
+ //---- testing methods ---------------------------------------------
+
+ public boolean testHasNumberOfUndos(int number) {
+ return fUndoChanges.size() == number;
+ }
+
+ public boolean testHasNumberOfRedos(int number) {
+ return fRedoChanges.size() == number;
+ }
+
+}
diff --git a/org.eclipse.ltk.ui.refactoring.tests/.classpath b/org.eclipse.ltk.ui.refactoring.tests/.classpath
new file mode 100644
index 00000000000..065ac06e197
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring.tests/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/org.eclipse.ltk.ui.refactoring.tests/.cvsignore b/org.eclipse.ltk.ui.refactoring.tests/.cvsignore
new file mode 100644
index 00000000000..fe99505dcc5
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring.tests/.cvsignore
@@ -0,0 +1,2 @@
+bin
+
diff --git a/org.eclipse.ltk.ui.refactoring.tests/.project b/org.eclipse.ltk.ui.refactoring.tests/.project
new file mode 100644
index 00000000000..f8663ef7d8e
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring.tests/.project
@@ -0,0 +1,28 @@
+
+
+ org.eclipse.ltk.ui.refactoring.tests
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/org.eclipse.ltk.ui.refactoring.tests/build.properties b/org.eclipse.ltk.ui.refactoring.tests/build.properties
new file mode 100644
index 00000000000..50095f2b27a
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring.tests/build.properties
@@ -0,0 +1,4 @@
+source.refuitests.jar = src/
+output.refuitests.jar = bin/
+bin.includes = plugin.xml,\
+ refuitests.jar
diff --git a/org.eclipse.ltk.ui.refactoring.tests/plugin.properties b/org.eclipse.ltk.ui.refactoring.tests/plugin.properties
new file mode 100644
index 00000000000..cd3604963b8
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring.tests/plugin.properties
@@ -0,0 +1,12 @@
+###############################################################################
+# Copyright (c) 2000, 2004 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Common Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/cpl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+pluginName= Refactoring UI Test Plug-in
+providerName= Eclipse.org
\ No newline at end of file
diff --git a/org.eclipse.ltk.ui.refactoring.tests/plugin.xml b/org.eclipse.ltk.ui.refactoring.tests/plugin.xml
new file mode 100644
index 00000000000..c9ee8c7f257
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring.tests/plugin.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.eclipse.ltk.ui.refactoring.tests/src/org/eclipse/ltk/ui/refactoring/tests/AllTests.java b/org.eclipse.ltk.ui.refactoring.tests/src/org/eclipse/ltk/ui/refactoring/tests/AllTests.java
new file mode 100644
index 00000000000..1af849c1eb4
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring.tests/src/org/eclipse/ltk/ui/refactoring/tests/AllTests.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.ui.refactoring.tests;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AllTests {
+
+ public static Test suite() {
+ TestSuite suite= new TestSuite("All Refactoring UI Tests"); //$NON-NLS-1$
+ suite.addTestSuite(EmptySuite.class);
+ return suite;
+ }
+}
+
diff --git a/org.eclipse.ltk.ui.refactoring.tests/src/org/eclipse/ltk/ui/refactoring/tests/EmptySuite.java b/org.eclipse.ltk.ui.refactoring.tests/src/org/eclipse/ltk/ui/refactoring/tests/EmptySuite.java
new file mode 100644
index 00000000000..3d4f42a846b
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring.tests/src/org/eclipse/ltk/ui/refactoring/tests/EmptySuite.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.ui.refactoring.tests;
+
+import junit.framework.TestCase;
+
+public class EmptySuite extends TestCase {
+
+ public void test0() {
+ }
+}
diff --git a/org.eclipse.ltk.ui.refactoring.tests/src/org/eclipse/ltk/ui/refactoring/tests/RefactoringUITestPlugin.java b/org.eclipse.ltk.ui.refactoring.tests/src/org/eclipse/ltk/ui/refactoring/tests/RefactoringUITestPlugin.java
new file mode 100644
index 00000000000..47cdc027ebb
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring.tests/src/org/eclipse/ltk/ui/refactoring/tests/RefactoringUITestPlugin.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.ui.refactoring.tests;
+
+import org.eclipse.core.runtime.IPluginDescriptor;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+public class RefactoringUITestPlugin extends AbstractUIPlugin {
+
+ private static RefactoringUITestPlugin fgDefault;
+
+ public RefactoringUITestPlugin(IPluginDescriptor descriptor) {
+ super(descriptor);
+ fgDefault= this;
+ }
+
+ public static RefactoringUITestPlugin getDefault() {
+ return fgDefault;
+ }
+
+ public static String getPluginId() {
+ return getDefault().getDescriptor().getUniqueIdentifier();
+ }
+}
diff --git a/org.eclipse.ltk.ui.refactoring.tests/test.xml b/org.eclipse.ltk.ui.refactoring.tests/test.xml
new file mode 100644
index 00000000000..821f3edec78
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring.tests/test.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.eclipse.ltk.ui.refactoring/.classpath b/org.eclipse.ltk.ui.refactoring/.classpath
new file mode 100644
index 00000000000..065ac06e197
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/org.eclipse.ltk.ui.refactoring/.cvsignore b/org.eclipse.ltk.ui.refactoring/.cvsignore
new file mode 100644
index 00000000000..fe99505dcc5
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring/.cvsignore
@@ -0,0 +1,2 @@
+bin
+
diff --git a/org.eclipse.ltk.ui.refactoring/.project b/org.eclipse.ltk.ui.refactoring/.project
new file mode 100644
index 00000000000..8d07c0b5484
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring/.project
@@ -0,0 +1,28 @@
+
+
+ org.eclipse.ltk.ui.refactoring
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/org.eclipse.ltk.ui.refactoring/.template b/org.eclipse.ltk.ui.refactoring/.template
new file mode 100644
index 00000000000..f3bcd418c73
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring/.template
@@ -0,0 +1,4 @@
+
+
diff --git a/org.eclipse.ltk.ui.refactoring/build.properties b/org.eclipse.ltk.ui.refactoring/build.properties
new file mode 100644
index 00000000000..e0c44cdf0ef
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring/build.properties
@@ -0,0 +1,4 @@
+source.refui.jar = src/
+output.refui.jar = bin/
+bin.includes = plugin.xml,\
+ refui.jar
diff --git a/org.eclipse.ltk.ui.refactoring/plugin.properties b/org.eclipse.ltk.ui.refactoring/plugin.properties
new file mode 100644
index 00000000000..2f7acb55042
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring/plugin.properties
@@ -0,0 +1,12 @@
+###############################################################################
+# Copyright (c) 2000, 2004 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Common Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/cpl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+pluginName= Refactoring UI
+providerName= Eclipse.org
\ No newline at end of file
diff --git a/org.eclipse.ltk.ui.refactoring/plugin.xml b/org.eclipse.ltk.ui.refactoring/plugin.xml
new file mode 100644
index 00000000000..a5a34c384b5
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring/plugin.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/internal/ui/refactoring/RefactoringUIMessages.java b/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/internal/ui/refactoring/RefactoringUIMessages.java
new file mode 100644
index 00000000000..2010654bf67
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/internal/ui/refactoring/RefactoringUIMessages.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.internal.ui.refactoring;
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class RefactoringUIMessages {
+
+ private static final String BUNDLE_NAME= "org.eclipse.ltk.internal.ui.refactoring.RefactoringUIMessages";//$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE= ResourceBundle.getBundle(BUNDLE_NAME);
+
+ private RefactoringUIMessages() {
+ }
+
+ public static String getString(String key) {
+ try {
+ return RESOURCE_BUNDLE.getString(key);
+ } catch (MissingResourceException e) {
+ return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$
+ }
+ }
+
+ public static String getFormattedString(String key, String arg) {
+ try{
+ return MessageFormat.format(RESOURCE_BUNDLE.getString(key), new String[] { arg });
+ } catch (MissingResourceException e) {
+ return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$
+ }
+ }
+
+ public static String getFormattedString(String key, Object arg) {
+ try{
+ return MessageFormat.format(RESOURCE_BUNDLE.getString(key), new Object[] { arg });
+ } catch (MissingResourceException e) {
+ return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$
+ }
+ }
+
+ public static String getFormattedString(String key, String[] args) {
+ try{
+ return MessageFormat.format(RESOURCE_BUNDLE.getString(key), args);
+ } catch (MissingResourceException e) {
+ return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$
+ }
+ }
+
+ public static String getFormattedString(String key, Object[] args) {
+ try{
+ return MessageFormat.format(RESOURCE_BUNDLE.getString(key), args);
+ } catch (MissingResourceException e) {
+ return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/internal/ui/refactoring/RefactoringUIMessages.properties b/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/internal/ui/refactoring/RefactoringUIMessages.properties
new file mode 100644
index 00000000000..21a55292908
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/internal/ui/refactoring/RefactoringUIMessages.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2000, 2004 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Common Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/cpl-v10.html
+#
+# Contributors:
+# IBM Corporation - initial API and implementation
+###############################################################################
+
+RefactoringUIPlugin.internal_error=Internal Error
+RefactoringUIPlugin.listener_removed=Listener removed due to the following exception
\ No newline at end of file
diff --git a/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/internal/ui/refactoring/RefactoringUIPlugin.java b/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/internal/ui/refactoring/RefactoringUIPlugin.java
new file mode 100644
index 00000000000..6f7d08f9737
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/internal/ui/refactoring/RefactoringUIPlugin.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.internal.ui.refactoring;
+
+import org.eclipse.core.runtime.IPluginDescriptor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.core.resources.ResourcesPlugin;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+import org.eclipse.ltk.ui.refactoring.IRefactoringUIStatusCodes;
+
+public class RefactoringUIPlugin extends AbstractUIPlugin {
+
+ private static RefactoringUIPlugin fgDefault;
+
+ public RefactoringUIPlugin(IPluginDescriptor descriptor) {
+ super(descriptor);
+ fgDefault= this;
+ }
+
+ public static RefactoringUIPlugin getDefault() {
+ return fgDefault;
+ }
+
+ public static String getPluginId() {
+ return getDefault().getDescriptor().getUniqueIdentifier();
+ }
+
+ public static void log(IStatus status) {
+ getDefault().getLog().log(status);
+ }
+
+ public static void log(Throwable t) {
+ IStatus status= new Status(
+ IStatus.ERROR, getPluginId(),
+ IRefactoringUIStatusCodes.INTERNAL_ERROR,
+ RefactoringUIMessages.getString("RefactoringUIPlugin.internal_error"), //$NON-NLS-1$
+ t);
+ ResourcesPlugin.getPlugin().getLog().log(status);
+ }
+
+ public static void logRemovedListener(Throwable t) {
+ IStatus status= new Status(
+ IStatus.ERROR, getPluginId(),
+ IRefactoringUIStatusCodes.INTERNAL_ERROR,
+ RefactoringUIMessages.getString("RefactoringUIPlugin.listener_removed"), //$NON-NLS-1$
+ t);
+ ResourcesPlugin.getPlugin().getLog().log(status);
+ }
+}
diff --git a/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/ui/refactoring/IRefactoringUIStatusCodes.java b/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/ui/refactoring/IRefactoringUIStatusCodes.java
new file mode 100644
index 00000000000..928e7c5df75
--- /dev/null
+++ b/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/ui/refactoring/IRefactoringUIStatusCodes.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.ui.refactoring;
+
+/**
+ * Status codes used by the refactoring ui plug-in.
+ *
+ * This interface is not intended to be implemented by clients.
+ *
+ *
+ * @see org.eclipse.core.runtime.Status
+ *
+ * @since 3.0
+ */
+public abstract class IRefactoringUIStatusCodes {
+
+ private IRefactoringUIStatusCodes() {
+ // no instance
+ }
+
+ /**
+ * Status code (value 10000) indicating an internal error.
+ */
+ public static final int INTERNAL_ERROR= 10000;
+
+}