/* * 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.wizard; import com.android.annotations.VisibleForTesting; import com.android.tools.idea.gradle.project.GradleProjectImporter; import com.android.tools.idea.templates.Template; import com.google.common.base.Functions; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.intellij.ide.util.projectWizard.ModuleBuilder; import com.intellij.ide.util.projectWizard.ModuleWizardStep; import com.intellij.ide.util.projectWizard.SettingsStep; import com.intellij.ide.util.projectWizard.WizardContext; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.module.StdModuleTypes; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.DumbAwareRunnable; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectType; import com.intellij.openapi.projectRoots.JavaSdkType; import com.intellij.openapi.projectRoots.SdkTypeId; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ui.configuration.ModulesProvider; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.vfs.VirtualFile; import icons.AndroidIcons; import org.jetbrains.android.newProject.AndroidModuleBuilder; import org.jetbrains.android.sdk.AndroidSdkType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.io.File; import java.util.Collection; import java.util.List; import java.util.Map; import static com.android.SdkConstants.GRADLE_LATEST_VERSION; import static com.android.SdkConstants.GRADLE_PLUGIN_RECOMMENDED_VERSION; import static com.android.tools.idea.templates.TemplateMetadata.*; import static com.android.tools.idea.wizard.NewModuleWizardState.ATTR_PROJECT_LOCATION; import static com.android.tools.idea.wizard.FormFactorUtils.ATTR_MODULE_NAME; public class ImportWizardModuleBuilder extends ModuleBuilder implements TemplateWizardStep.UpdateListener, ChooseTemplateStep.TemplateChangeListener { @NotNull protected final List<ModuleWizardStep> mySteps; @NotNull protected final Iterable<WizardPath> myPaths; protected final NewModuleWizardState myWizardState; @Nullable private final VirtualFile myImportSource; @NotNull private final Map<ModuleWizardStep, WizardPath> myStepsToPath = Maps.newHashMap(); @VisibleForTesting protected boolean myInitializationComplete = false; @Nullable private Project myProject; private ImportSourceModulePath myImportSourcesPath; public ImportWizardModuleBuilder(@Nullable File templateFile, @Nullable Project project, @Nullable VirtualFile importSource, @Nullable Icon sidePanelIcon, @NotNull List<ModuleWizardStep> steps, @NotNull Disposable disposable, boolean inGlobalWizard) { myProject = project; myImportSource = importSource; mySteps = steps; if (project == null) { myWizardState = new NewProjectWizardState() { @Override public void setTemplateLocation(@NotNull File file) { super.setTemplateLocation(file); update(); } }; } else { myWizardState = new NewModuleWizardState() { @Override public void setTemplateLocation(@NotNull File file) { super.setTemplateLocation(file); update(); } }; } myWizardState.put(ATTR_IS_LAUNCHER, project == null); myWizardState.updateParameters(); if (templateFile != null) { myWizardState.setTemplateLocation(templateFile); } if (inGlobalWizard) { if (myProject != null) { myWizardState.myHidden.add(ATTR_MODULE_NAME); } myWizardState.myHidden.add(ATTR_PROJECT_LOCATION); } Template.convertApisToInt(myWizardState.getParameters()); Iterable<WizardPath> paths = setupWizardPaths(project, sidePanelIcon, disposable); if (inGlobalWizard) { myPaths = Iterables.filter(paths, new Predicate<WizardPath>() { @Override public boolean apply(WizardPath input) { return input.supportsGlobalWizard(); } }); } else { myPaths = paths; } for (WizardPath path : myPaths) { addSteps(path); } myWizardState.setDefaultWizardPath(getDefaultPath()); if (project != null) { myWizardState.put(ATTR_PROJECT_LOCATION, project.getBasePath()); } myWizardState.put(ATTR_GRADLE_VERSION, GRADLE_LATEST_VERSION); myWizardState.put(ATTR_GRADLE_PLUGIN_VERSION, GRADLE_PLUGIN_RECOMMENDED_VERSION); update(); myInitializationComplete = true; } protected WizardPath getDefaultPath() { return myImportSourcesPath; } protected Iterable<WizardPath> setupWizardPaths(@Nullable Project project, @Nullable Icon sidePanelIcon, Disposable disposable) { myImportSourcesPath = new ImportSourceModulePath(myImportSource, myWizardState, new WizardContext(project), sidePanelIcon, this); return ImmutableList.<WizardPath>of(myImportSourcesPath); } protected void addSteps(WizardPath path) { Collection<ModuleWizardStep> steps = path.getSteps(); mySteps.addAll(steps); myStepsToPath.putAll(Maps.toMap(steps, Functions.constant(path))); } public boolean isStepVisible(ModuleWizardStep step) { WizardPath path = myStepsToPath.get(step); return path == null ? step.isStepVisible() : path == myWizardState.getActiveWizardPath() && path.isStepVisible(step); } public boolean updateWizardSteps() { if (!myInitializationComplete) { return false; } myWizardState.getActiveWizardPath().update(); return true; } public void setupModuleBuilder(boolean haveGlobalRepository) { // Hide the library checkbox myWizardState.myHidden.add(ATTR_IS_LIBRARY_MODULE); myWizardState.put(ATTR_PER_MODULE_REPOS, !haveGlobalRepository); } @Override @NotNull public ModuleWizardStep[] createWizardSteps(@NotNull WizardContext wizardContext, @NotNull ModulesProvider modulesProvider) { update(); return mySteps.toArray(new ModuleWizardStep[mySteps.size()]); } @Nullable @Override public ModuleWizardStep modifySettingsStep(@NotNull SettingsStep settingsStep) { if (myWizardState.hasAttr(ATTR_APP_TITLE)) { final String applicationName = myWizardState.getString(ATTR_APP_TITLE); if (!applicationName.isEmpty()) { settingsStep.getModuleNameField().setText(applicationName.replace(" ", "")); } } return null; } @Override public void update() { if (!myInitializationComplete) { return; } updateWizardSteps(); } @Override public void setupRootModel(final @NotNull ModifiableRootModel rootModel) throws ConfigurationException { final Project project = rootModel.getProject(); // in IntelliJ wizard user is able to choose SDK (i.e. for "java library" module), so set it if (myJdk != null){ rootModel.setSdk(myJdk); } else { rootModel.inheritSdk(); } if (myProject == null) { project.putUserData(ExternalSystemDataKeys.NEWLY_IMPORTED_PROJECT, Boolean.TRUE); } StartupManager.getInstance(project).runWhenProjectIsInitialized(new DumbAwareRunnable() { @Override public void run() { ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { if (myProject == null) { myWizardState.putSdkDependentParams(); myWizardState.put(ATTR_PROJECT_LOCATION, project.getBasePath()); AssetStudioAssetGenerator assetGenerator = new AssetStudioAssetGenerator(myWizardState); NewProjectWizard.createProject(myWizardState, project, assetGenerator); } else { myWizardState.put(ATTR_MODULE_NAME, getName()); createModule(); } } }); } }); } }); } @Override @NotNull public ModuleType getModuleType() { return StdModuleTypes.JAVA; } @Override protected ProjectType getProjectType() { return AndroidModuleBuilder.ANDROID_PROJECT_TYPE; } @Override public Icon getBigIcon() { return AndroidIcons.Android24; } @Override public Icon getNodeIcon() { return AndroidIcons.Android; } public void createModule() { createModule(true); } /** * Inflate the chosen template to create the module. * @param performGradleSync if set to true, a sync will be triggered after the template has been created. */ public void createModule(boolean performGradleSync) { WizardPath path = myWizardState.getActiveWizardPath(); path.createModule(); if (performGradleSync && myProject != null) { GradleProjectImporter.getInstance().requestProjectSync(myProject, null); } } @Override public boolean isSuitableSdkType(SdkTypeId sdkType) { boolean isJavaTemplate = myWizardState.isOnDefaultWizardPath() && NewModuleWizardState.isAndroidTemplate(myWizardState.getTemplateMetadata()); return isJavaTemplate ? sdkType instanceof JavaSdkType : AndroidSdkType.getInstance().equals(sdkType); } @Override public void templateChanged(String templateName) { myWizardState.templateChanged(myProject, templateName); // Let the other elements of the wizard update for (ModuleWizardStep step : mySteps) { step.updateStep(); } } @NotNull public Iterable<WizardPath> getPaths() { return myPaths; } }