Skip to content

Commit af188cb

Browse files
authored
Merge pull request #37 from OneAndOlaf/improvement/update-validators
Allow changing validators after creation
2 parents 05aa7fa + 737cfaa commit af188cb

File tree

4 files changed

+117
-8
lines changed

4 files changed

+117
-8
lines changed

src/main/kotlin/com/github/hanseter/json/editor/JsonPropertiesEditor.kt

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,26 @@ class JsonPropertiesEditor @JvmOverloads constructor(
3232
IdReferenceProposalProvider.IdReferenceProposalProviderEmpty
3333
var resolutionScopeProvider: ResolutionScopeProvider =
3434
ResolutionScopeProvider.ResolutionScopeProviderEmpty
35-
val validators: List<Validator> =
36-
listOf(IdReferenceValidator { referenceProposalProvider }) + additionalValidators
35+
36+
private val fixedValidators = listOf(IdReferenceValidator { referenceProposalProvider })
37+
38+
var additionalValidators: List<Validator> = additionalValidators
39+
set(value) {
40+
field = value.toList()
41+
validators = fixedValidators + field
42+
}
43+
44+
// since this is read a lot more frequently than it's updated, we cache the complete validator
45+
// list instead of having it be computed every time
46+
var validators: List<Validator> = fixedValidators + additionalValidators
47+
private set(value) {
48+
field = value
49+
Platform.runLater {
50+
idsToPanes.values.forEach {
51+
it.revalidate()
52+
}
53+
}
54+
}
3755

3856
private val actions =
3957
actions + PreviewAction(
@@ -205,7 +223,7 @@ class JsonPropertiesEditor @JvmOverloads constructor(
205223
resolutionScope,
206224
{ referenceProposalProvider },
207225
actions,
208-
validators,
226+
{ validators },
209227
viewOptions,
210228
customizationObject,
211229
callback

src/main/kotlin/com/github/hanseter/json/editor/JsonPropertiesPane.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class JsonPropertiesPane(
3030
private val resolutionScope: URI?,
3131
private val refProvider: Supplier<IdReferenceProposalProvider>,
3232
private val actions: List<EditorAction>,
33-
private val validators: List<Validator>,
33+
private val validators: () -> List<Validator>,
3434
viewOptions: ViewOptions,
3535
private val customizationObject: CustomizationObject,
3636
private val changeListener: JsonPropertiesEditor.OnEditCallback
@@ -145,7 +145,6 @@ class JsonPropertiesPane(
145145
actions,
146146
actionHandler,
147147
objId,
148-
validators.filter { it.selector.matches(control.model) },
149148
customizationObject
150149
)
151150
)
@@ -332,7 +331,7 @@ class JsonPropertiesPane(
332331

333332
private fun updateTreeUiElements(root: FilterableTreeItem<TreeItemData>, data: JSONObject) {
334333
(root.value as? ControlTreeItemData)?.typeControl?.also { control ->
335-
val errors = ValidationEngine.validateData(control, objId, data, validators).toMap()
334+
val errors = ValidationEngine.validateData(control, objId, data, validators()).toMap()
336335
flattenBottomUp(root).forEach { item ->
337336
(item.value as? ControlTreeItemData)?.also { data ->
338337
item.value.validationMessage =
@@ -346,6 +345,12 @@ class JsonPropertiesPane(
346345
}
347346
}
348347

348+
fun revalidate() {
349+
controlItem?.also { item ->
350+
updateTreeUiElements(item, contentHandler.data)
351+
}
352+
}
353+
349354
private fun saveUiState(): UiState? {
350355
val controlItem = controlItem ?: return null
351356

src/main/kotlin/com/github/hanseter/json/editor/ui/FilterableTreeItem.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import javafx.collections.ObservableList
1212
import javafx.collections.transformation.FilteredList
1313
import javafx.event.Event
1414
import javafx.scene.control.TreeItem
15-
import org.controlsfx.validation.Severity
1615

1716
/**
1817
* Creates a filterable TreeItem with children.
@@ -122,7 +121,6 @@ class ControlTreeItemData(
122121
private val actions: List<EditorAction>,
123122
private val actionHandler: (Event, EditorAction, TypeControl) -> Unit,
124123
private val objId: String,
125-
val validators: List<Validator>,
126124
private val customizationObject: CustomizationObject
127125
) : TreeItemData {
128126
private val changeListeners: MutableList<(TreeItemData) -> Unit> = mutableListOf()

src/test/kotlin/com/github/hanseter/json/editor/ValidationTest.kt

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,92 @@ class ValidationTest {
5959
MatcherAssert.assertThat(editor.valid.get(), Matchers.`is`(false))
6060
}
6161

62+
@Test
63+
fun `additional validators are used if registered later`() {
64+
val editor = JsonPropertiesEditor()
65+
66+
val schema = JSONObject("""
67+
{
68+
"properties": {
69+
"a": {
70+
"type": "string"
71+
}
72+
}
73+
}
74+
""")
75+
76+
editor.display("1", "1", JSONObject().put("a", "foo"), schema) { it }
77+
78+
WaitForAsyncUtils.waitForFxEvents()
79+
MatcherAssert.assertThat(editor.valid.get(), Matchers.`is`(true))
80+
81+
editor.additionalValidators += object : Validator {
82+
override val selector: TargetSelector
83+
get() = TargetSelector.SchemaType(SupportedType.SimpleType.StringType)
84+
85+
override fun validate(model: TypeModel<*, *>, objId: String): List<Validator.ValidationResult> {
86+
return if (model.value == "foo") {
87+
emptyList()
88+
} else listOf(Validator.SimpleValidationResult(Severity.ERROR, "error"))
89+
}
90+
91+
}
92+
93+
WaitForAsyncUtils.waitForFxEvents()
94+
MatcherAssert.assertThat(editor.valid.get(), Matchers.`is`(true))
95+
96+
val stringControl = editor.getControlInTable("a") as TextField
97+
98+
stringControl.text = "bar"
99+
100+
WaitForAsyncUtils.waitForFxEvents()
101+
MatcherAssert.assertThat(editor.valid.get(), Matchers.`is`(false))
102+
}
103+
104+
@Test
105+
fun `changing validators triggers validation`() {
106+
val editor = JsonPropertiesEditor()
107+
108+
val schema = JSONObject("""
109+
{
110+
"properties": {
111+
"a": {
112+
"type": "string"
113+
}
114+
}
115+
}
116+
""")
117+
118+
editor.display("1", "1", JSONObject().put("a", "foo"), schema) { it }
119+
120+
WaitForAsyncUtils.waitForFxEvents()
121+
MatcherAssert.assertThat(editor.valid.get(), Matchers.`is`(true))
122+
123+
val stringControl = editor.getControlInTable("a") as TextField
124+
125+
stringControl.text = "bar"
126+
127+
WaitForAsyncUtils.waitForFxEvents()
128+
MatcherAssert.assertThat(editor.valid.get(), Matchers.`is`(true))
129+
130+
editor.additionalValidators += object : Validator {
131+
override val selector: TargetSelector
132+
get() = TargetSelector.SchemaType(SupportedType.SimpleType.StringType)
133+
134+
override fun validate(model: TypeModel<*, *>, objId: String): List<Validator.ValidationResult> {
135+
return if (model.value == "foo") {
136+
emptyList()
137+
} else listOf(Validator.SimpleValidationResult(Severity.ERROR, "error"))
138+
}
139+
}
140+
141+
WaitForAsyncUtils.waitForFxEvents()
142+
MatcherAssert.assertThat(editor.valid.get(), Matchers.`is`(false))
143+
144+
editor.additionalValidators = emptyList()
145+
146+
WaitForAsyncUtils.waitForFxEvents()
147+
MatcherAssert.assertThat(editor.valid.get(), Matchers.`is`(true))
148+
}
149+
62150
}

0 commit comments

Comments
 (0)