Wizard: add project name and path to the first step

This commit is contained in:
Ilya Kirillov
2020-03-13 14:35:29 +03:00
parent cf7bbdde10
commit 586b044235
6 changed files with 83 additions and 36 deletions
@@ -1,8 +1,10 @@
package org.jetbrains.kotlin.tools.projectWizard.wizard package org.jetbrains.kotlin.tools.projectWizard.wizard
import com.intellij.ide.RecentProjectsManager
import com.intellij.ide.projectWizard.ProjectSettingsStep import com.intellij.ide.projectWizard.ProjectSettingsStep
import com.intellij.ide.util.projectWizard.* import com.intellij.ide.util.projectWizard.*
import com.intellij.openapi.Disposable import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationNamesInfo
import com.intellij.openapi.module.ModifiableModuleModel import com.intellij.openapi.module.ModifiableModuleModel
import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.module.ModuleType import com.intellij.openapi.module.ModuleType
@@ -20,14 +22,13 @@ import org.jetbrains.kotlin.idea.projectWizard.UiEditorUsageStats
import org.jetbrains.kotlin.idea.projectWizard.WizardStatsService import org.jetbrains.kotlin.idea.projectWizard.WizardStatsService
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.tools.projectWizard.core.Failure import org.jetbrains.kotlin.tools.projectWizard.core.*
import org.jetbrains.kotlin.tools.projectWizard.core.Success
import org.jetbrains.kotlin.tools.projectWizard.core.entity.StringValidators import org.jetbrains.kotlin.tools.projectWizard.core.entity.StringValidators
import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult
import org.jetbrains.kotlin.tools.projectWizard.core.isSuccess import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.reference
import org.jetbrains.kotlin.tools.projectWizard.core.onFailure
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
import org.jetbrains.kotlin.tools.projectWizard.plugins.Plugins 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.plugins.buildSystem.BuildSystemType
import org.jetbrains.kotlin.tools.projectWizard.plugins.projectTemplates.ProjectTemplatesPlugin import org.jetbrains.kotlin.tools.projectWizard.plugins.projectTemplates.ProjectTemplatesPlugin
import org.jetbrains.kotlin.tools.projectWizard.wizard.service.IdeaServices import org.jetbrains.kotlin.tools.projectWizard.wizard.service.IdeaServices
@@ -37,6 +38,7 @@ import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.firstStep.FirstWizardS
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.runWithProgressBar import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.runWithProgressBar
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.secondStep.SecondStepWizardComponent import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.secondStep.SecondStepWizardComponent
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.io.File
import java.nio.file.Paths import java.nio.file.Paths
import javax.swing.JComponent import javax.swing.JComponent
import com.intellij.openapi.module.Module as IdeaModule import com.intellij.openapi.module.Module as IdeaModule
@@ -117,7 +119,6 @@ class NewProjectWizardModuleBuilder : EmptyModuleBuilder() {
override fun modifySettingsStep(settingsStep: SettingsStep): ModuleWizardStep { override fun modifySettingsStep(settingsStep: SettingsStep): ModuleWizardStep {
updateProjectNameAndPomDate(settingsStep) updateProjectNameAndPomDate(settingsStep)
return when (wizard.buildSystemType) { return when (wizard.buildSystemType) {
BuildSystemType.Jps -> { BuildSystemType.Jps -> {
KotlinModuleSettingStep( KotlinModuleSettingStep(
@@ -149,8 +150,8 @@ class NewProjectWizardModuleBuilder : EmptyModuleBuilder() {
ProjectTemplatesPlugin::template.settingValue.suggestedProjectName.decapitalize() ProjectTemplatesPlugin::template.settingValue.suggestedProjectName.decapitalize()
} }
settingsStep.moduleNameLocationSettings?.apply { settingsStep.moduleNameLocationSettings?.apply {
val projectParentDirectory = moduleContentRoot.let { Paths.get(it).parent.toString() } moduleName = wizard.projectName!!
moduleName = ProjectWizardUtil.findNonExistingFileName(projectParentDirectory, suggestedProjectName, "") moduleContentRoot = wizard.projectPath!!.toString()
} }
settingsStep.safeAs<ProjectSettingsStep>()?.bindModuleSettings() settingsStep.safeAs<ProjectSettingsStep>()?.bindModuleSettings()
@@ -184,7 +185,7 @@ class NewProjectWizardModuleBuilder : EmptyModuleBuilder() {
abstract class WizardStep(protected val wizard: IdeWizard, private val phase: GenerationPhase) : ModuleWizardStep() { abstract class WizardStep(protected val wizard: IdeWizard, private val phase: GenerationPhase) : ModuleWizardStep() {
override fun updateDataModel() = Unit // model is updated on every UI action override fun updateDataModel() = Unit // model is updated on every UI action
override fun validate(): Boolean = override fun validate(): Boolean =
when (val result = wizard.context.read{ with(wizard) { validate(setOf(phase)) } }) { when (val result = wizard.context.read { with(wizard) { validate(setOf(phase)) } }) {
is Success<*> -> true is Success<*> -> true
is Failure -> { is Failure -> {
throw ConfigurationException(result.asHtml(), KotlinNewProjectWizardBundle.message("error.validation")) throw ConfigurationException(result.asHtml(), KotlinNewProjectWizardBundle.message("error.validation"))
@@ -214,6 +215,7 @@ class ModuleNewWizardFirstStep(wizard: IdeWizard) : WizardStep(wizard, Generatio
init { init {
runPreparePhase() runPreparePhase()
initDefaultProjectNameAndPathValues()
component.onInit() component.onInit()
} }
@@ -222,6 +224,26 @@ class ModuleNewWizardFirstStep(wizard: IdeWizard) : WizardStep(wizard, Generatio
ProgressManager.getInstance().progressIndicator.text = task.title ?: "" ProgressManager.getInstance().progressIndicator.text = task.title ?: ""
} }
} }
private fun initDefaultProjectNameAndPathValues() {
val suggestedProjectParentLocation = suggestProjectLocation()
val suggestedProjectName = ProjectWizardUtil.findNonExistingFileName(suggestedProjectParentLocation, "untitled", "")
wizard.context.writeSettings {
StructurePlugin::name.reference.setValue(suggestedProjectName)
StructurePlugin::projectPath.reference.setValue(suggestedProjectParentLocation / suggestedProjectName)
}
}
// copied from com.intellij.ide.util.projectWizard.WizardContext.getProjectFileDirectory
private fun suggestProjectLocation(): String {
val lastProjectLocation = RecentProjectsManager.getInstance().lastProjectCreationLocation
if (lastProjectLocation != null) {
return lastProjectLocation.replace('/', File.separatorChar)
}
val userHome = SystemProperties.getUserHome()
val productName = ApplicationNamesInfo.getInstance().lowercaseProductName
return userHome.replace('/', File.separatorChar) + File.separator + productName.replace(" ", "") + "Projects"
}
} }
class ModuleNewWizardSecondStep( class ModuleNewWizardSecondStep(
@@ -13,19 +13,19 @@ class PomWizardStepComponent(context: Context) : WizardStepComponent(context) {
private val groupIdComponent = StringSettingComponent( private val groupIdComponent = StringSettingComponent(
StructurePlugin::groupId.reference, StructurePlugin::groupId.reference,
context, context,
showLabel = true needLabel = true
).asSubComponent() ).asSubComponent()
private val artifactIdComponent = StringSettingComponent( private val artifactIdComponent = StringSettingComponent(
StructurePlugin::artifactId.reference, StructurePlugin::artifactId.reference,
context, context,
showLabel = true needLabel = true
).asSubComponent() ).asSubComponent()
private val versionComponent = StringSettingComponent( private val versionComponent = StringSettingComponent(
StructurePlugin::version.reference, StructurePlugin::version.reference,
context, context,
showLabel = true needLabel = true
).asSubComponent() ).asSubComponent()
@@ -1,15 +1,21 @@
package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.firstStep package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.firstStep
import TemplateTag import TemplateTag
import com.intellij.ide.plugins.newui.VerticalLayout
import com.intellij.util.ui.JBUI import com.intellij.util.ui.JBUI
import org.jetbrains.kotlin.tools.projectWizard.core.Context import org.jetbrains.kotlin.tools.projectWizard.core.Context
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.SettingReference 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.core.entity.settings.reference
import org.jetbrains.kotlin.tools.projectWizard.plugins.StructurePlugin
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.KotlinPlugin
import org.jetbrains.kotlin.tools.projectWizard.plugins.projectTemplates.ProjectTemplatesPlugin import org.jetbrains.kotlin.tools.projectWizard.plugins.projectTemplates.ProjectTemplatesPlugin
import org.jetbrains.kotlin.tools.projectWizard.plugins.projectTemplates.applyProjectTemplate import org.jetbrains.kotlin.tools.projectWizard.plugins.projectTemplates.applyProjectTemplate
import org.jetbrains.kotlin.tools.projectWizard.projectTemplates.ProjectTemplate import org.jetbrains.kotlin.tools.projectWizard.projectTemplates.ProjectTemplate
import org.jetbrains.kotlin.tools.projectWizard.wizard.IdeWizard import org.jetbrains.kotlin.tools.projectWizard.wizard.IdeWizard
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.* import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.*
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.PathSettingComponent
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.SettingsList
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.StringSettingComponent
import java.awt.BorderLayout import java.awt.BorderLayout
import javax.swing.Box import javax.swing.Box
import javax.swing.BoxLayout import javax.swing.BoxLayout
@@ -17,11 +23,18 @@ import javax.swing.JComponent
import java.awt.Component as AwtComponent import java.awt.Component as AwtComponent
class FirstWizardStepComponent(wizard: IdeWizard) : WizardStepComponent(wizard.context) { class FirstWizardStepComponent(wizard: IdeWizard) : WizardStepComponent(wizard.context) {
private val nameAndLocationComponent = SettingsList(
listOf(
StructurePlugin::name.reference,
StructurePlugin::projectPath.reference
),
wizard.context
).asSubComponent()
private val buildSystemSubStep = BuildSystemSubStep(wizard.context).asSubComponent() private val buildSystemSubStep = BuildSystemSubStep(wizard.context).asSubComponent()
private val templatesSubStep = TemplatesSubStep(wizard.context).asSubComponent() private val templatesSubStep = TemplatesSubStep(wizard.context).asSubComponent()
override val component: JComponent = panel { override val component: JComponent = panel {
add(templatesSubStep.component, BorderLayout.CENTER) add(nameAndLocationComponent.component, BorderLayout.CENTER)
add(buildSystemSubStep.component, BorderLayout.SOUTH) add(buildSystemSubStep.component, BorderLayout.SOUTH)
} }
} }
@@ -23,7 +23,8 @@ object DefaultSettingComponent {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun <V : Any, T : SettingType<V>> create( fun <V : Any, T : SettingType<V>> create(
setting: SettingReference<V, T>, setting: SettingReference<V, T>,
context: Context context: Context,
needLabel: Boolean = true
): SettingComponent<V, T> = when (setting.type) { ): SettingComponent<V, T> = when (setting.type) {
VersionSettingType::class -> VersionSettingType::class ->
VersionSettingComponent( VersionSettingComponent(
@@ -33,22 +34,26 @@ object DefaultSettingComponent {
BooleanSettingType::class -> BooleanSettingType::class ->
BooleanSettingComponent( BooleanSettingComponent(
setting as SettingReference<Boolean, BooleanSettingType>, setting as SettingReference<Boolean, BooleanSettingType>,
context context,
needLabel
) as SettingComponent<V, T> ) as SettingComponent<V, T>
DropDownSettingType::class -> DropDownSettingType::class ->
DropdownSettingComponent( DropdownSettingComponent(
setting as SettingReference<DisplayableSettingItem, DropDownSettingType<DisplayableSettingItem>>, setting as SettingReference<DisplayableSettingItem, DropDownSettingType<DisplayableSettingItem>>,
context context,
needLabel
) as SettingComponent<V, T> ) as SettingComponent<V, T>
StringSettingType::class -> StringSettingType::class ->
StringSettingComponent( StringSettingComponent(
setting as SettingReference<String, StringSettingType>, setting as SettingReference<String, StringSettingType>,
context context,
needLabel
) as SettingComponent<V, T> ) as SettingComponent<V, T>
PathSettingType::class -> PathSettingType::class ->
PathSettingComponent( PathSettingComponent(
setting as SettingReference<Path, PathSettingType>, setting as SettingReference<Path, PathSettingType>,
context context,
needLabel
) as SettingComponent<V, T> ) as SettingComponent<V, T>
else -> TODO(setting.type.qualifiedName!!) else -> TODO(setting.type.qualifiedName!!)
} }
@@ -94,7 +99,8 @@ class VersionSettingComponent(
class DropdownSettingComponent( class DropdownSettingComponent(
reference: SettingReference<DisplayableSettingItem, DropDownSettingType<DisplayableSettingItem>>, reference: SettingReference<DisplayableSettingItem, DropDownSettingType<DisplayableSettingItem>>,
context: Context context: Context,
needLabel: Boolean = true
) : UIComponentDelegatingSettingComponent<DisplayableSettingItem, DropDownSettingType<DisplayableSettingItem>>( ) : UIComponentDelegatingSettingComponent<DisplayableSettingItem, DropDownSettingType<DisplayableSettingItem>>(
reference, reference,
context context
@@ -106,14 +112,15 @@ class DropdownSettingComponent(
filter = { value -> filter = { value ->
context.read { setting.type.filter(this, reference, value) } context.read { setting.type.filter(this, reference, value) }
}, },
labelText = setting.title, labelText = setting.title.takeIf { needLabel },
onValueUpdate = { newValue -> value = newValue } onValueUpdate = { newValue -> value = newValue }
).asSubComponent() ).asSubComponent()
} }
class BooleanSettingComponent( class BooleanSettingComponent(
reference: SettingReference<Boolean, BooleanSettingType>, reference: SettingReference<Boolean, BooleanSettingType>,
context: Context context: Context,
needLabel: Boolean = true
) : UIComponentDelegatingSettingComponent<Boolean, BooleanSettingType>( ) : UIComponentDelegatingSettingComponent<Boolean, BooleanSettingType>(
reference, reference,
context context
@@ -130,7 +137,7 @@ class BooleanSettingComponent(
class StringSettingComponent( class StringSettingComponent(
reference: SettingReference<String, StringSettingType>, reference: SettingReference<String, StringSettingType>,
context: Context, context: Context,
showLabel: Boolean = true needLabel: Boolean = true
) : UIComponentDelegatingSettingComponent<String, StringSettingType>( ) : UIComponentDelegatingSettingComponent<String, StringSettingType>(
reference, reference,
context context
@@ -138,7 +145,7 @@ class StringSettingComponent(
override val uiComponent = TextFieldComponent( override val uiComponent = TextFieldComponent(
context = context, context = context,
initialValue = null, initialValue = null,
labelText = if (showLabel) setting.title else null, labelText = setting.title.takeIf { needLabel },
validator = setting.validator, validator = setting.validator,
onValueUpdate = { newValue -> value = newValue } onValueUpdate = { newValue -> value = newValue }
).asSubComponent() ).asSubComponent()
@@ -146,14 +153,15 @@ class StringSettingComponent(
class PathSettingComponent( class PathSettingComponent(
reference: SettingReference<Path, PathSettingType>, reference: SettingReference<Path, PathSettingType>,
context: Context context: Context,
needLabel: Boolean = true
) : UIComponentDelegatingSettingComponent<Path, PathSettingType>( ) : UIComponentDelegatingSettingComponent<Path, PathSettingType>(
reference, reference,
context context
) { ) {
override val uiComponent = PathFieldComponent( override val uiComponent = PathFieldComponent(
context = context, context = context,
labelText = setting.title, labelText = setting.title.takeIf { needLabel },
validator = settingValidator { path -> setting.validator.validate(this, path) }, validator = settingValidator { path -> setting.validator.validate(this, path) },
onValueUpdate = { newValue -> value = newValue } onValueUpdate = { newValue -> value = newValue }
).asSubComponent() ).asSubComponent()
@@ -1,14 +1,13 @@
package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting
import com.intellij.ui.components.panels.VerticalLayout import com.intellij.ui.layout.panel
import com.intellij.util.ui.components.BorderLayoutPanel
import org.jetbrains.kotlin.tools.projectWizard.core.Context import org.jetbrains.kotlin.tools.projectWizard.core.Context
import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult
import org.jetbrains.kotlin.tools.projectWizard.core.entity.isSpecificError import org.jetbrains.kotlin.tools.projectWizard.core.entity.isSpecificError
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.SettingReference import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.SettingReference
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.DynamicComponent 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.FocusableComponent
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.PanelWithStatusText
import javax.swing.JComponent
interface ErrorAwareComponent { interface ErrorAwareComponent {
fun findComponentWithError(error: ValidationResult.ValidationError): FocusableComponent? fun findComponentWithError(error: ValidationResult.ValidationError): FocusableComponent?
@@ -18,16 +17,15 @@ class SettingsList(
settings: List<SettingReference<*, *>>, settings: List<SettingReference<*, *>>,
private val context: Context private val context: Context
) : DynamicComponent(context), ErrorAwareComponent { ) : DynamicComponent(context), ErrorAwareComponent {
private val panel = PanelWithStatusText(VerticalLayout(5), "This module has no settings to configure") private val ui = BorderLayoutPanel()
var settingComponents: List<SettingComponent<*, *>> = emptyList() private var settingComponents: List<SettingComponent<*, *>> = emptyList()
private set
init { init {
setSettings(settings) setSettings(settings)
} }
override val component: JComponent = panel override val component get() = ui
override fun onInit() { override fun onInit() {
super.onInit() super.onInit()
@@ -35,12 +33,18 @@ class SettingsList(
} }
fun setSettings(settings: List<SettingReference<*, *>>) { fun setSettings(settings: List<SettingReference<*, *>>) {
panel.isStatusTextVisible = settings.isEmpty() ui.removeAll()
panel.removeAll()
settingComponents = settings.map { setting -> settingComponents = settings.map { setting ->
DefaultSettingComponent.create(setting, context) DefaultSettingComponent.create(setting, context, needLabel = false)
} }
settingComponents.forEach { setting -> setting.onInit(); panel.add(setting.component) } ui.addToCenter(panel {
settingComponents.forEach { settingComponent ->
settingComponent.onInit()
row(settingComponent.setting.title + ":") {
settingComponent.component(growX)
}
}
})
} }
override fun findComponentWithError(error: ValidationResult.ValidationError) = read { override fun findComponentWithError(error: ValidationResult.ValidationError) = read {
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.tools.projectWizard.settings.version.Version
import java.nio.file.Paths import java.nio.file.Paths
class StructurePlugin(context: Context) : Plugin(context) { class StructurePlugin(context: Context) : Plugin(context) {
val projectPath by valueSetting("Root path", GenerationPhase.PROJECT_GENERATION, pathParser) { val projectPath by pathSetting("Root path", GenerationPhase.PROJECT_GENERATION) {
defaultValue = value(Paths.get(".")) defaultValue = value(Paths.get("."))
} }
val name by stringSetting("Name", GenerationPhase.PROJECT_GENERATION) val name by stringSetting("Name", GenerationPhase.PROJECT_GENERATION)