diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidNature.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidNature.java | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidNature.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidNature.java new file mode 100644 index 000000000..3b1c29fe9 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidNature.java @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.adt.internal.project; + +import com.android.ide.eclipse.adt.AdtConstants; +import com.android.ide.eclipse.adt.internal.build.builders.PostCompilerBuilder; +import com.android.ide.eclipse.adt.internal.build.builders.PreCompilerBuilder; +import com.android.ide.eclipse.adt.internal.build.builders.ResourceManagerBuilder; + +import org.eclipse.core.resources.ICommand; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IProjectNature; +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.jdt.core.JavaCore; + +/** + * Project nature for the Android Projects. + */ +public class AndroidNature implements IProjectNature { + + /** the project this nature object is associated with */ + private IProject mProject; + + /** + * Configures this nature for its project. This is called by the workspace + * when natures are added to the project using + * <code>IProject.setDescription</code> and should not be called directly + * by clients. The nature extension id is added to the list of natures + * before this method is called, and need not be added here. + * + * Exceptions thrown by this method will be propagated back to the caller of + * <code>IProject.setDescription</code>, but the nature will remain in + * the project description. + * + * The Android nature adds the pre-builder and the APK builder if necessary. + * + * @see org.eclipse.core.resources.IProjectNature#configure() + * @throws CoreException if configuration fails. + */ + @Override + public void configure() throws CoreException { + configureResourceManagerBuilder(mProject); + configurePreBuilder(mProject); + configureApkBuilder(mProject); + } + + /** + * De-configures this nature for its project. This is called by the + * workspace when natures are removed from the project using + * <code>IProject.setDescription</code> and should not be called directly + * by clients. The nature extension id is removed from the list of natures + * before this method is called, and need not be removed here. + * + * Exceptions thrown by this method will be propagated back to the caller of + * <code>IProject.setDescription</code>, but the nature will still be + * removed from the project description. + * + * The Android nature removes the custom pre builder and APK builder. + * + * @see org.eclipse.core.resources.IProjectNature#deconfigure() + * @throws CoreException if configuration fails. + */ + @Override + public void deconfigure() throws CoreException { + // remove the android builders + removeBuilder(mProject, ResourceManagerBuilder.ID); + removeBuilder(mProject, PreCompilerBuilder.ID); + removeBuilder(mProject, PostCompilerBuilder.ID); + } + + /** + * Returns the project to which this project nature applies. + * + * @return the project handle + * @see org.eclipse.core.resources.IProjectNature#getProject() + */ + @Override + public IProject getProject() { + return mProject; + } + + /** + * Sets the project to which this nature applies. Used when instantiating + * this project nature runtime. This is called by + * <code>IProject.create()</code> or + * <code>IProject.setDescription()</code> and should not be called + * directly by clients. + * + * @param project the project to which this nature applies + * @see org.eclipse.core.resources.IProjectNature#setProject(org.eclipse.core.resources.IProject) + */ + @Override + public void setProject(IProject project) { + mProject = project; + } + + /** + * Adds the Android Nature and the Java Nature to the project if it doesn't + * already have them. + * + * @param project An existing or new project to update + * @param monitor An optional progress monitor. Can be null. + * @param addAndroidNature true if the Android Nature should be added to the project; false to + * add only the Java nature. + * @throws CoreException if fails to change the nature. + */ + public static synchronized void setupProjectNatures(IProject project, + IProgressMonitor monitor, boolean addAndroidNature) throws CoreException { + if (project == null || !project.isOpen()) return; + if (monitor == null) monitor = new NullProgressMonitor(); + + // Add the natures. We need to add the Java nature first, so it adds its builder to the + // project first. This way, when the android nature is added, we can control where to put + // the android builders in relation to the java builder. + // Adding the java nature after the android one, would place the java builder before the + // android builders. + addNatureToProjectDescription(project, JavaCore.NATURE_ID, monitor); + if (addAndroidNature) { + addNatureToProjectDescription(project, AdtConstants.NATURE_DEFAULT, monitor); + } + } + + /** + * Add the specified nature to the specified project. The nature is only + * added if not already present. + * <p/> + * Android Natures are always inserted at the beginning of the list of natures in order to + * have the jdt views/dialogs display the proper icon. + * + * @param project The project to modify. + * @param natureId The Id of the nature to add. + * @param monitor An existing progress monitor. + * @throws CoreException if fails to change the nature. + */ + private static void addNatureToProjectDescription(IProject project, + String natureId, IProgressMonitor monitor) throws CoreException { + if (!project.hasNature(natureId)) { + + IProjectDescription description = project.getDescription(); + String[] natures = description.getNatureIds(); + String[] newNatures = new String[natures.length + 1]; + + // Android natures always come first. + if (natureId.equals(AdtConstants.NATURE_DEFAULT)) { + System.arraycopy(natures, 0, newNatures, 1, natures.length); + newNatures[0] = natureId; + } else { + System.arraycopy(natures, 0, newNatures, 0, natures.length); + newNatures[natures.length] = natureId; + } + + description.setNatureIds(newNatures); + project.setDescription(description, new SubProgressMonitor(monitor, 10)); + } + } + + /** + * Adds the ResourceManagerBuilder, if its not already there. It'll insert + * itself as the first builder. + * @throws CoreException + * + */ + public static void configureResourceManagerBuilder(IProject project) + throws CoreException { + // get the builder list + IProjectDescription desc = project.getDescription(); + ICommand[] commands = desc.getBuildSpec(); + + // look for the builder in case it's already there. + for (int i = 0; i < commands.length; ++i) { + if (ResourceManagerBuilder.ID.equals(commands[i].getBuilderName())) { + return; + } + } + + // it's not there, lets add it at the beginning of the builders + ICommand[] newCommands = new ICommand[commands.length + 1]; + System.arraycopy(commands, 0, newCommands, 1, commands.length); + ICommand command = desc.newCommand(); + command.setBuilderName(ResourceManagerBuilder.ID); + newCommands[0] = command; + desc.setBuildSpec(newCommands); + project.setDescription(desc, null); + } + + /** + * Adds the PreCompilerBuilder if its not already there. It'll check for + * presence of the ResourceManager and insert itself right after. + * @param project + * @throws CoreException + */ + public static void configurePreBuilder(IProject project) + throws CoreException { + // get the builder list + IProjectDescription desc = project.getDescription(); + ICommand[] commands = desc.getBuildSpec(); + + // look for the builder in case it's already there. + for (int i = 0; i < commands.length; ++i) { + if (PreCompilerBuilder.ID.equals(commands[i].getBuilderName())) { + return; + } + } + + // we need to add it after the resource manager builder. + // Let's look for it + int index = -1; + for (int i = 0; i < commands.length; ++i) { + if (ResourceManagerBuilder.ID.equals(commands[i].getBuilderName())) { + index = i; + break; + } + } + + // we're inserting after + index++; + + // do the insertion + + // copy the builders before. + ICommand[] newCommands = new ICommand[commands.length + 1]; + System.arraycopy(commands, 0, newCommands, 0, index); + + // insert the new builder + ICommand command = desc.newCommand(); + command.setBuilderName(PreCompilerBuilder.ID); + newCommands[index] = command; + + // copy the builder after + System.arraycopy(commands, index, newCommands, index + 1, commands.length-index); + + // set the new builders in the project + desc.setBuildSpec(newCommands); + project.setDescription(desc, null); + } + + public static void configureApkBuilder(IProject project) + throws CoreException { + // Add the .apk builder at the end if it's not already there + IProjectDescription desc = project.getDescription(); + ICommand[] commands = desc.getBuildSpec(); + + for (int i = 0; i < commands.length; ++i) { + if (PostCompilerBuilder.ID.equals(commands[i].getBuilderName())) { + return; + } + } + + ICommand[] newCommands = new ICommand[commands.length + 1]; + System.arraycopy(commands, 0, newCommands, 0, commands.length); + ICommand command = desc.newCommand(); + command.setBuilderName(PostCompilerBuilder.ID); + newCommands[commands.length] = command; + desc.setBuildSpec(newCommands); + project.setDescription(desc, null); + } + + /** + * Removes a builder from the project. + * @param project The project to remove the builder from. + * @param id The String ID of the builder to remove. + * @return true if the builder was found and removed. + * @throws CoreException + */ + public static boolean removeBuilder(IProject project, String id) throws CoreException { + IProjectDescription description = project.getDescription(); + ICommand[] commands = description.getBuildSpec(); + for (int i = 0; i < commands.length; ++i) { + if (id.equals(commands[i].getBuilderName())) { + ICommand[] newCommands = new ICommand[commands.length - 1]; + System.arraycopy(commands, 0, newCommands, 0, i); + System.arraycopy(commands, i + 1, newCommands, i, commands.length - i - 1); + description.setBuildSpec(newCommands); + project.setDescription(description, null); + return true; + } + } + + return false; + } +} |