blob: 591a6cf0859aa9146774165aaf4a896de860b6f8 [file] [log] [blame]
package org.eclipse.jdt.internal.core;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.*;
import java.io.File;
import java.util.*;
/**
* This operation sets an <code>IJavaProject</code>'s output location.
*
* @see IJavaProject
*/
public class SetOutputLocationOperation extends JavaModelOperation {
/**
* The new output location for the Java project
*/
protected IPath fOutputLocation;
/**
* When executed, this operation sets the output location of the given project.
* The output location is where the builder writes <code>.class</code> files.
*/
public SetOutputLocationOperation(IJavaProject project, IPath outputLocation) {
super(new IJavaElement[] {project});
fOutputLocation = outputLocation;
}
/**
* Recursively adds all subfolders of <code>folder</code> to the given collection.
*/
protected void collectAllSubfolders(IFolder folder, Vector collection) throws JavaModelException {
try {
IResource[] members= folder.members();
for (int i = 0, max = members.length; i < max; i++) {
IResource r= members[i];
if (r.getType() == IResource.FOLDER) {
collection.addElement(r);
collectAllSubfolders((IFolder)r, collection);
}
}
} catch (CoreException e) {
throw new JavaModelException(e);
}
}
/**
* Returns a collection of package fragments that have been added/removed
* as the result of changing the output location to/from the given
* location. The collection is empty if no package fragments are
* affected.
*/
protected Vector determineAffectedPackageFragments(IPath location) throws JavaModelException {
Vector fragments = new Vector();
JavaProject project = ((JavaProject) getElementsToProcess()[0]);
// see if this will cause any package fragments to be affected
IWorkspace workspace = getWorkspace();
IResource resource = null;
if (location != null) {
resource = workspace.getRoot().findMember(location);
}
if (resource != null && resource.getType() == IResource.FOLDER) {
IFolder folder = (IFolder) resource;
// only changes if it actually existed
IClasspathEntry[] classpath = project.getResolvedClasspath(true);
for (int i = 0; i < classpath.length; i++) {
IClasspathEntry entry = classpath[i];
IPath path = classpath[i].getPath();
if (entry.getEntryKind() != IClasspathEntry.CPE_PROJECT && path.isPrefixOf(location) && !path.equals(location)) {
IPackageFragmentRoot[] roots = project.getPackageFragmentRoots(classpath[i]);
IPackageFragmentRoot root = roots[0];
// now the output location becomes a package fragment - along with any subfolders
Vector folders = new Vector();
folders.addElement(folder);
collectAllSubfolders(folder, folders);
Enumeration elements = folders.elements();
int segments = path.segmentCount();
while (elements.hasMoreElements()) {
IFolder f = (IFolder) elements.nextElement();
IPath relativePath = f.getFullPath().removeFirstSegments(segments);
String name = relativePath.toOSString();
name = name.replace(File.pathSeparatorChar, '.');
if (name.endsWith(".")) { //$NON-NLS-1$
name = name.substring(0, name.length() - 1);
}
IPackageFragment pkg = root.getPackageFragment(name);
fragments.addElement(pkg);
}
}
}
}
return fragments;
}
/**
* Sets the output location of the pre-specified project.
*
* <p>This can cause changes in package fragments - i.e. if the
* old and new output location folder could be considered as
* a package fragment.
*/
protected void executeOperation() throws JavaModelException {
beginTask(Util.bind("classpath.settingOutputLocationProgress"), 2); //$NON-NLS-1$
JavaProject project= ((JavaProject) getElementsToProcess()[0]);
IPath oldLocation= project.getOutputLocation();
IPath newLocation= fOutputLocation;
// see if this will cause any package fragments to be added
boolean deltaToFire= false;
JavaElementDelta delta = newJavaElementDelta();
Vector added= determineAffectedPackageFragments(oldLocation);
Enumeration pkgs= added.elements();
while (pkgs.hasMoreElements()) {
IPackageFragment frag= (IPackageFragment)pkgs.nextElement();
((IPackageFragmentRoot)frag.getParent()).close();
delta.added(frag);
deltaToFire = true;
}
// see if this will cause any package fragments to be removed
Vector removed= determineAffectedPackageFragments(newLocation);
pkgs= removed.elements();
while (pkgs.hasMoreElements()) {
IPackageFragment frag= (IPackageFragment)pkgs.nextElement();
((IPackageFragmentRoot)frag.getParent()).close();
delta.removed(frag);
deltaToFire = true;
}
project.setOutputLocation0(fOutputLocation);
if (deltaToFire) {
addDelta(delta);
}
worked(1);
project.saveClasspath();
worked(1);
// loose all built state - next build will be a full one
JavaModelManager.getJavaModelManager().setLastBuiltState(project.getProject(), null);
done();
}
/**
* Possible failures: <ul>
* <li>NO_ELEMENTS_TO_PROCESS - the project supplied to the operation is
* <code>null</code>.
* <li>NULL_PATH - the output location path supplied to the operation
* is <code>null</code>.
* <li>PATH_OUTSIDE_PROJECT - the output location path supplied to the operation
* is outside of the project supplied to this operation.
* <li>DEVICE_PATH - the path supplied to this operation must not specify a
* device
* <li>RELATIVE_PATH - the path supplied to this operation must be
* an absolute path
* <li>INVALID_PATH - the output location cannot overlap any package fragment
* root, except the project folder.
* <li>ELEMENT_DOES_NOT_EXIST - the Java project does not exist
* </ul>
*/
public IJavaModelStatus verify() {
IJavaModelStatus status = super.verify();
if (!status.isOK()) {
return status;
}
// retrieve classpath
IClasspathEntry[] classpath = null;
IJavaProject javaProject= (IJavaProject)getElementToProcess();
IPath projectPath= javaProject.getProject().getFullPath();
try {
classpath = javaProject.getResolvedClasspath(true);
} catch (JavaModelException e) {
return e.getJavaModelStatus();
}
return JavaConventions.validateClasspath((IJavaProject) fElementsToProcess[0], classpath, fOutputLocation);
}
}