Wizard: add JPS project settings on the first step

This commit is contained in:
Ilya Kirillov
2020-03-19 15:38:04 +03:00
parent 0dc0c41842
commit cca4384371
7 changed files with 174 additions and 46 deletions
@@ -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
)
)
}
@@ -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<IdeaModule>? {
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 }
@@ -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<ModuleIR>,
buildSystem: BuildSystemType
): TaskResult<Unit> = runWriteAction {
ProjectImporter(project, modulesModel, path, modulesIrs)
.import()
): TaskResult<Unit> {
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()
@@ -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)
)
@@ -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
}
}
@@ -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<TitledComponent>,
private val context: Context
) : DynamicComponent(context) {
@@ -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()