| /* |
| * 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; |
| } |
| } |