| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 |
| * |
| * 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.tools.idea.actions; |
| |
| import com.android.SdkConstants; |
| import com.android.tools.idea.gradle.eclipse.AdtImportProvider; |
| import com.android.tools.idea.gradle.project.GradleProjectImporter; |
| import com.google.common.collect.Lists; |
| import com.intellij.ide.actions.OpenProjectFileChooserDescriptor; |
| import com.intellij.ide.util.PropertiesComponent; |
| import com.intellij.ide.util.newProjectWizard.AddModuleWizard; |
| import com.intellij.ide.util.projectWizard.ProjectBuilder; |
| import com.intellij.openapi.actionSystem.AnAction; |
| import com.intellij.openapi.actionSystem.AnActionEvent; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.components.StorageScheme; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.fileChooser.FileChooserDescriptor; |
| import com.intellij.openapi.fileChooser.FileChooserDialog; |
| import com.intellij.openapi.fileChooser.FileChooserFactory; |
| import com.intellij.openapi.options.ConfigurationException; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.project.ex.ProjectManagerEx; |
| import com.intellij.openapi.ui.Messages; |
| import com.intellij.openapi.vfs.LocalFileSystem; |
| import com.intellij.openapi.vfs.VfsUtilCore; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.projectImport.ProjectImportProvider; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.List; |
| |
| import static com.android.tools.idea.gradle.eclipse.GradleImport.isEclipseProjectDir; |
| import static com.android.tools.idea.gradle.project.AdtModuleImporter.isAdtProjectLocation; |
| import static com.android.tools.idea.gradle.project.GradleModuleImporter.isGradleProject; |
| import static com.android.tools.idea.gradle.project.ProjectImportUtil.findImportTarget; |
| import static com.intellij.ide.impl.NewProjectUtil.createFromWizard; |
| import static com.intellij.openapi.project.Project.DIRECTORY_STORE_FOLDER; |
| import static com.intellij.openapi.roots.ui.configuration.ModulesProvider.EMPTY_MODULES_PROVIDER; |
| import static com.intellij.openapi.util.io.FileUtil.ensureExists; |
| import static com.intellij.util.ui.UIUtil.invokeLaterIfNeeded; |
| import static java.util.Collections.emptyList; |
| |
| /** |
| * Imports a new project into Android Studio. |
| * <p/> |
| * This action replaces the default "Import Project..." changing the behavior of project imports. If the user selects a project's root |
| * directory of a Gradle project, this action will detect that the project is a Gradle project and it will direct the user to the Gradle |
| * "Import Project" wizard, instead of the intermediate wizard where users can choose to import a project from existing sources. This has |
| * been a source of confusion for our users. |
| * <p/> |
| * The code in the original action cannot be extended or reused. It is implemented using static methods and the method where we change the |
| * behavior is at the bottom of the call chain. |
| */ |
| public class AndroidImportProjectAction extends AnAction { |
| @NonNls private static final String LAST_IMPORTED_LOCATION = "last.imported.location"; |
| private static final Logger LOG = Logger.getInstance(AndroidImportProjectAction.class); |
| |
| private static final String WIZARD_TITLE = "Select Eclipse or Gradle Project to Import"; |
| private static final String WIZARD_DESCRIPTION = "Select your Eclipse project folder, build.gradle or settings.gradle"; |
| |
| public AndroidImportProjectAction() { |
| super("Import Project..."); |
| } |
| |
| @Override |
| public void actionPerformed(AnActionEvent e) { |
| try { |
| AddModuleWizard wizard = selectFileAndCreateWizard(); |
| if (wizard != null) { |
| if (wizard.getStepCount() > 0) { |
| if (!wizard.showAndGet()) { |
| return; |
| } |
| //noinspection ConstantConditions |
| createFromWizard(wizard, null); |
| } |
| } |
| } |
| catch (IOException exception) { |
| handleImportException(e.getProject(), exception); |
| } |
| catch (ConfigurationException exception) { |
| handleImportException(e.getProject(), exception); |
| } |
| } |
| |
| private static void handleImportException(@Nullable Project project, @NotNull Exception e1) { |
| String message = String.format("Project import failed: %s", e1.getMessage()); |
| Messages.showErrorDialog(project, message, "Import Project"); |
| LOG.error(e1); |
| } |
| |
| @NotNull |
| protected FileChooserDescriptor createFileChooserDescriptor() { |
| FileChooserDescriptor descriptor = new FileChooserDescriptor(true, true, true, true, false, false) { |
| FileChooserDescriptor myDelegate = new OpenProjectFileChooserDescriptor(true); |
| |
| @Override |
| public Icon getIcon(VirtualFile file) { |
| Icon icon = myDelegate.getIcon(file); |
| return icon == null ? super.getIcon(file) : icon; |
| } |
| }; |
| descriptor.setHideIgnored(false); |
| descriptor.setTitle(WIZARD_TITLE); |
| descriptor.setDescription(WIZARD_DESCRIPTION); |
| return descriptor; |
| } |
| |
| @Nullable |
| private AddModuleWizard selectFileAndCreateWizard() throws IOException, ConfigurationException { |
| return selectFileAndCreateWizard(createFileChooserDescriptor()); |
| } |
| |
| @Nullable |
| private AddModuleWizard selectFileAndCreateWizard(@NotNull FileChooserDescriptor descriptor) |
| throws IOException, ConfigurationException { |
| FileChooserDialog chooser = FileChooserFactory.getInstance().createFileChooser(descriptor, null, null); |
| VirtualFile toSelect = null; |
| String lastLocation = PropertiesComponent.getInstance().getValue(LAST_IMPORTED_LOCATION); |
| if (lastLocation != null) { |
| toSelect = LocalFileSystem.getInstance().refreshAndFindFileByPath(lastLocation); |
| } |
| VirtualFile[] files = chooser.choose(null, toSelect); |
| if (files.length == 0) { |
| return null; |
| } |
| VirtualFile file = files[0]; |
| PropertiesComponent.getInstance().setValue(LAST_IMPORTED_LOCATION, file.getPath()); |
| return createImportWizard(file); |
| } |
| |
| @Nullable |
| protected AddModuleWizard createImportWizard(@NotNull VirtualFile file) throws IOException, ConfigurationException { |
| VirtualFile target = findImportTarget(file); |
| if (target == null) { |
| return null; |
| } |
| VirtualFile targetDir = target.isDirectory() ? target : target.getParent(); |
| File targetDirFile = VfsUtilCore.virtualToIoFile(targetDir); |
| |
| if (isAdtProjectLocation(file)) { |
| importAdtProject(file); |
| } |
| else if (isEclipseProjectDir(targetDirFile) && |
| targetDir.findChild(SdkConstants.FN_BUILD_GRADLE) == null && |
| !ApplicationManager.getApplication().isUnitTestMode()) { |
| String message = String.format("%1$s is an Eclipse project, but not an Android Eclipse project.\n\n" + |
| "Please select the directory of an Android Eclipse project" + |
| "(which for example will contain\nan AndroidManifest.xml file) and try again.", file.getPath()); |
| Messages.showErrorDialog(message, "Import Project"); |
| } |
| else if (isGradleProject(target)) { |
| GradleProjectImporter gradleImporter = GradleProjectImporter.getInstance(); |
| gradleImporter.importProject(file); |
| } |
| else { |
| return importWithExtensions(file); |
| } |
| return null; |
| } |
| |
| @Nullable |
| private static AddModuleWizard importWithExtensions(@NotNull VirtualFile file) { |
| List<ProjectImportProvider> available = getImportProvidersForTarget(file); |
| if (available.isEmpty()) { |
| Messages.showInfoMessage((Project) null, "Cannot import anything from " + file.getPath(), "Cannot Import"); |
| return null; |
| } |
| String path; |
| if (available.size() == 1) { |
| path = available.get(0).getPathToBeImported(file); |
| } |
| else { |
| path = ProjectImportProvider.getDefaultPath(file); |
| } |
| |
| ProjectImportProvider[] availableProviders = available.toArray(new ProjectImportProvider[available.size()]); |
| return new AddModuleWizard(null, path, availableProviders); |
| } |
| |
| @NotNull |
| private static List<ProjectImportProvider> getImportProvidersForTarget(@NotNull VirtualFile file) { |
| VirtualFile target = findImportTarget(file); |
| if (target == null) { |
| return emptyList(); |
| } |
| else { |
| List<ProjectImportProvider> available = Lists.newArrayList(); |
| for (ProjectImportProvider provider : ProjectImportProvider.PROJECT_IMPORT_PROVIDER.getExtensions()) { |
| if (provider.canImport(target, null)) { |
| available.add(provider); |
| } |
| } |
| return available; |
| } |
| } |
| |
| private static void importAdtProject(@NotNull VirtualFile file) { |
| AdtImportProvider adtImportProvider = new AdtImportProvider(true); |
| AddModuleWizard wizard = new AddModuleWizard(null, ProjectImportProvider.getDefaultPath(file), adtImportProvider); |
| if (wizard.showAndGet()) { |
| try { |
| doCreate(wizard); |
| } |
| catch (final IOException e) { |
| invokeLaterIfNeeded(new Runnable() { |
| @Override |
| public void run() { |
| Messages.showErrorDialog(e.getMessage(), "Project Initialization Failed"); |
| } |
| }); |
| } |
| } |
| } |
| |
| private static void doCreate(@NotNull AddModuleWizard wizard) throws IOException { |
| // TODO: Now we need to add as module if file does not exist |
| ProjectBuilder projectBuilder = wizard.getProjectBuilder(); |
| |
| try { |
| File projectFilePath = new File(wizard.getNewProjectFilePath()); |
| File projectDirPath = projectFilePath.isDirectory() ? projectFilePath : projectFilePath.getParentFile(); |
| LOG.assertTrue(projectDirPath != null, "Cannot create project in '" + projectFilePath + "': no parent file exists"); |
| ensureExists(projectDirPath); |
| |
| if (StorageScheme.DIRECTORY_BASED == wizard.getStorageScheme()) { |
| File ideaDirPath = new File(projectDirPath, DIRECTORY_STORE_FOLDER); |
| ensureExists(ideaDirPath); |
| } |
| |
| boolean unitTestMode = ApplicationManager.getApplication().isUnitTestMode(); |
| ProjectManagerEx projectManager = ProjectManagerEx.getInstanceEx(); |
| Project project = projectManager.newProject(wizard.getProjectName(), projectDirPath.getPath(), true, false); |
| if (project == null) { |
| return; |
| } |
| if (!unitTestMode) { |
| project.save(); |
| } |
| if (projectBuilder != null) { |
| if (!projectBuilder.validate(null, project)) { |
| return; |
| } |
| projectBuilder.commit(project, null, EMPTY_MODULES_PROVIDER); |
| } |
| if (!unitTestMode) { |
| project.save(); |
| } |
| } |
| finally { |
| if (projectBuilder != null) { |
| projectBuilder.cleanup(); |
| } |
| } |
| } |
| } |