Wizard: do not allow to choose Frontend Application template & JS Library at the same time

#KT-40371 fixed
This commit is contained in:
Ilya Kirillov
2020-07-16 19:56:00 +03:00
parent fdc06b2c1c
commit 0208fad057
7 changed files with 94 additions and 29 deletions
@@ -1,5 +1,6 @@
package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.components package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.components
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.ui.ComboBox import com.intellij.openapi.ui.ComboBox
import com.intellij.ui.ColoredListCellRenderer import com.intellij.ui.ColoredListCellRenderer
import com.intellij.ui.SimpleTextAttributes import com.intellij.ui.SimpleTextAttributes
@@ -13,13 +14,14 @@ import java.awt.event.ItemEvent
import javax.swing.DefaultComboBoxModel import javax.swing.DefaultComboBoxModel
import javax.swing.Icon import javax.swing.Icon
import javax.swing.JList import javax.swing.JList
import javax.swing.SwingUtilities
class DropDownComponent<T : DisplayableSettingItem>( class DropDownComponent<T : DisplayableSettingItem>(
context: Context, context: Context,
initialValues: List<T> = emptyList(), private val initialValues: List<T> = emptyList(),
initiallySelectedValue: T? = null, initiallySelectedValue: T? = null,
labelText: String? = null, labelText: String? = null,
filter: (T) -> Boolean = { true }, private val filter: (T) -> Boolean = { true },
private val validator: SettingValidator<T> = settingValidator { ValidationResult.OK }, private val validator: SettingValidator<T> = settingValidator { ValidationResult.OK },
private val iconProvider: (T) -> Icon? = { null }, private val iconProvider: (T) -> Icon? = { null },
onValueUpdate: (T) -> Unit = {} onValueUpdate: (T) -> Unit = {}
@@ -68,6 +70,32 @@ class DropDownComponent<T : DisplayableSettingItem>(
} }
} }
fun filterValues() {
val selectedItem = model.selectedItem
safeUpdateUi {
model.removeAllElements()
initialValues.filter(filter).forEach(model::addElement)
when {
model.getIndexOf(selectedItem) != -1 -> {
model.selectedItem = selectedItem
}
model.size != 0 -> {
uiComponent.selectedIndex = 0
uiComponent.selectedItem?.let {
ApplicationManager.getApplication().invokeLater {
@Suppress("UNCHECKED_CAST")
forceValueUpdate(it as T)
}
}
}
}
}
uiComponent.repaint()
}
private val model get() = uiComponent.model as DefaultComboBoxModel
val valuesCount val valuesCount
get() = uiComponent.model.size get() = uiComponent.model.size
@@ -51,6 +51,10 @@ abstract class UIComponent<V : Any>(
validate(value) validate(value)
} }
protected fun forceValueUpdate(newValue: V) {
onValueUpdate(newValue)
}
override fun onInit() { override fun onInit() {
super.onInit() super.onInit()
getUiValue()?.let(::validate) getUiValue()?.let(::validate)
@@ -1,12 +1,11 @@
package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.secondStep package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.secondStep
import com.intellij.ui.components.JBLabel
import com.intellij.util.ui.JBUI import com.intellij.util.ui.JBUI
import com.intellij.util.ui.UIUtil
import org.jetbrains.kotlin.idea.projectWizard.UiEditorUsageStats import org.jetbrains.kotlin.idea.projectWizard.UiEditorUsageStats
import org.jetbrains.kotlin.tools.projectWizard.core.Context import org.jetbrains.kotlin.tools.projectWizard.core.Context
import org.jetbrains.kotlin.tools.projectWizard.core.Reader import org.jetbrains.kotlin.tools.projectWizard.core.Reader
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.settings.SettingReference
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.CommonTargetConfigurator import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.CommonTargetConfigurator
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.getConfiguratorSettings import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.getConfiguratorSettings
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.moduleType import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.moduleType
@@ -59,13 +58,18 @@ class ModuleSettingsComponent(
settingsList.setComponents(moduleSettingComponents) settingsList.setComponents(moduleSettingComponents)
} }
private fun createTemplatesListComponentForModule(module: Module) = @OptIn(ExperimentalStdlibApi::class)
read { availableTemplatesFor(module) }.takeIf { it.isNotEmpty() }?.let { templates -> private fun createTemplatesListComponentForModule(module: Module): ModuleTemplateComponent? {
ModuleTemplateComponent(context, module, templates, uiEditorUsagesStats) { val templates = read { availableTemplatesFor(module) }.takeIf { it.isNotEmpty() } ?: return null
updateModule(module) val templatesWithNoneTemplate = buildList {
component.updateUI() add(NoneTemplate)
} addAll(templates)
} }
return ModuleTemplateComponent(context, module, templatesWithNoneTemplate, uiEditorUsagesStats) {
updateModule(module)
component.updateUI()
}
}
} }
private class ModuleNameComponent(context: Context, private val module: Module) : TitledComponent(context) { private class ModuleNameComponent(context: Context, private val module: Module) : TitledComponent(context) {
@@ -117,11 +121,9 @@ private class ModuleTemplateComponent(
@OptIn(ExperimentalStdlibApi::class) @OptIn(ExperimentalStdlibApi::class)
private val dropDown = DropDownComponent( private val dropDown = DropDownComponent(
context, context,
initialValues = buildList { initialValues = templates,
add(NoneTemplate)
addAll(templates)
},
initiallySelectedValue = module.template ?: NoneTemplate, initiallySelectedValue = module.template ?: NoneTemplate,
filter = { template: Template -> read { template.isApplicableTo(this, module) } },
labelText = null, labelText = null,
) { value -> ) { value ->
module.template = value.takeIf { it != NoneTemplate } module.template = value.takeIf { it != NoneTemplate }
@@ -150,19 +152,24 @@ private class ModuleTemplateComponent(
addToBottom(templateDescriptionLabel) addToBottom(templateDescriptionLabel)
} }
override val title: String = KotlinNewProjectWizardUIBundle.message("module.settings.template") override fun onValueUpdated(reference: SettingReference<*, *>?) {
super.onValueUpdated(reference)
private object NoneTemplate : Template() { dropDown.filterValues()
override val title = KotlinNewProjectWizardUIBundle.message("module.settings.template.none")
override val description: String = ""
override val moduleTypes: Set<ModuleType> = ModuleType.ALL
override val id: String = "none"
} }
override val title: String = KotlinNewProjectWizardUIBundle.message("module.settings.template")
}
private object NoneTemplate : Template() {
override val title = KotlinNewProjectWizardUIBundle.message("module.settings.template.none")
override val description: String = ""
override val moduleTypes: Set<ModuleType> = ModuleType.ALL
override val id: String = "none"
} }
fun Reader.availableTemplatesFor(module: Module) = fun Reader.availableTemplatesFor(module: Module) =
TemplatesPlugin::templates.propertyValue.values.filter { template -> TemplatesPlugin::templates.propertyValue.values.filter { template ->
module.configurator.moduleType in template.moduleTypes && template.isApplicableTo(module) module.configurator.moduleType in template.moduleTypes
} }
@@ -10,6 +10,7 @@ import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.tools.projectWizard.KotlinNewProjectWizardBundle import org.jetbrains.kotlin.tools.projectWizard.KotlinNewProjectWizardBundle
import org.jetbrains.kotlin.tools.projectWizard.core.Reader import org.jetbrains.kotlin.tools.projectWizard.core.Reader
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.ModuleConfiguratorSetting import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.ModuleConfiguratorSetting
import org.jetbrains.kotlin.tools.projectWizard.core.entity.settings.ModuleConfiguratorSettingReference
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.BuildSystemIR import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.BuildSystemIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.KotlinBuildSystemPluginIR import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.KotlinBuildSystemPluginIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.GradleIRListBuilder import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.GradleIRListBuilder
@@ -19,6 +20,7 @@ import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleType
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModulesToIrConversionData import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModulesToIrConversionData
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.ModuleKind import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.ModuleKind
import org.jetbrains.kotlin.tools.projectWizard.templates.SimpleJsClientTemplate
interface JSConfigurator : ModuleConfiguratorWithModuleType, ModuleConfiguratorWithSettings { interface JSConfigurator : ModuleConfiguratorWithModuleType, ModuleConfiguratorWithSettings {
override val moduleType: ModuleType get() = ModuleType.js override val moduleType: ModuleType get() = ModuleType.js
@@ -60,6 +62,13 @@ interface JSConfigurator : ModuleConfiguratorWithModuleType, ModuleConfiguratorW
GenerationPhase.PROJECT_GENERATION GenerationPhase.PROJECT_GENERATION
) { ) {
defaultValue = value(JsTargetKind.APPLICATION) defaultValue = value(JsTargetKind.APPLICATION)
filter = filter@{ reference, kindCandidate ->
when {
reference !is ModuleConfiguratorSettingReference<*, *> -> false
kindCandidate == JsTargetKind.LIBRARY && reference.module?.template is SimpleJsClientTemplate -> false
else -> true
}
}
} }
val cssSupport by booleanSetting( val cssSupport by booleanSetting(
@@ -25,7 +25,10 @@ class NativeConsoleApplicationTemplate : Template() {
override val moduleTypes: Set<ModuleType> = setOf(ModuleType.native) override val moduleTypes: Set<ModuleType> = setOf(ModuleType.native)
override val id: String = "nativeConsoleApp" override val id: String = "nativeConsoleApp"
override fun isApplicableTo(module: Module): Boolean = override fun isApplicableTo(
reader: Reader,
module: Module
): Boolean =
module.configurator.safeAs<NativeTargetConfigurator>()?.isDesktopTarget == true module.configurator.safeAs<NativeTargetConfigurator>()?.isDesktopTarget == true
override fun updateTargetIr(module: ModuleIR, targetConfigurationIR: TargetConfigurationIR): TargetConfigurationIR = override fun updateTargetIr(module: ModuleIR, targetConfigurationIR: TargetConfigurationIR): TargetConfigurationIR =
@@ -17,8 +17,6 @@ import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.*
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.multiplatform.DefaultTargetConfigurationIR import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.multiplatform.DefaultTargetConfigurationIR
import org.jetbrains.kotlin.tools.projectWizard.library.MavenArtifact import org.jetbrains.kotlin.tools.projectWizard.library.MavenArtifact
import org.jetbrains.kotlin.tools.projectWizard.library.NpmArtifact import org.jetbrains.kotlin.tools.projectWizard.library.NpmArtifact
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.JsBrowserTargetConfigurator
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.JsSingleplatformModuleConfigurator
import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase import org.jetbrains.kotlin.tools.projectWizard.phases.GenerationPhase
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleSubType import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleSubType
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleType import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleType
@@ -29,7 +27,9 @@ import org.jetbrains.kotlin.tools.projectWizard.transformers.interceptors.Templa
import org.jetbrains.kotlin.tools.projectWizard.transformers.interceptors.interceptTemplate import org.jetbrains.kotlin.tools.projectWizard.transformers.interceptors.interceptTemplate
import org.jetbrains.kotlin.tools.projectWizard.KotlinNewProjectWizardBundle import org.jetbrains.kotlin.tools.projectWizard.KotlinNewProjectWizardBundle
import org.jetbrains.kotlin.tools.projectWizard.Versions import org.jetbrains.kotlin.tools.projectWizard.Versions
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.*
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.KotlinPlugin import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.KotlinPlugin
import org.jetbrains.kotlin.tools.projectWizard.templates.withSettingsOf
class SimpleJsClientTemplate : Template() { class SimpleJsClientTemplate : Template() {
override val title: String = KotlinNewProjectWizardBundle.message("module.template.js.simple.title") override val title: String = KotlinNewProjectWizardBundle.message("module.template.js.simple.title")
@@ -40,9 +40,20 @@ class SimpleJsClientTemplate : Template() {
@NonNls @NonNls
override val id: String = "simpleJsClient" override val id: String = "simpleJsClient"
override fun isApplicableTo(module: Module): Boolean = override fun isApplicableTo(
module.configurator == JsBrowserTargetConfigurator reader: Reader,
|| module.configurator == JsSingleplatformModuleConfigurator module: Module
): Boolean = when (module.configurator) {
JsBrowserTargetConfigurator -> true
JsSingleplatformModuleConfigurator -> {
with(reader) {
withSettingsOf(module, module.configurator) {
JSConfigurator.kind.reference.notRequiredSettingValue == JsTargetKind.APPLICATION
}
}
}
else -> false
}
val renderEngine by enumSetting<RenderEngine>( val renderEngine by enumSetting<RenderEngine>(
KotlinNewProjectWizardBundle.message("module.template.js.simple.setting.rendering.engine"), KotlinNewProjectWizardBundle.message("module.template.js.simple.setting.rendering.engine"),
@@ -77,7 +77,10 @@ abstract class Template : SettingsOwner, EntitiesOwnerDescriptor, DisplayableSet
override val text: String get() = title override val text: String get() = title
open fun isApplicableTo(module: Module): Boolean = true open fun isApplicableTo(
reader: Reader,
module: Module
): Boolean = true
open val settings: List<TemplateSetting<*, *>> = emptyList() open val settings: List<TemplateSetting<*, *>> = emptyList()
open val interceptionPoints: List<InterceptionPoint<Any>> = emptyList() open val interceptionPoints: List<InterceptionPoint<Any>> = emptyList()