From cca4384371c2d9340ed6dfe066f29252b2337e8a Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Thu, 19 Mar 2020 15:38:04 +0300 Subject: [PATCH] Wizard: add JPS project settings on the first step --- .../tools/projectWizard/wizard/IdeWizard.kt | 27 ++++ .../wizard/NewProjectWizardModuleBuilder.kt | 8 +- .../wizard/service/IdeaJpsWizardService.kt | 54 +++++--- .../wizard/service/IdeaWizardService.kt | 4 +- .../ui/firstStep/FirstWizardStepComponent.kt | 123 ++++++++++++++---- .../wizard/ui/setting/TitledComponentsList.kt | 2 +- .../AbstractNewWizardProjectImportTest.kt | 2 +- 7 files changed, 174 insertions(+), 46 deletions(-) diff --git a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/IdeWizard.kt b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/IdeWizard.kt index eb20261044e..e1ed34a0d8a 100644 --- a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/IdeWizard.kt +++ b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/IdeWizard.kt @@ -1,5 +1,13 @@ package org.jetbrains.kotlin.tools.projectWizard.wizard +import com.intellij.facet.impl.ui.libraries.LibraryOptionsPanel +import com.intellij.framework.library.FrameworkLibraryVersionFilter +import com.intellij.openapi.project.Project +import com.intellij.openapi.projectRoots.Sdk +import com.intellij.openapi.roots.ui.configuration.libraries.CustomLibraryDescription +import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainer +import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainerFactory +import org.jetbrains.kotlin.idea.framework.JavaRuntimeLibraryDescription import org.jetbrains.kotlin.tools.projectWizard.core.PluginsCreator import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.SettingReference import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.SettingType @@ -29,6 +37,12 @@ class IdeWizard( initPluginSettingsDefaultValues() } + val jpsData = JpsData( + JavaRuntimeLibraryDescription(null), + LibrariesContainerFactory.createContainer(null as Project?), + ) + + var projectPath by setting(StructurePlugin::projectPath.reference) var projectName by setting(StructurePlugin::name.reference) @@ -51,5 +65,18 @@ class IdeWizard( reference.notRequiredSettingValue } } + + data class JpsData( + val libraryDescription: JavaRuntimeLibraryDescription, + val librariesContainer: LibrariesContainer, + var jdk: Sdk? = null, + val libraryOptionsPanel: LibraryOptionsPanel = LibraryOptionsPanel( + libraryDescription, + "", + FrameworkLibraryVersionFilter.ALL, + librariesContainer, + false + ) + ) } diff --git a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/NewProjectWizardModuleBuilder.kt b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/NewProjectWizardModuleBuilder.kt index 36b119c1981..0d9f1df8d6e 100644 --- a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/NewProjectWizardModuleBuilder.kt +++ b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/NewProjectWizardModuleBuilder.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase import org.jetbrains.kotlin.tools.projectWizard.plugins.Plugins import org.jetbrains.kotlin.tools.projectWizard.plugins.StructurePlugin import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.BuildSystemType +import org.jetbrains.kotlin.tools.projectWizard.wizard.service.IdeaJpsWizardService import org.jetbrains.kotlin.tools.projectWizard.wizard.service.IdeaServices import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.asHtml import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.firstStep.FirstWizardStepComponent @@ -82,8 +83,11 @@ class NewProjectWizardModuleBuilder : EmptyModuleBuilder() { ): List? { val modulesModel = model ?: ModuleManager.getInstance(project).modifiableModel val success = wizard.apply( - services = IdeaServices.createScopeDependent(project, modulesModel) + - IdeaServices.PROJECT_INDEPENDENT, + services = buildList { + +IdeaServices.createScopeDependent(project) + +IdeaServices.PROJECT_INDEPENDENT + +IdeaJpsWizardService(project, modulesModel, this@NewProjectWizardModuleBuilder, wizard) + }, phases = GenerationPhase.startingFrom(GenerationPhase.FIRST_STEP) ).onFailure { errors -> val errorMessages = errors.joinToString(separator = "\n") { it.message } diff --git a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/service/IdeaJpsWizardService.kt b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/service/IdeaJpsWizardService.kt index b5cdf49a76c..abd07712f5d 100644 --- a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/service/IdeaJpsWizardService.kt +++ b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/service/IdeaJpsWizardService.kt @@ -6,19 +6,20 @@ package org.jetbrains.kotlin.tools.projectWizard.wizard.service import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix +import com.intellij.ide.impl.NewProjectUtil +import com.intellij.ide.util.projectWizard.ModuleBuilder import com.intellij.jarRepository.JarRepositoryManager import com.intellij.openapi.module.ModifiableModuleModel import com.intellij.openapi.module.ModuleTypeId import com.intellij.openapi.project.Project -import com.intellij.openapi.roots.DependencyScope -import com.intellij.openapi.roots.ModuleRootManager -import com.intellij.openapi.roots.ModuleRootModificationUtil -import com.intellij.openapi.roots.OrderRootType +import com.intellij.openapi.roots.* import com.intellij.openapi.vfs.VfsUtil import com.intellij.util.PathUtil import org.jetbrains.idea.maven.utils.library.RepositoryLibraryProperties import org.jetbrains.jps.model.java.JavaResourceRootType import org.jetbrains.jps.model.java.JavaSourceRootType +import org.jetbrains.kotlin.idea.formatter.KotlinStyleGuideCodeStyle.Companion.INSTANCE +import org.jetbrains.kotlin.idea.formatter.ProjectCodeStyleImporter import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.tools.projectWizard.core.* import org.jetbrains.kotlin.tools.projectWizard.core.service.ProjectImportingWizardService @@ -26,12 +27,18 @@ import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.* import org.jetbrains.kotlin.tools.projectWizard.library.MavenArtifact import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.BuildSystemType import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.SourcesetType +import org.jetbrains.kotlin.tools.projectWizard.wizard.IdeWizard +import org.jetbrains.kotlin.tools.projectWizard.wizard.NewProjectWizardModuleBuilder +import org.jetbrains.kotlin.idea.framework.KotlinSdkType import java.nio.file.Path +import java.util.* import com.intellij.openapi.module.Module as IdeaModule class IdeaJpsWizardService( private val project: Project, - private val modulesModel: ModifiableModuleModel + private val modulesModel: ModifiableModuleModel, + private val modulesBuilder: NewProjectWizardModuleBuilder, + private val ideWizard: IdeWizard ) : ProjectImportingWizardService, IdeaWizardService { override fun isSuitableFor(buildSystemType: BuildSystemType): Boolean = buildSystemType == BuildSystemType.Jps @@ -40,9 +47,26 @@ class IdeaJpsWizardService( path: Path, modulesIrs: List, buildSystem: BuildSystemType - ): TaskResult = runWriteAction { - ProjectImporter(project, modulesModel, path, modulesIrs) - .import() + ): TaskResult { + ideWizard.jpsData.jdk?.let { jdk -> NewProjectUtil.applyJdkToProject(project, jdk) } + KotlinSdkType.setUpIfNeeded() + modulesBuilder.addModuleConfigurationUpdater(JpsModuleConfigurationUpdater(ideWizard.jpsData)) + + return runWriteAction { + ProjectImporter(project, modulesModel, path, modulesIrs).import() + } + } +} + +private class JpsModuleConfigurationUpdater(private val jpsData: IdeWizard.JpsData) : ModuleBuilder.ModuleConfigurationUpdater() { + override fun update(module: IdeaModule, rootModel: ModifiableRootModel) = with(jpsData) { + libraryOptionsPanel.apply()?.addLibraries( + rootModel, + ArrayList(), + librariesContainer + ) + libraryDescription.finishLibConfiguration(module, rootModel, true) + ProjectCodeStyleImporter.apply(module.project, INSTANCE) } } @@ -146,13 +170,13 @@ private class ProjectImporter( private fun downloadLibraryAndGetItsClasses(libraryProperties: RepositoryLibraryProperties) = JarRepositoryManager.loadDependenciesModal( - project, - libraryProperties, - false, - false, - librariesPath.toString(), - null - ).asSequence() + project, + libraryProperties, + false, + false, + librariesPath.toString(), + null + ).asSequence() .filter { it.type == OrderRootType.CLASSES } .map { PathUtil.getLocalPath(it.file) } .toList() diff --git a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/service/IdeaWizardService.kt b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/service/IdeaWizardService.kt index 674474d2bfa..ef828c66005 100644 --- a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/service/IdeaWizardService.kt +++ b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/service/IdeaWizardService.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.tools.projectWizard.wizard.service -import com.intellij.openapi.module.ModifiableModuleModel import com.intellij.openapi.project.Project import org.jetbrains.kotlin.tools.projectWizard.core.service.WizardService @@ -19,10 +18,9 @@ object IdeaServices { IdeaSettingSavingWizardService() ) - fun createScopeDependent(project: Project, model: ModifiableModuleModel?) = listOfNotNull( + fun createScopeDependent(project: Project) = listOfNotNull( IdeaGradleWizardService(project), IdeaMavenWizardService(project), - model?.let { IdeaJpsWizardService(project, it) }, IdeaFileFormattingService(project), IdeaRunConfigurationsService(project) ) diff --git a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/firstStep/FirstWizardStepComponent.kt b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/firstStep/FirstWizardStepComponent.kt index 3f899db5d5b..759b4e47b3c 100644 --- a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/firstStep/FirstWizardStepComponent.kt +++ b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/firstStep/FirstWizardStepComponent.kt @@ -1,17 +1,23 @@ package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.firstStep import com.intellij.icons.AllIcons +import com.intellij.ide.util.projectWizard.JavaModuleBuilder +import com.intellij.openapi.roots.ui.configuration.JdkComboBox +import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel +import com.intellij.openapi.util.Condition import com.intellij.ui.JBColor import com.intellij.ui.TitledSeparator import com.intellij.ui.layout.panel -import com.intellij.util.io.size import com.intellij.util.ui.JBUI import com.intellij.util.ui.components.BorderLayoutPanel +import org.jetbrains.kotlin.idea.framework.KotlinModuleBuilder import org.jetbrains.kotlin.tools.projectWizard.core.Context import org.jetbrains.kotlin.tools.projectWizard.core.entity.path import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.SettingReference import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.reference import org.jetbrains.kotlin.tools.projectWizard.plugins.StructurePlugin +import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.BuildSystemPlugin +import org.jetbrains.kotlin.tools.projectWizard.plugins.buildSystem.BuildSystemType import org.jetbrains.kotlin.tools.projectWizard.plugins.projectTemplates.ProjectTemplatesPlugin import org.jetbrains.kotlin.tools.projectWizard.wizard.IdeWizard import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.* @@ -22,9 +28,9 @@ import java.awt.event.MouseAdapter import java.awt.event.MouseEvent import javax.swing.JComponent -class FirstWizardStepComponent(wizard: IdeWizard) : WizardStepComponent(wizard.context) { - private val context = wizard.context - private val projectSettingsComponent = ProjectSettingsComponent(context).asSubComponent() +class FirstWizardStepComponent(ideWizard: IdeWizard) : WizardStepComponent(ideWizard.context) { + private val context = ideWizard.context + private val projectSettingsComponent = ProjectSettingsComponent(ideWizard).asSubComponent() private val projectPreviewComponent = ProjectPreviewComponent(context).asSubComponent() override val component: JComponent = borderPanel { @@ -33,10 +39,11 @@ class FirstWizardStepComponent(wizard: IdeWizard) : WizardStepComponent(wizard.c } } -class ProjectSettingsComponent(context: Context) : DynamicComponent(context) { +class ProjectSettingsComponent(ideWizard: IdeWizard) : DynamicComponent(ideWizard.context) { + private val context = ideWizard.context private val projectTemplateComponent = ProjectTemplateSettingComponent(context).asSubComponent() private val buildSystemSetting = BuildSystemTypeSettingComponent(context).asSubComponent() - private val buildSystemAdditionalSettingsComponent = BuildSystemAdditionalSettingsComponent(context).asSubComponent() + private val buildSystemAdditionalSettingsComponent = BuildSystemAdditionalSettingsComponent(ideWizard).asSubComponent() private val nameAndLocationComponent = TitledComponentsList( listOf( @@ -98,38 +105,106 @@ class ProjectSettingsComponent(context: Context) : DynamicComponent(context) { } } -class BuildSystemAdditionalSettingsComponent(context: Context) : DynamicComponent(context) { - private val settingsList = TitledComponentsList( - listOf( - StructurePlugin::groupId.reference.createSettingComponent(context), - StructurePlugin::artifactId.reference.createSettingComponent(context), - StructurePlugin::version.reference.createSettingComponent(context) - ), - context - ).asSubComponent() +class BuildSystemAdditionalSettingsComponent(ideWizard: IdeWizard) : DynamicComponent(ideWizard.context) { + private val pomSettingsList = PomSettingsComponent(ideWizard.context).asSubComponent() + private val kotlinJpsRuntimeComponent = KotlinJpsRuntimeComponent(ideWizard).asSubComponent() - override val component: JComponent = HideableSection("Artifact Coordinates", settingsList.component) + override fun onValueUpdated(reference: SettingReference<*, *>?) { + super.onValueUpdated(reference) + if (reference == BuildSystemPlugin::type.reference) { + updateBuildSystemComponent() + } + } + + override fun onInit() { + super.onInit() + updateBuildSystemComponent() + } + + private fun updateBuildSystemComponent() { + val buildSystemType = read { BuildSystemPlugin::type.settingValue() } + val state = buildSystemType.state() + section.updateTitleAndComponent(state.sectionTitle, state.component) + } + + private enum class State(val sectionTitle: String) { + POM("Artifact Coordinates"), JPS("Kotlin Runtime") + } + + private fun BuildSystemType.state() = + if (this == BuildSystemType.Jps) State.JPS + else State.POM + + private val State.component + get() = when (this) { + State.POM -> pomSettingsList.component + State.JPS -> kotlinJpsRuntimeComponent.component + } + + private val section = HideableSection(State.POM.sectionTitle, State.POM.component) + + override val component: JComponent = section +} + +private class PomSettingsComponent(context: Context) : TitledComponentsList( + listOf( + StructurePlugin::groupId.reference.createSettingComponent(context), + StructurePlugin::artifactId.reference.createSettingComponent(context), + StructurePlugin::version.reference.createSettingComponent(context) + ), + context +) + +class KotlinJpsRuntimeComponent(ideWizard: IdeWizard) : DynamicComponent(ideWizard.context) { + private val javaModuleBuilder = JavaModuleBuilder() + private val jdkComboBox = JdkComboBox( + ProjectSdksModel().apply { reset(null) }, + Condition(javaModuleBuilder::isSuitableSdkType) + ).apply { + ideWizard.jpsData.jdk = selectedJdk + addActionListener { + ideWizard.jpsData.jdk = selectedJdk + } + } + override val component: JComponent = panel { + row("Project JDK:") { + borderPanel { addToCenter(jdkComboBox) }.addBorder(JBUI.Borders.empty(0, 7))(growX) + } + row("Kotlin Runtime:") { + ideWizard.jpsData.libraryOptionsPanel.simplePanel(growX) + } + } } @Suppress("SpellCheckingInspection") -private class HideableSection(text: String, private val component: JComponent) : BorderLayoutPanel() { +private class HideableSection(text: String, private var component: JComponent) : BorderLayoutPanel() { private val titledSeparator = TitledSeparator(text) private var isExpanded = false init { - addToTop(titledSeparator) - addToCenter(component) - update(isExpanded) - - addMouseListener(object : MouseAdapter() { + updateComponent(component) + titledSeparator.addMouseListener(object : MouseAdapter() { override fun mouseReleased(e: MouseEvent) = update(!isExpanded) }) } + fun updateTitleAndComponent(newTitle: String, newComponent: JComponent) { + titledSeparator.text = newTitle + updateComponent(newComponent) + } + + private fun updateComponent(newComponent: JComponent) { + component = newComponent + removeAll() + addToTop(titledSeparator) + addToCenter(newComponent) + update(isExpanded) + } + private fun update(isExpanded: Boolean) { this.isExpanded = isExpanded - component.isVisible = this.isExpanded - titledSeparator.label.icon = if (this.isExpanded) AllIcons.General.ArrowDown else AllIcons.General.ArrowRight + component.isVisible = isExpanded + titledSeparator.label.icon = if (isExpanded) AllIcons.General.ArrowDown else AllIcons.General.ArrowRight } } diff --git a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/setting/TitledComponentsList.kt b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/setting/TitledComponentsList.kt index 1393c5a02c4..a172d0e6d06 100644 --- a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/setting/TitledComponentsList.kt +++ b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/setting/TitledComponentsList.kt @@ -9,7 +9,7 @@ import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.DynamicComponent import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.FocusableComponent import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.TitledComponent -class TitledComponentsList( +open class TitledComponentsList( private var components: List, private val context: Context ) : DynamicComponent(context) { diff --git a/idea/idea-new-project-wizard/tests/org/jetbrains/kotlin/tools/projectWizard/wizard/AbstractNewWizardProjectImportTest.kt b/idea/idea-new-project-wizard/tests/org/jetbrains/kotlin/tools/projectWizard/wizard/AbstractNewWizardProjectImportTest.kt index 8ec7409da2d..c74ae11a5c9 100644 --- a/idea/idea-new-project-wizard/tests/org/jetbrains/kotlin/tools/projectWizard/wizard/AbstractNewWizardProjectImportTest.kt +++ b/idea/idea-new-project-wizard/tests/org/jetbrains/kotlin/tools/projectWizard/wizard/AbstractNewWizardProjectImportTest.kt @@ -72,7 +72,7 @@ abstract class AbstractNewWizardProjectImportTest : PlatformTestCase() { val wizard = createWizard(directory, buildSystem, tempDirectory) val projectDependentServices = - IdeaServices.createScopeDependent(project, null) + + IdeaServices.createScopeDependent(project) + TestWizardServices.createProjectDependent(project) + TestWizardServices.PROJECT_INDEPENDENT wizard.apply(projectDependentServices, GenerationPhase.ALL).assertSuccess()