/* * Copyright (C) 2014 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.tools.idea.gradle.project.GradleProjectImporter; import com.android.tools.idea.gradle.project.NewProjectImportGradleSyncListener; import com.android.tools.idea.templates.KeystoreUtils; import com.android.tools.idea.templates.TemplateManager; import com.android.tools.idea.templates.TemplateUtils; import com.android.tools.idea.wizard.FormFactorUtils.FormFactor; import com.google.common.collect.Lists; import com.intellij.ide.startup.StartupManagerEx; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.pom.java.LanguageLevel; import org.jetbrains.android.sdk.AndroidSdkData; import org.jetbrains.android.sdk.AndroidSdkUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.List; 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.ATTR_JAVA_VERSION; import static com.android.tools.idea.wizard.WizardConstants.APPLICATION_NAME_KEY; import static com.android.tools.idea.wizard.WizardConstants.PROJECT_LOCATION_KEY; /** * Presents a wizard to the user to create a new project. */ public class NewProjectWizardDynamic extends DynamicWizard { private static final String ERROR_MSG_TITLE = "Error in New Project Wizard"; private final List<File> myFilesToOpen = Lists.newArrayList(); public NewProjectWizardDynamic(@Nullable Project project, @Nullable Module module) { super(project, module, "New Project"); setTitle("Create New Project"); } @Override public void init() { if (!AndroidSdkUtils.isAndroidSdkAvailable() || !TemplateManager.templatesAreValid()) { String title = "SDK problem"; String msg = "<html>Your Android SDK is missing, out of date, or is missing templates.<br>" + "You can configure your SDK via <b>Configure | Project Defaults | Project Structure | SDKs</b></html>"; super.init(); Messages.showErrorDialog(msg, title); } addPaths(); initState(); super.init(); } /** * Add the steps for this wizard */ protected void addPaths() { addPath(new ConfigureAndroidProjectPath(getDisposable())); for (NewFormFactorModulePath path : NewFormFactorModulePath.getAvailableFormFactorModulePaths(getDisposable())) { addPath(path); } } /** * Populate our state store with some common configuration items, such as the SDK location and the Gradle configuration. */ protected void initState() { ScopedStateStore state = getState(); state.put(WizardConstants.GRADLE_VERSION_KEY, GRADLE_LATEST_VERSION); state.put(WizardConstants.GRADLE_PLUGIN_VERSION_KEY, GRADLE_PLUGIN_RECOMMENDED_VERSION); state.put(WizardConstants.USE_PER_MODULE_REPOS_KEY, false); state.put(WizardConstants.IS_NEW_PROJECT_KEY, true); state.put(WizardConstants.IS_GRADLE_PROJECT_KEY, true); try { state.put(WizardConstants.DEBUG_KEYSTORE_SHA_1_KEY, KeystoreUtils.sha1(KeystoreUtils.getOrCreateDefaultDebugKeystore())); } catch (Exception e) { LOG.error("Could not create default debug keystore: " + e.getMessage()); state.put(WizardConstants.DEBUG_KEYSTORE_SHA_1_KEY, ""); } AndroidSdkData sdkData = AndroidSdkUtils.tryToChooseAndroidSdk(); if (sdkData != null) { state.put(WizardConstants.SDK_DIR_KEY, sdkData.getLocation().getPath()); } String mavenUrl = System.getProperty(TemplateWizard.MAVEN_URL_PROPERTY); if (mavenUrl != null) { state.put(WizardConstants.MAVEN_URL_KEY, mavenUrl); } } @Override protected String getWizardActionDescription() { return String.format("Create %1$s", getState().get(APPLICATION_NAME_KEY)); } @Override public void performFinishingActions() { if (ApplicationManager.getApplication().isUnitTestMode()) { return; } GradleProjectImporter projectImporter = GradleProjectImporter.getInstance(); String rootPath = getState().get(PROJECT_LOCATION_KEY); if (rootPath == null) { LOG.error("No root path specified for project"); return; } File rootLocation = new File(rootPath); String projectName = getState().get(APPLICATION_NAME_KEY); if (projectName == null) { projectName = "Unnamed Project"; } // Collect files to open for (AndroidStudioWizardPath path : myPaths) { if (path instanceof NewFormFactorModulePath) { myFilesToOpen.addAll(((NewFormFactorModulePath)path).getFilesToOpen()); } } // Pick the highest language level of all the modules/form factors. // We have to pick the language level up front while creating the project rather than // just reacting to it during sync, because otherwise the user gets prompted with // a changing-language-level-requires-reopening modal dialog box and have to reload // the project LanguageLevel initialLanguageLevel = null; Iterator<FormFactor> iterator = FormFactor.iterator(); while (iterator.hasNext()) { FormFactor factor = iterator.next(); Object version = getState().get(FormFactorUtils.getLanguageLevelKey(factor)); if (version != null) { LanguageLevel level = LanguageLevel.parse(version.toString()); if (level != null && (initialLanguageLevel == null || level.isAtLeast(initialLanguageLevel))) { initialLanguageLevel = level; } } } try { projectImporter.importNewlyCreatedProject(projectName, rootLocation, new NewProjectImportGradleSyncListener() { @Override public void syncSucceeded(@NotNull final Project project) { // Open files -- but wait until the Android facets are available, otherwise for example // the layout editor won't add Design tabs to the file StartupManagerEx manager = StartupManagerEx.getInstanceEx(project); if (!manager.postStartupActivityPassed()) { manager.registerPostStartupActivity(new Runnable() { @Override public void run() { openTemplateFiles(project); } }); } else { openTemplateFiles(project); } } private boolean openTemplateFiles(Project project) { return TemplateUtils.openEditors(project, myFilesToOpen, true); } }, null, initialLanguageLevel); } catch (IOException e) { Messages.showErrorDialog(e.getMessage(), ERROR_MSG_TITLE); LOG.error(e); } catch (ConfigurationException e) { Messages.showErrorDialog(e.getMessage(), ERROR_MSG_TITLE); LOG.error(e); } } }