From 72f92d7a3b6400c628ea9ce35a4b890c7d4c1826 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Wed, 12 Feb 2020 19:46:43 +0300 Subject: [PATCH] Wizard: use IntelliJ validator in UI instead of custom one --- .../ui/components/PathFieldComponent.kt | 4 +- .../wizard/ui/components/UIComponent.kt | 21 +++-- .../modulesEditor/ModulesEditorComponent.kt | 8 +- .../ui/setting/DefaultSettingComponent.kt | 3 +- .../wizard/ui/setting/SettingComponent.kt | 2 +- .../wizard/ui/setting/ValidationIndicator.kt | 87 ++++++++++--------- 6 files changed, 70 insertions(+), 55 deletions(-) diff --git a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/components/PathFieldComponent.kt b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/components/PathFieldComponent.kt index c93c01ef2bd..7895f006d3f 100644 --- a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/components/PathFieldComponent.kt +++ b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/components/PathFieldComponent.kt @@ -41,7 +41,9 @@ class PathFieldComponent( ) } - override fun updateUiValue(newValue: Path)= safeUpdateUi { + override fun getValidatorTarget(): JComponent = uiComponent.textField + + override fun updateUiValue(newValue: Path) = safeUpdateUi { uiComponent.text = newValue.toString() } diff --git a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/components/UIComponent.kt b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/components/UIComponent.kt index 3f939d2b870..6d0ff5b24e6 100644 --- a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/components/UIComponent.kt +++ b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/components/UIComponent.kt @@ -5,12 +5,15 @@ package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.components +import com.intellij.openapi.Disposable import org.jetbrains.kotlin.tools.projectWizard.core.ValuesReadingContext import org.jetbrains.kotlin.tools.projectWizard.core.entity.* 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.label import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.panel import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.ErrorAwareComponent +import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.IdeaBasedComponentValidator import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.SettingComponent import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.ValidationIndicator import java.awt.BorderLayout @@ -21,13 +24,19 @@ abstract class UIComponent( labelText: String? = null, private val validator: SettingValidator? = null, private val onValueUpdate: (V) -> Unit = {} -) : DynamicComponent(valuesReadingContext), ErrorAwareComponent, FocusableComponent { - private val validationIndicator = if (validator != null) - ValidationIndicator(defaultText = labelText, showText = true) - else null +) : DynamicComponent(valuesReadingContext), ErrorAwareComponent, FocusableComponent, Disposable { + private val validationIndicator by lazy(LazyThreadSafetyMode.NONE) { + if (validator != null) + IdeaBasedComponentValidator(this, getValidatorTarget()) + else null + } + + override fun dispose() {} protected abstract val uiComponent: JComponent + protected open fun getValidatorTarget() = uiComponent + abstract fun updateUiValue(newValue: V) abstract fun getUiValue(): V? @@ -47,7 +56,7 @@ abstract class UIComponent( final override val component: JComponent by lazy(LazyThreadSafetyMode.NONE) { panel { - validationIndicator?.let { add(it, BorderLayout.NORTH) } + labelText?.let { add(label("$it:"), BorderLayout.NORTH) } add(uiComponent, BorderLayout.CENTER) } } @@ -62,7 +71,7 @@ abstract class UIComponent( fun validate(value: V) { if (validator == null) return if (validationIndicator == null) return - validationIndicator.validationState = validator.validate(valuesReadingContext, value) + validationIndicator?.updateValidationState(validator.validate(valuesReadingContext, value)) } override fun focusOn() { diff --git a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/secondStep/modulesEditor/ModulesEditorComponent.kt b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/secondStep/modulesEditor/ModulesEditorComponent.kt index eda2043514f..3ef330837f6 100644 --- a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/secondStep/modulesEditor/ModulesEditorComponent.kt +++ b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/secondStep/modulesEditor/ModulesEditorComponent.kt @@ -11,8 +11,8 @@ import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ProjectKind import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.panel +import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.AlwaysShownValidationIndicator import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.SettingComponent -import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.ValidationIndicator import java.awt.BorderLayout import javax.swing.BorderFactory import javax.swing.JComponent @@ -66,11 +66,9 @@ class ModulesEditorComponent( } } - override val validationIndicator = ValidationIndicator(showText = true) { error -> - val module = error.target as? Module ?: return@ValidationIndicator + override val validationIndicator = AlwaysShownValidationIndicator(showText = true) { error -> + val module = error.target as? Module ?: return@AlwaysShownValidationIndicator tree.selectModule(module) selectSettingWithError(error) - }.apply { - background = tree.background } } diff --git a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/setting/DefaultSettingComponent.kt b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/setting/DefaultSettingComponent.kt index 4d59a4e2d71..de1f295792f 100644 --- a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/setting/DefaultSettingComponent.kt +++ b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/setting/DefaultSettingComponent.kt @@ -73,12 +73,11 @@ class VersionSettingComponent( } } - override val validationIndicator = ValidationIndicator(showText = false) + override val validationIndicator = null override val component: JComponent by lazy(LazyThreadSafetyMode.NONE) { panel { add( panel { - add(validationIndicator, BorderLayout.WEST) add(settingLabel, BorderLayout.CENTER) }, BorderLayout.WEST diff --git a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/setting/SettingComponent.kt b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/setting/SettingComponent.kt index 9f47e3c5815..637fde23ad2 100644 --- a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/setting/SettingComponent.kt +++ b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/setting/SettingComponent.kt @@ -36,7 +36,7 @@ abstract class SettingComponent>( private fun updateValidationState() { val value = value if (validationIndicator != null && value != null) { - validationIndicator!!.validationState = setting.validator.validate(valuesReadingContext, value) + validationIndicator!!.updateValidationState(setting.validator.validate(valuesReadingContext, value)) } } } diff --git a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/setting/ValidationIndicator.kt b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/setting/ValidationIndicator.kt index 9e87a74f4fc..2f8eab8b615 100644 --- a/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/setting/ValidationIndicator.kt +++ b/idea/idea-new-project-wizard/src/org/jetbrains/kotlin/tools/projectWizard/wizard/ui/setting/ValidationIndicator.kt @@ -1,35 +1,57 @@ package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting import com.intellij.icons.AllIcons -import com.intellij.ui.JBColor -import com.intellij.util.ui.EmptyIcon +import com.intellij.openapi.Disposable +import com.intellij.openapi.ui.ComponentValidator +import com.intellij.openapi.ui.ValidationInfo +import com.intellij.util.ui.JBUI import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult -import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.asHtml import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.label +import org.jetbrains.kotlin.utils.addToStdlib.safeAs import java.awt.BorderLayout import java.awt.Cursor import java.awt.event.MouseEvent import java.awt.event.MouseListener import javax.swing.BorderFactory -import javax.swing.Icon +import javax.swing.JComponent import javax.swing.JPanel -class ValidationIndicator( - defaultText: String? = null, +interface ValidationIndicator { + fun updateValidationState(newState: ValidationResult) +} + +class IdeaBasedComponentValidator( + parentDisposable: Disposable, + private val jComponent: JComponent +) : ValidationIndicator { + private val validator = ComponentValidator(parentDisposable).installOn(jComponent) + + override fun updateValidationState(newState: ValidationResult) { + validator.updateInfo( + newState.safeAs() + ?.messages + ?.firstOrNull() + ?.let { ValidationInfo(it, jComponent) } + ) + } +} + +class AlwaysShownValidationIndicator( private val showText: Boolean, private val onClickAction: ((ValidationResult.ValidationError) -> Unit)? = null -) : JPanel(BorderLayout()) { - private val textLabel = defaultText?.let { label("$it: ") } - private val errorLabel = label(" ").apply { - foreground = JBColor.red - } +) : JPanel(BorderLayout()), ValidationIndicator { + private val errorLabel = label(" ") private var currentError: ValidationResult.ValidationError? = null - init { - border = BorderFactory.createEmptyBorder(3, 3, 3, 3) - textLabel?.let { add(it, BorderLayout.WEST) } + errorLabel.icon = AllIcons.General.Error + background = JBUI.CurrentTheme.Validator.errorBackgroundColor() + border = + BorderFactory.createCompoundBorder( + BorderFactory.createLineBorder(JBUI.CurrentTheme.Validator.errorBorderColor()), + JBUI.Borders.empty(4, 8) + ) add(errorLabel, BorderLayout.CENTER) if (onClickAction != null) { @@ -47,32 +69,17 @@ class ValidationIndicator( } } - private fun setIcon(icon: Icon?) { - if (textLabel != null) textLabel.icon = icon - else errorLabel.icon = icon ?: EmptyIcon.ICON_16 - } - - private fun String.linkifyErrorText() = - if (onClickAction == null) this - else "$this".asHtml() - - var validationState: ValidationResult = ValidationResult.OK - set(value) { - field = value - when (value) { - ValidationResult.OK -> { - setIcon(null) - errorLabel.text = " " - toolTipText = null - currentError = null - } - is ValidationResult.ValidationError -> { - setIcon(AllIcons.General.Error) - val errors = value.messages.firstOrNull().orEmpty() - toolTipText = errors - if (showText) errorLabel.text = errors.linkifyErrorText() - currentError = value - } + override fun updateValidationState(newState: ValidationResult) { + isVisible = !newState.isOk + when (newState) { + ValidationResult.OK -> { + currentError = null + } + is ValidationResult.ValidationError -> { + val errors = newState.messages.firstOrNull().orEmpty() + if (showText) errorLabel.text = errors + currentError = newState } } + } } \ No newline at end of file