Skip to content

Commit

Permalink
Merge pull request #37 from OneAndOlaf/improvement/update-validators
Browse files Browse the repository at this point in the history
Allow changing validators after creation
  • Loading branch information
Hanseter authored Jun 7, 2024
2 parents 05aa7fa + 737cfaa commit af188cb
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,26 @@ class JsonPropertiesEditor @JvmOverloads constructor(
IdReferenceProposalProvider.IdReferenceProposalProviderEmpty
var resolutionScopeProvider: ResolutionScopeProvider =
ResolutionScopeProvider.ResolutionScopeProviderEmpty
val validators: List<Validator> =
listOf(IdReferenceValidator { referenceProposalProvider }) + additionalValidators

private val fixedValidators = listOf(IdReferenceValidator { referenceProposalProvider })

var additionalValidators: List<Validator> = additionalValidators
set(value) {
field = value.toList()
validators = fixedValidators + field
}

// since this is read a lot more frequently than it's updated, we cache the complete validator
// list instead of having it be computed every time
var validators: List<Validator> = fixedValidators + additionalValidators
private set(value) {
field = value
Platform.runLater {
idsToPanes.values.forEach {
it.revalidate()
}
}
}

private val actions =
actions + PreviewAction(
Expand Down Expand Up @@ -205,7 +223,7 @@ class JsonPropertiesEditor @JvmOverloads constructor(
resolutionScope,
{ referenceProposalProvider },
actions,
validators,
{ validators },
viewOptions,
customizationObject,
callback
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class JsonPropertiesPane(
private val resolutionScope: URI?,
private val refProvider: Supplier<IdReferenceProposalProvider>,
private val actions: List<EditorAction>,
private val validators: List<Validator>,
private val validators: () -> List<Validator>,
viewOptions: ViewOptions,
private val customizationObject: CustomizationObject,
private val changeListener: JsonPropertiesEditor.OnEditCallback
Expand Down Expand Up @@ -145,7 +145,6 @@ class JsonPropertiesPane(
actions,
actionHandler,
objId,
validators.filter { it.selector.matches(control.model) },
customizationObject
)
)
Expand Down Expand Up @@ -332,7 +331,7 @@ class JsonPropertiesPane(

private fun updateTreeUiElements(root: FilterableTreeItem<TreeItemData>, data: JSONObject) {
(root.value as? ControlTreeItemData)?.typeControl?.also { control ->
val errors = ValidationEngine.validateData(control, objId, data, validators).toMap()
val errors = ValidationEngine.validateData(control, objId, data, validators()).toMap()
flattenBottomUp(root).forEach { item ->
(item.value as? ControlTreeItemData)?.also { data ->
item.value.validationMessage =
Expand All @@ -346,6 +345,12 @@ class JsonPropertiesPane(
}
}

fun revalidate() {
controlItem?.also { item ->
updateTreeUiElements(item, contentHandler.data)
}
}

private fun saveUiState(): UiState? {
val controlItem = controlItem ?: return null

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import javafx.collections.ObservableList
import javafx.collections.transformation.FilteredList
import javafx.event.Event
import javafx.scene.control.TreeItem
import org.controlsfx.validation.Severity

/**
* Creates a filterable TreeItem with children.
Expand Down Expand Up @@ -122,7 +121,6 @@ class ControlTreeItemData(
private val actions: List<EditorAction>,
private val actionHandler: (Event, EditorAction, TypeControl) -> Unit,
private val objId: String,
val validators: List<Validator>,
private val customizationObject: CustomizationObject
) : TreeItemData {
private val changeListeners: MutableList<(TreeItemData) -> Unit> = mutableListOf()
Expand Down
88 changes: 88 additions & 0 deletions src/test/kotlin/com/github/hanseter/json/editor/ValidationTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,92 @@ class ValidationTest {
MatcherAssert.assertThat(editor.valid.get(), Matchers.`is`(false))
}

@Test
fun `additional validators are used if registered later`() {
val editor = JsonPropertiesEditor()

val schema = JSONObject("""
{
"properties": {
"a": {
"type": "string"
}
}
}
""")

editor.display("1", "1", JSONObject().put("a", "foo"), schema) { it }

WaitForAsyncUtils.waitForFxEvents()
MatcherAssert.assertThat(editor.valid.get(), Matchers.`is`(true))

editor.additionalValidators += object : Validator {
override val selector: TargetSelector
get() = TargetSelector.SchemaType(SupportedType.SimpleType.StringType)

override fun validate(model: TypeModel<*, *>, objId: String): List<Validator.ValidationResult> {
return if (model.value == "foo") {
emptyList()
} else listOf(Validator.SimpleValidationResult(Severity.ERROR, "error"))
}

}

WaitForAsyncUtils.waitForFxEvents()
MatcherAssert.assertThat(editor.valid.get(), Matchers.`is`(true))

val stringControl = editor.getControlInTable("a") as TextField

stringControl.text = "bar"

WaitForAsyncUtils.waitForFxEvents()
MatcherAssert.assertThat(editor.valid.get(), Matchers.`is`(false))
}

@Test
fun `changing validators triggers validation`() {
val editor = JsonPropertiesEditor()

val schema = JSONObject("""
{
"properties": {
"a": {
"type": "string"
}
}
}
""")

editor.display("1", "1", JSONObject().put("a", "foo"), schema) { it }

WaitForAsyncUtils.waitForFxEvents()
MatcherAssert.assertThat(editor.valid.get(), Matchers.`is`(true))

val stringControl = editor.getControlInTable("a") as TextField

stringControl.text = "bar"

WaitForAsyncUtils.waitForFxEvents()
MatcherAssert.assertThat(editor.valid.get(), Matchers.`is`(true))

editor.additionalValidators += object : Validator {
override val selector: TargetSelector
get() = TargetSelector.SchemaType(SupportedType.SimpleType.StringType)

override fun validate(model: TypeModel<*, *>, objId: String): List<Validator.ValidationResult> {
return if (model.value == "foo") {
emptyList()
} else listOf(Validator.SimpleValidationResult(Severity.ERROR, "error"))
}
}

WaitForAsyncUtils.waitForFxEvents()
MatcherAssert.assertThat(editor.valid.get(), Matchers.`is`(false))

editor.additionalValidators = emptyList()

WaitForAsyncUtils.waitForFxEvents()
MatcherAssert.assertThat(editor.valid.get(), Matchers.`is`(true))
}

}

0 comments on commit af188cb

Please sign in to comment.