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 @@ + + + + + + + diff --git a/org.eclipse.ltk.core.refactoring.tests/.cvsignore b/org.eclipse.ltk.core.refactoring.tests/.cvsignore new file mode 100644 index 00000000000..fe99505dcc5 --- /dev/null +++ b/org.eclipse.ltk.core.refactoring.tests/.cvsignore @@ -0,0 +1,2 @@ +bin + diff --git a/org.eclipse.ltk.core.refactoring.tests/.project b/org.eclipse.ltk.core.refactoring.tests/.project new file mode 100644 index 00000000000..e824a4cb125 --- /dev/null +++ b/org.eclipse.ltk.core.refactoring.tests/.project @@ -0,0 +1,28 @@ + + + org.eclipse.ltk.core.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.core.refactoring.tests/.template b/org.eclipse.ltk.core.refactoring.tests/.template new file mode 100644 index 00000000000..f3bcd418c73 --- /dev/null +++ b/org.eclipse.ltk.core.refactoring.tests/.template @@ -0,0 +1,4 @@ + +
+

Tips on working with this plug-in project

  • For the view of the new plug-in at a glance, go to the Overview.
  • You can test the contributions of this plug-in by launching another instance of the workbench. On the Run menu, click Run As and choose Run-time Workbench from the available choices.
  • You can add more functionality to this plug-in by adding extensions using the New Extension Wizard.
  • The plug-in project contains Java code that you can debug. Place breakpoints in Java classes. On the Run menu, select Debug As and choose Run-time Workbench from the available choices.
  • +
    diff --git a/org.eclipse.ltk.core.refactoring.tests/build.properties b/org.eclipse.ltk.core.refactoring.tests/build.properties new file mode 100644 index 00000000000..4e0aec862e2 --- /dev/null +++ b/org.eclipse.ltk.core.refactoring.tests/build.properties @@ -0,0 +1,4 @@ +source.refcoretests.jar = src/ +output.refcoretests.jar = bin/ +bin.includes = plugin.xml,\ + refcoretests.jar diff --git a/org.eclipse.ltk.core.refactoring.tests/plugin.properties b/org.eclipse.ltk.core.refactoring.tests/plugin.properties new file mode 100644 index 00000000000..994a343fc1c --- /dev/null +++ b/org.eclipse.ltk.core.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 Core Test Plug-in +providerName= Eclipse.org \ No newline at end of file diff --git a/org.eclipse.ltk.core.refactoring.tests/plugin.xml b/org.eclipse.ltk.core.refactoring.tests/plugin.xml new file mode 100644 index 00000000000..5cb77a34072 --- /dev/null +++ b/org.eclipse.ltk.core.refactoring.tests/plugin.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/AllTests.java b/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/AllTests.java new file mode 100644 index 00000000000..963b02c3ab1 --- /dev/null +++ b/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/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.core.refactoring.tests; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AllTests { + + public static Test suite() { + TestSuite suite= new TestSuite("All Refactoring Core Tests"); //$NON-NLS-1$ + suite.addTestSuite(EmptySuite.class); + return suite; + } +} + diff --git a/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/EmptySuite.java b/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/EmptySuite.java new file mode 100644 index 00000000000..eb4ef070ae8 --- /dev/null +++ b/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/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.core.refactoring.tests; + +import junit.framework.TestCase; + +public class EmptySuite extends TestCase { + + public void test0() { + } +} diff --git a/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/RefactoringCoreTestPlugin.java b/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/RefactoringCoreTestPlugin.java new file mode 100644 index 00000000000..39b810996f2 --- /dev/null +++ b/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/RefactoringCoreTestPlugin.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.tests; + +import org.eclipse.core.runtime.IPluginDescriptor; +import org.eclipse.core.runtime.Plugin; + +public class RefactoringCoreTestPlugin extends Plugin { + + private static RefactoringCoreTestPlugin fgDefault; + + public RefactoringCoreTestPlugin(IPluginDescriptor descriptor) { + super(descriptor); + fgDefault= this; + } + + public static RefactoringCoreTestPlugin getDefault() { + return fgDefault; + } + + public static String getPluginId() { + return getDefault().getDescriptor().getUniqueIdentifier(); + } +} diff --git a/org.eclipse.ltk.core.refactoring.tests/test.xml b/org.eclipse.ltk.core.refactoring.tests/test.xml new file mode 100644 index 00000000000..77098b0d459 --- /dev/null +++ b/org.eclipse.ltk.core.refactoring.tests/test.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.eclipse.ltk.core.refactoring/.classpath b/org.eclipse.ltk.core.refactoring/.classpath new file mode 100644 index 00000000000..065ac06e197 --- /dev/null +++ b/org.eclipse.ltk.core.refactoring/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.eclipse.ltk.core.refactoring/.cvsignore b/org.eclipse.ltk.core.refactoring/.cvsignore new file mode 100644 index 00000000000..fe99505dcc5 --- /dev/null +++ b/org.eclipse.ltk.core.refactoring/.cvsignore @@ -0,0 +1,2 @@ +bin + diff --git a/org.eclipse.ltk.core.refactoring/.project b/org.eclipse.ltk.core.refactoring/.project new file mode 100644 index 00000000000..90d3e96e467 --- /dev/null +++ b/org.eclipse.ltk.core.refactoring/.project @@ -0,0 +1,28 @@ + + + org.eclipse.ltk.core.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.core.refactoring/build.properties b/org.eclipse.ltk.core.refactoring/build.properties new file mode 100644 index 00000000000..fcf2617a335 --- /dev/null +++ b/org.eclipse.ltk.core.refactoring/build.properties @@ -0,0 +1,4 @@ +source.refcore.jar = src/ +output.refcore.jar = bin/ +bin.includes = plugin.xml,\ + refcore.jar diff --git a/org.eclipse.ltk.core.refactoring/plugin.properties b/org.eclipse.ltk.core.refactoring/plugin.properties new file mode 100644 index 00000000000..5cd6d24aa05 --- /dev/null +++ b/org.eclipse.ltk.core.refactoring/plugin.properties @@ -0,0 +1,18 @@ +############################################################################### +# 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 Core +providerName= Eclipse.org + +renameParticipantsExtensionPoint= Rename Participants +createParticipantsExtensionPoint= Create Participants +deleteParticipantsExtensionPoint= Delete Participants +moveParticipantsExtensionPoint= Move Participants +copyParticipantsExtensionPoint= Copy Participants diff --git a/org.eclipse.ltk.core.refactoring/plugin.xml b/org.eclipse.ltk.core.refactoring/plugin.xml new file mode 100644 index 00000000000..fd750ba3889 --- /dev/null +++ b/org.eclipse.ltk.core.refactoring/plugin.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/Change.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/Change.java new file mode 100644 index 00000000000..b77ddec28d1 --- /dev/null +++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/Change.java @@ -0,0 +1,236 @@ +/******************************************************************************* + * 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.IAdaptable; +import org.eclipse.core.runtime.IProgressMonitor; + +import org.eclipse.ltk.internal.core.refactoring.Assert; + +/** + * Represents a generic change to the workbench. An 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: + *

    + * Below a code snippet that can be used to execute a change: + *
    + *   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. + *

    + * + * @since 3.0 + */ +public abstract class Change implements IAdaptable { + + private Change fParent; + private boolean fIsEnabled= true; + + /** + * Constructs a new change object. + */ + protected Change() { + } + + /** + * Returns the human readable name of this change. The + * name MUST not be 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: + *

    + *

    + * 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. + *

    + * + * @param pm a progress monitor + * + * @throws CoreException if some error occurred while initializing the validation + * state. In this case the change object has to be treated as invalid + */ + public abstract void initializeValidationData(IProgressMonitor pm) throws CoreException; + + /** + * Verifies that this change object is still valid and can be executed by calling + * 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 or null 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 this Change. 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 trueif 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. + *

    + */ + public void setEnabled(boolean enabled) { + for (Iterator iter= fChanges.iterator(); iter.hasNext(); ) { + ((Change)iter.next()).setEnabled(enabled); + } + } + /** + * {@inheritDoc} + *

    + * 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. + *

    + */ + public void initializeValidationData(IProgressMonitor pm) throws CoreException { + pm.beginTask("", fChanges.size()); //$NON-NLS-1$ + for (Iterator iter= fChanges.iterator(); iter.hasNext();) { + Change change= (Change)iter.next(); + change.initializeValidationData(new SubProgressMonitor(pm, 1)); + pm.worked(1); + } + } + + /** + * {@inheritDoc} + *

    + * 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. + *

    + */ + public RefactoringStatus isValid(IProgressMonitor pm) throws CoreException { + RefactoringStatus result= new RefactoringStatus(); + pm.beginTask("", fChanges.size()); //$NON-NLS-1$ + for (Iterator iter= fChanges.iterator(); iter.hasNext() && !result.hasFatalError();) { + Change change= (Change)iter.next(); + if (change.isEnabled()) + result.merge(change.isValid(new SubProgressMonitor(pm, 1))); + else + pm.worked(1); + } + pm.done(); + return result; + } + + /** + * {@inheritDoc} + *

    + * 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. + *

    + */ + public Change perform(IProgressMonitor pm) throws CoreException { + fUndoUntilException= null; + List undos= new ArrayList(fChanges.size()); + pm.beginTask("", fChanges.size()); //$NON-NLS-1$ + pm.setTaskName(RefactoringCoreMessages.getString("CompositeChange.performingChangesTask.name")); //$NON-NLS-1$ + Change change= null; + try { + for (Iterator iter= fChanges.iterator(); iter.hasNext();) { + change= (Change)iter.next(); + if (change.isEnabled()) { + Change undoChange= change.perform(new SubProgressMonitor(pm, 1)); + if (undos != null) { + if (undoChange == null) { + undos= null; + } else { + undos.add(undoChange); + } + } + } + } + if (undos != null) { + Collections.reverse(undos); + return createUndoChange((Change[]) undos.toArray(new Change[undos.size()])); + } else { + return null; + } + } catch (CoreException e) { + handleUndos(change, undos); + throw e; + } catch (RuntimeException e) { + handleUndos(change, undos); + throw e; + } + } + + private void handleUndos(Change failedChange, List undos) { + if (undos == null) { + fUndoUntilException= null; + return; + } + if (failedChange instanceof CompositeChange) { + Change partUndoChange= ((CompositeChange)failedChange).getUndoUntilException(); + if (partUndoChange != null) { + undos.add(partUndoChange); + } + } + if (undos.size() == 0) { + fUndoUntilException= new NullChange(getName()); + return; + } + Collections.reverse(undos); + fUndoUntilException= createUndoChange((Change[]) undos.toArray(new Change[undos.size()])); + } + + /** + * {@inheritDoc} + *

    + * The composite change sends dispose to all its children. It is guaranteed + * that all children receive the dispose call. + *

    + */ + public void dispose() { + for (Iterator iter= fChanges.iterator(); iter.hasNext(); ) { + final Change change= (Change)iter.next(); + Platform.run(new ISafeRunnable() { + public void run() throws Exception { + change.dispose(); + } + public void handleException(Throwable exception) { + RefactoringCorePlugin.log(exception); + } + }); + } + } + + /** + * Returns the undo object containing all undo changes of those children + * that got successfully executed while performing this change. Returns + * 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 method addUndo + * 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. + *

    + * + * @since 3.0 + */ +public interface IUndoManager { + + /** + * Adds a listener to the undo manager. + * + * @param listener the listener to be added to the undo manager + */ + public void addListener(IUndoManagerListener listener); + + /** + * Removes the given listener from this undo manager. + * + * @param listener the listener to be removed + */ + public void removeListener(IUndoManagerListener listener); + + /** + * The infrastructure is going to perform the given change. + * + * @param change the change to be performed. + */ + public void aboutToPerformChange(Change change); + + /** + * The infrastructure has performed the given change. + * + * @param change the change that was performed + * @param undo the corresponding undo change or 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: + *

    + * + * @since 3.0 + */ +public abstract class Refactoring extends PlatformObject { + + /** + * Returns the refactoring's name. + * + * @return the refactoring's human readable name. Must not be + * 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. + *

    + * This method can be called more than once. + *

    + * + * @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. + *

    + * This method can be called more than once. + *

    + * + * @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 IFiles. + * + * @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: + *
      + *
    1. the refactoring itself is checked whether it is an instance + * of the requested type.
    2. + *
    3. its processor is checked whether it is an instance of the + * requested type.
    4. + *
    5. the request is delegated to the super class.
    6. + *
    + * + * @return the requested adapter or nullif 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 @@ + +
    +

    Tips on working with this plug-in project

  • For the view of the new plug-in at a glance, go to the Overview.
  • You can test the contributions of this plug-in by launching another instance of the workbench. On the Run menu, click Run As and choose Run-time Workbench from the available choices.
  • You can add more functionality to this plug-in by adding extensions using the New Extension Wizard.
  • The plug-in project contains Java code that you can debug. Place breakpoints in Java classes. On the Run menu, select Debug As and choose Run-time Workbench from the available choices.
  • +
    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; + +}