FXMeta viewer and editor fully functional
This commit is contained in:
parent
eba5096129
commit
74e70819ee
@ -1,7 +1,8 @@
|
|||||||
val dataforgeVersion by extra("0.1.3-dev-2")
|
val dataforgeVersion by extra("0.1.3-dev-5")
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
jcenter()
|
jcenter()
|
||||||
maven("https://kotlin.bintray.com/kotlinx")
|
maven("https://kotlin.bintray.com/kotlinx")
|
||||||
maven("http://npm.mipt.ru:8081/artifactory/gradle-dev-local")
|
maven("http://npm.mipt.ru:8081/artifactory/gradle-dev-local")
|
||||||
|
@ -9,17 +9,17 @@ kotlin {
|
|||||||
val commonMain by getting {
|
val commonMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
api("hep.dataforge:dataforge-output:$dataforgeVersion")
|
api("hep.dataforge:dataforge-output:$dataforgeVersion")
|
||||||
api("hep.dataforge:dataforge-output-metadata:$dataforgeVersion")
|
// api("hep.dataforge:dataforge-output-metadata:$dataforgeVersion")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val jvmMain by getting{
|
val jvmMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
api("hep.dataforge:dataforge-output-jvm:$dataforgeVersion")
|
// api("hep.dataforge:dataforge-output-jvm:$dataforgeVersion")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val jsMain by getting{
|
val jsMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
api("hep.dataforge:dataforge-output-js:$dataforgeVersion")
|
// api("hep.dataforge:dataforge-output-js:$dataforgeVersion")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
package hep.dataforge.vis.fx.demo
|
||||||
|
|
||||||
|
import hep.dataforge.descriptors.NodeDescriptor
|
||||||
|
import hep.dataforge.meta.buildMeta
|
||||||
|
import hep.dataforge.meta.toConfig
|
||||||
|
import hep.dataforge.values.ValueType
|
||||||
|
import hep.dataforge.vis.fx.meta.ConfigEditor
|
||||||
|
import hep.dataforge.vis.fx.meta.FXMeta
|
||||||
|
import hep.dataforge.vis.fx.meta.MetaViewer
|
||||||
|
import javafx.geometry.Orientation
|
||||||
|
import tornadofx.*
|
||||||
|
|
||||||
|
|
||||||
|
class MetaEditorDemoApp : App(MetaEditorDemo::class)
|
||||||
|
|
||||||
|
class MetaEditorDemo : View("Meta editor demo") {
|
||||||
|
|
||||||
|
val meta = buildMeta {
|
||||||
|
"aNode" to {
|
||||||
|
"innerNode" to {
|
||||||
|
"innerValue" to true
|
||||||
|
}
|
||||||
|
"b" to 22
|
||||||
|
"c" to "StringValue"
|
||||||
|
}
|
||||||
|
}.toConfig()
|
||||||
|
|
||||||
|
val descriptor = NodeDescriptor.build {
|
||||||
|
node("aNode") {
|
||||||
|
info = "A root demo node"
|
||||||
|
value("b") {
|
||||||
|
info = "b number value"
|
||||||
|
type(ValueType.NUMBER)
|
||||||
|
}
|
||||||
|
node("otherNode") {
|
||||||
|
value("otherValue") {
|
||||||
|
type(ValueType.BOOLEAN)
|
||||||
|
default(false)
|
||||||
|
info = "default value"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val rootNode = FXMeta.root(meta,descriptor)
|
||||||
|
|
||||||
|
override val root =
|
||||||
|
splitpane(Orientation.HORIZONTAL, MetaViewer(rootNode).root, ConfigEditor(rootNode).root)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
launch<MetaEditorDemoApp>()
|
||||||
|
}
|
@ -24,27 +24,30 @@ import tornadofx.*
|
|||||||
* @author Alexander Nozik
|
* @author Alexander Nozik
|
||||||
*/
|
*/
|
||||||
class ConfigEditor(
|
class ConfigEditor(
|
||||||
val configuration: Config,
|
val rootNode: FXMetaNode<Config>,
|
||||||
title: String = "Configuration editor",
|
title: String = "Configuration editor"
|
||||||
val descriptor: NodeDescriptor? = null
|
|
||||||
) : Fragment(title = title, icon = dfIconView) {
|
) : Fragment(title = title, icon = dfIconView) {
|
||||||
|
|
||||||
val filter: (FXMeta) -> Boolean = { cfg ->
|
constructor(config: Config, descriptor: NodeDescriptor, title: String = "Configuration editor") :
|
||||||
when (cfg) {
|
this(FXMeta.root(config, descriptor = descriptor))
|
||||||
is FXMetaNode<*> -> !(cfg.descriptor?.tags?.contains(NO_CONFIGURATOR_TAG) ?: false)
|
|
||||||
is FXMetaValue -> !(cfg.descriptor?.tags?.contains(NO_CONFIGURATOR_TAG) ?: false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val root = borderpane {
|
override val root = borderpane {
|
||||||
center = treetableview<FXMeta> {
|
center = treetableview<FXMeta<Config>> {
|
||||||
root = TreeItem(FXMeta.root(configuration, descriptor))
|
root = TreeItem(rootNode)
|
||||||
root.isExpanded = true
|
root.isExpanded = true
|
||||||
sortMode = TreeSortMode.ALL_DESCENDANTS
|
sortMode = TreeSortMode.ALL_DESCENDANTS
|
||||||
columnResizePolicy = TreeTableView.CONSTRAINED_RESIZE_POLICY
|
columnResizePolicy = TreeTableView.CONSTRAINED_RESIZE_POLICY
|
||||||
column("Name", FXMeta::name) {
|
populate {
|
||||||
|
when (val fxMeta = it.value) {
|
||||||
|
is FXMetaNode -> {
|
||||||
|
fxMeta.children
|
||||||
|
}
|
||||||
|
is FXMetaValue -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
column("Name", FXMeta<Config>::name) {
|
||||||
setCellFactory {
|
setCellFactory {
|
||||||
object : TextFieldTreeTableCell<FXMeta, NameToken>() {
|
object : TextFieldTreeTableCell<FXMeta<Config>, NameToken>() {
|
||||||
override fun updateItem(item: NameToken?, empty: Boolean) {
|
override fun updateItem(item: NameToken?, empty: Boolean) {
|
||||||
super.updateItem(item, empty)
|
super.updateItem(item, empty)
|
||||||
contextMenu?.items?.removeIf { it.text == "Remove" }
|
contextMenu?.items?.removeIf { it.text == "Remove" }
|
||||||
@ -57,7 +60,7 @@ class ConfigEditor(
|
|||||||
Color.GRAY
|
Color.GRAY
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (treeTableRow.treeItem.value.hasValue.get()) {
|
if (treeTableRow.treeItem.value.parent != null && treeTableRow.treeItem.value.hasValue.get()) {
|
||||||
contextmenu {
|
contextmenu {
|
||||||
item("Remove") {
|
item("Remove") {
|
||||||
action {
|
action {
|
||||||
@ -73,15 +76,15 @@ class ConfigEditor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
column("Value") { param: TreeTableColumn.CellDataFeatures<FXMeta, FXMeta> ->
|
column("Value") { param: TreeTableColumn.CellDataFeatures<FXMeta<Config>, FXMeta<Config>> ->
|
||||||
param.value.valueProperty()
|
param.value.valueProperty()
|
||||||
}.setCellFactory {
|
}.setCellFactory {
|
||||||
ValueCell()
|
ValueCell()
|
||||||
}
|
}
|
||||||
|
|
||||||
column("Description") { param: TreeTableColumn.CellDataFeatures<FXMeta, String> -> param.value.value.descriptionProperty }
|
column("Description") { param: TreeTableColumn.CellDataFeatures<FXMeta<Config>, String> -> param.value.value.descriptionProperty }
|
||||||
.setCellFactory { param: TreeTableColumn<FXMeta, String> ->
|
.setCellFactory { param: TreeTableColumn<FXMeta<Config>, String> ->
|
||||||
val cell = TreeTableCell<FXMeta, String>()
|
val cell = TreeTableCell<FXMeta<Config>, String>()
|
||||||
val text = Text()
|
val text = Text()
|
||||||
cell.graphic = text
|
cell.graphic = text
|
||||||
cell.prefHeight = Control.USE_COMPUTED_SIZE
|
cell.prefHeight = Control.USE_COMPUTED_SIZE
|
||||||
@ -112,22 +115,20 @@ class ConfigEditor(
|
|||||||
return result.orElse(null)
|
return result.orElse(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class ValueCell : TreeTableCell<FXMeta, FXMeta?>() {
|
private inner class ValueCell : TreeTableCell<FXMeta<Config>, FXMeta<Config>?>() {
|
||||||
|
|
||||||
public override fun updateItem(item: FXMeta?, empty: Boolean) {
|
public override fun updateItem(item: FXMeta<Config>?, empty: Boolean) {
|
||||||
if (!empty) {
|
if (!empty) {
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
when (item) {
|
when (item) {
|
||||||
is FXMetaValue -> {
|
is FXMetaValue<Config> -> {
|
||||||
text = null
|
text = null
|
||||||
val chooser = ValueChooser.build(item.valueProperty, item.descriptor) {
|
val chooser = ValueChooser.build(item.valueProperty, item.descriptor) {
|
||||||
item.set(it)
|
item.set(it)
|
||||||
}
|
}
|
||||||
graphic = chooser.node
|
graphic = chooser.node
|
||||||
}
|
}
|
||||||
is FXMetaNode<*> -> {
|
is FXMetaNode<Config> -> {
|
||||||
item as FXMetaNode<Config>
|
|
||||||
|
|
||||||
text = null
|
text = null
|
||||||
graphic = hbox {
|
graphic = hbox {
|
||||||
button("node", Glyph("FontAwesome", "PLUS_CIRCLE")) {
|
button("node", Glyph("FontAwesome", "PLUS_CIRCLE")) {
|
||||||
|
@ -1,286 +0,0 @@
|
|||||||
//package hep.dataforge.vis.fx.meta
|
|
||||||
//
|
|
||||||
//import hep.dataforge.descriptors.NodeDescriptor
|
|
||||||
//import hep.dataforge.descriptors.ValueDescriptor
|
|
||||||
//import hep.dataforge.meta.Config
|
|
||||||
//import hep.dataforge.meta.Meta
|
|
||||||
//import hep.dataforge.names.Name
|
|
||||||
//import hep.dataforge.values.Null
|
|
||||||
//import hep.dataforge.values.Value
|
|
||||||
//import javafx.beans.binding.StringBinding
|
|
||||||
//import javafx.beans.property.SimpleObjectProperty
|
|
||||||
//import javafx.beans.property.SimpleStringProperty
|
|
||||||
//import javafx.beans.value.ObservableBooleanValue
|
|
||||||
//import javafx.beans.value.ObservableStringValue
|
|
||||||
//import javafx.collections.FXCollections
|
|
||||||
//import javafx.collections.ObservableList
|
|
||||||
//import javafx.scene.control.TreeItem
|
|
||||||
//import tornadofx.*
|
|
||||||
//
|
|
||||||
//class ConfigTreeItem(configFX: ConfigFX) : TreeItem<ConfigFX>(configFX) {
|
|
||||||
// init {
|
|
||||||
// this.children.bind(value.children) { ConfigTreeItem(it) }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun isLeaf(): Boolean = value is ConfigFXValue
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//
|
|
||||||
///**
|
|
||||||
// * A node, containing relative representation of configuration node and description
|
|
||||||
// * Created by darksnake on 01-May-17.
|
|
||||||
// */
|
|
||||||
//sealed class ConfigFX(name: String) {
|
|
||||||
//
|
|
||||||
// val nameProperty = SimpleStringProperty(name)
|
|
||||||
// val name by nameProperty
|
|
||||||
//
|
|
||||||
// val parentProperty = SimpleObjectProperty<ConfigFXNode>()
|
|
||||||
// val parent by parentProperty
|
|
||||||
//
|
|
||||||
// abstract val hasValueProperty: ObservableBooleanValue
|
|
||||||
// //abstract val hasDefaultProperty: ObservableBooleanValue
|
|
||||||
//
|
|
||||||
// abstract val descriptionProperty: ObservableStringValue
|
|
||||||
//
|
|
||||||
// abstract val children: ObservableList<ConfigFX>
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * remove itself from parent
|
|
||||||
// */
|
|
||||||
// abstract fun remove()
|
|
||||||
//
|
|
||||||
// abstract fun invalidate()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//
|
|
||||||
///**
|
|
||||||
// * Tree item for node
|
|
||||||
// * Created by darksnake on 30-Apr-17.
|
|
||||||
// */
|
|
||||||
//open class ConfigFXNode(name: String, parent: ConfigFXNode? = null) : ConfigFX(name) {
|
|
||||||
//
|
|
||||||
// final override val hasValueProperty = parentProperty.booleanBinding(nameProperty) {
|
|
||||||
// it?.config?.hasMeta(this.name) ?: false
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * A descriptor that could be manually set to the node
|
|
||||||
// */
|
|
||||||
// val descriptorProperty = SimpleObjectProperty<NodeDescriptor?>()
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Actual descriptor which holds value inferred from parrent
|
|
||||||
// */
|
|
||||||
// private val actualDescriptor = objectBinding(descriptorProperty, parentProperty, nameProperty) {
|
|
||||||
// value ?: parent?.descriptor?.getNodeDescriptor(name)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// val descriptor: NodeDescriptor? by actualDescriptor
|
|
||||||
//
|
|
||||||
// val configProperty = SimpleObjectProperty<Config?>()
|
|
||||||
//
|
|
||||||
// private val actualConfig = objectBinding(configProperty, parentProperty, nameProperty) {
|
|
||||||
// value ?: parent?.config?.getMetaList(name)?.firstOrNull()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// val config: Config? by actualConfig
|
|
||||||
//
|
|
||||||
// final override val descriptionProperty: ObservableStringValue = stringBinding(actualDescriptor) {
|
|
||||||
// value?.info ?: ""
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override val children: ObservableList<ConfigFX> = FXCollections.observableArrayList<ConfigFX>()
|
|
||||||
//
|
|
||||||
// init {
|
|
||||||
// parentProperty.set(parent)
|
|
||||||
// hasValueProperty.onChange {
|
|
||||||
// parent?.hasValueProperty?.invalidate()
|
|
||||||
// }
|
|
||||||
// invalidate()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Get existing configuration node or create and attach new one
|
|
||||||
// *
|
|
||||||
// * @return
|
|
||||||
// */
|
|
||||||
// private fun getOrBuildNode(): Config {
|
|
||||||
// return config ?: if (parent == null) {
|
|
||||||
// throw RuntimeException("The configuration for root node is note defined")
|
|
||||||
// } else {
|
|
||||||
// parent.getOrBuildNode().requestNode(name)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fun addValue(name: String) {
|
|
||||||
// getOrBuildNode().setValue(name, Null)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fun setValue(name: String, value: Value) {
|
|
||||||
// getOrBuildNode().setValue(name, value)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fun removeValue(valueName: String) {
|
|
||||||
// config?.removeValue(valueName)
|
|
||||||
// children.removeIf { it.name == name }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fun addNode(name: String) {
|
|
||||||
// getOrBuildNode().requestNode(name)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fun removeNode(name: String) {
|
|
||||||
// config?.removeNode(name)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun remove() {
|
|
||||||
// //FIXME does not work on multinodes
|
|
||||||
// parent?.removeNode(name)
|
|
||||||
// invalidate()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// final override fun invalidate() {
|
|
||||||
// actualDescriptor.invalidate()
|
|
||||||
// actualConfig.invalidate()
|
|
||||||
// hasValueProperty.invalidate()
|
|
||||||
//
|
|
||||||
// val nodeNames = ArrayList<String>()
|
|
||||||
// val valueNames = ArrayList<String>()
|
|
||||||
//
|
|
||||||
// config?.apply {
|
|
||||||
// nodeNames.addAll(this.nodeNames.toList())
|
|
||||||
// valueNames.addAll(this.valueNames.toList())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// descriptor?.apply {
|
|
||||||
// nodeNames.addAll(childrenDescriptors().keys)
|
|
||||||
// valueNames.addAll(valueDescriptors().keys)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// //removing old values
|
|
||||||
// children.removeIf { !(valueNames.contains(it.name) || nodeNames.contains(it.name)) }
|
|
||||||
//
|
|
||||||
// valueNames.forEach { name ->
|
|
||||||
// children.find { it.name == name }?.invalidate().orElse {
|
|
||||||
// children.add(ConfigFXValue(name, this))
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// nodeNames.forEach { name ->
|
|
||||||
// children.find { it.name == name }?.invalidate().orElse {
|
|
||||||
// children.add(ConfigFXNode(name, this))
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// children.sortBy { it.name }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fun updateValue(path: Name, value: Value?) {
|
|
||||||
// when {
|
|
||||||
// path.length == 0 -> kotlin.error("Path never could be empty when updating value")
|
|
||||||
// path.length == 1 -> {
|
|
||||||
// val hasDescriptor = descriptor?.getValueDescriptor(path) != null
|
|
||||||
// if (value == null && !hasDescriptor) {
|
|
||||||
// //removing the value if it is present
|
|
||||||
// children.removeIf { it.name == path.unescaped }
|
|
||||||
// } else {
|
|
||||||
// //invalidating value if it is present
|
|
||||||
// children.find { it is ConfigFXValue && it.name == path.unescaped }?.invalidate().orElse {
|
|
||||||
// //adding new node otherwise
|
|
||||||
// children.add(ConfigFXValue(path.unescaped, this))
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// path.length > 1 -> children.filterIsInstance<ConfigFXNode>().find { it.name == path.first.unescaped }?.updateValue(
|
|
||||||
// path.cutFirst(),
|
|
||||||
// value
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fun updateNode(path: Name, list: List<Meta>) {
|
|
||||||
// when {
|
|
||||||
// path.isEmpty() -> invalidate()
|
|
||||||
// path.length == 1 -> {
|
|
||||||
// val hasDescriptor = descriptor?.getNodeDescriptor(path.unescaped) != null
|
|
||||||
// if (list.isEmpty() && !hasDescriptor) {
|
|
||||||
// children.removeIf { it.name == path.unescaped }
|
|
||||||
// } else {
|
|
||||||
// children.find { it is ConfigFXNode && it.name == path.unescaped }?.invalidate().orElse {
|
|
||||||
// children.add(ConfigFXNode(path.unescaped, this))
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else -> children.filterIsInstance<ConfigFXNode>().find { it.name == path.first.toString() }?.updateNode(
|
|
||||||
// path.cutFirst(),
|
|
||||||
// list
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//class ConfigFXRoot(rootConfig: Config, rootDescriptor: NodeDescriptor? = null) : ConfigFXNode(rootConfig.name),
|
|
||||||
// ConfigChangeListener {
|
|
||||||
//
|
|
||||||
// init {
|
|
||||||
// configProperty.set(rootConfig)
|
|
||||||
// descriptorProperty.set(rootDescriptor)
|
|
||||||
// rootConfig.addListener(this)
|
|
||||||
// invalidate()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun notifyValueChanged(name: Name, oldItem: Value?, newItem: Value?) {
|
|
||||||
// updateValue(name, newItem)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun notifyNodeChanged(nodeName: Name, oldItem: List<Meta>, newItem: List<Meta>) {
|
|
||||||
// updateNode(nodeName, newItem)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//
|
|
||||||
///**
|
|
||||||
// * Created by darksnake on 01-May-17.
|
|
||||||
// */
|
|
||||||
//class ConfigFXValue(name: String, parent: ConfigFXNode) : ConfigFX(name) {
|
|
||||||
//
|
|
||||||
// init {
|
|
||||||
// parentProperty.set(parent)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override val hasValueProperty = parentProperty.booleanBinding(nameProperty) {
|
|
||||||
// it?.config?.hasValue(this.name) ?: false
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// override val children: ObservableList<ConfigFX> = FXCollections.emptyObservableList()
|
|
||||||
//
|
|
||||||
// val descriptor: ValueDescriptor? = parent.descriptor?.values[name]
|
|
||||||
//
|
|
||||||
// override val descriptionProperty: ObservableStringValue = object : StringBinding() {
|
|
||||||
// override fun computeValue(): String {
|
|
||||||
// return descriptor?.info ?: ""
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// val valueProperty = parentProperty.objectBinding(nameProperty) {
|
|
||||||
// parent.config?.optValue(name).nullable ?: descriptor?.default
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// var value: Value
|
|
||||||
// set(value) {
|
|
||||||
// parent?.setValue(name, value)
|
|
||||||
// }
|
|
||||||
// get() = valueProperty.value ?: Value.NULL
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// override fun remove() {
|
|
||||||
// parent?.removeValue(name)
|
|
||||||
// invalidate()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun invalidate() {
|
|
||||||
// valueProperty.invalidate()
|
|
||||||
// hasValueProperty.invalidate()
|
|
||||||
// }
|
|
||||||
//}
|
|
@ -1,9 +1,13 @@
|
|||||||
package hep.dataforge.vis.fx.meta
|
package hep.dataforge.vis.fx.meta
|
||||||
|
|
||||||
|
import hep.dataforge.descriptors.ItemDescriptor
|
||||||
import hep.dataforge.descriptors.NodeDescriptor
|
import hep.dataforge.descriptors.NodeDescriptor
|
||||||
|
import hep.dataforge.descriptors.ValueDescriptor
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
|
import hep.dataforge.names.Name
|
||||||
import hep.dataforge.names.NameToken
|
import hep.dataforge.names.NameToken
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
|
import hep.dataforge.values.Null
|
||||||
import hep.dataforge.values.Value
|
import hep.dataforge.values.Value
|
||||||
import javafx.beans.binding.ListBinding
|
import javafx.beans.binding.ListBinding
|
||||||
import javafx.beans.binding.ObjectBinding
|
import javafx.beans.binding.ObjectBinding
|
||||||
@ -13,67 +17,129 @@ import javafx.beans.value.ObservableStringValue
|
|||||||
import javafx.collections.ObservableList
|
import javafx.collections.ObservableList
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
sealed class FXMeta {
|
/**
|
||||||
|
* A display for meta and descriptor
|
||||||
|
*/
|
||||||
|
sealed class FXMeta<M : MetaNode<M>> : Comparable<FXMeta<*>> {
|
||||||
abstract val name: NameToken
|
abstract val name: NameToken
|
||||||
abstract val parent: FXMetaNode<*>?
|
abstract val parent: FXMetaNode<M>?
|
||||||
abstract val descriptionProperty: ObservableStringValue
|
abstract val descriptionProperty: ObservableStringValue
|
||||||
|
abstract val descriptor: ItemDescriptor?
|
||||||
|
|
||||||
abstract val hasValue: ObservableBooleanValue
|
abstract val hasValue: ObservableBooleanValue
|
||||||
|
|
||||||
companion object {
|
override fun compareTo(other: FXMeta<*>): Int {
|
||||||
fun <M : MetaNode<M>> root(node: M, descriptor: NodeDescriptor? = null): FXMetaNode<M> =
|
return if (this.hasValue.get() == other.hasValue.get()) {
|
||||||
FXMetaNode(NameToken("root"), null, node, descriptor)
|
this.name.toString().compareTo(other.name.toString())
|
||||||
|
} else {
|
||||||
|
this.hasValue.get().compareTo(other.hasValue.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun root(node: Meta, descriptor: NodeDescriptor? = null): FXMetaNode<SealedMeta> =
|
companion object {
|
||||||
root(node.seal(), descriptor)
|
fun <M : MetaNode<M>> root(
|
||||||
|
node: M,
|
||||||
|
descriptor: NodeDescriptor? = null,
|
||||||
|
rootName: String = "root"
|
||||||
|
): FXMetaNode<M> =
|
||||||
|
FXMetaNode(NameToken(rootName), null, node, descriptor)
|
||||||
|
|
||||||
|
fun root(node: Meta, descriptor: NodeDescriptor? = null, rootName: String = "root"): FXMetaNode<SealedMeta> =
|
||||||
|
root(node.seal(), descriptor, rootName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FXMetaNode<M : MetaNode<M>>(
|
class FXMetaNode<M : MetaNode<M>>(
|
||||||
override val name: NameToken,
|
override val name: NameToken,
|
||||||
override val parent: FXMetaNode<M>?,
|
override val parent: FXMetaNode<M>?,
|
||||||
node: M? = null,
|
nodeValue: M? = null,
|
||||||
descriptor: NodeDescriptor? = null
|
descriptorValue: NodeDescriptor? = null
|
||||||
) : FXMeta() {
|
) : FXMeta<M>() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A descriptor that could be manually set to the node
|
* A descriptor that could be manually set to the node
|
||||||
*/
|
*/
|
||||||
val descriptorProperty = SimpleObjectProperty(descriptor)
|
private val innerDescriptorProperty = SimpleObjectProperty(descriptorValue)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actual descriptor which holds value inferred from parrent
|
* Actual descriptor which holds value inferred from parrent
|
||||||
*/
|
*/
|
||||||
private val actualDescriptorProperty = objectBinding(descriptorProperty) {
|
val descriptorProperty = objectBinding(innerDescriptorProperty) {
|
||||||
value ?: parent?.descriptor?.nodes?.get(this@FXMetaNode.name.body)
|
value ?: parent?.descriptor?.nodes?.get(this@FXMetaNode.name.body)
|
||||||
}
|
}
|
||||||
|
|
||||||
val descriptor: NodeDescriptor? by actualDescriptorProperty
|
override val descriptor: NodeDescriptor? by descriptorProperty
|
||||||
|
|
||||||
private val innerNodeProperty = SimpleObjectProperty(node)
|
private val innerNodeProperty = SimpleObjectProperty(nodeValue)
|
||||||
|
|
||||||
val nodeProperty: ObjectBinding<M?> = objectBinding(innerNodeProperty) {
|
val nodeProperty: ObjectBinding<M?> = objectBinding(innerNodeProperty) {
|
||||||
value ?: parent?.node?.get(this@FXMetaNode.name.asName()).node
|
value ?: parent?.node?.get(this@FXMetaNode.name).node
|
||||||
}
|
}
|
||||||
|
|
||||||
val node: M? by nodeProperty
|
val node: M? by nodeProperty
|
||||||
|
|
||||||
override val descriptionProperty = descriptorProperty.stringBinding { it?.info ?: "" }
|
override val descriptionProperty = innerDescriptorProperty.stringBinding { it?.info ?: "" }
|
||||||
|
|
||||||
override val hasValue: ObservableBooleanValue = nodeProperty.booleanBinding { it != null }
|
override val hasValue: ObservableBooleanValue = nodeProperty.booleanBinding { it != null }
|
||||||
|
|
||||||
val children = object : ListBinding<FXMeta>() {
|
private val filter: (FXMeta<M>) -> Boolean = { cfg ->
|
||||||
override fun computeValue(): ObservableList<FXMeta> {
|
!(cfg.descriptor?.tags?.contains(ConfigEditor.NO_CONFIGURATOR_TAG) ?: false)
|
||||||
TODO()
|
}
|
||||||
|
|
||||||
|
val children = object : ListBinding<FXMeta<M>>() {
|
||||||
|
|
||||||
|
init {
|
||||||
|
bind(nodeProperty, descriptorProperty)
|
||||||
|
|
||||||
|
val listener: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit = { name, _, _ ->
|
||||||
|
if (name.length == 1) invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
(node as? MutableMeta<*>)?.onChange(this, listener)
|
||||||
|
|
||||||
|
nodeProperty.addListener { _, oldValue, newValue ->
|
||||||
|
if (newValue == null) {
|
||||||
|
(oldValue as? MutableMeta<*>)?.removeListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newValue is MutableMeta<*>) {
|
||||||
|
newValue.onChange(this, listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun computeValue(): ObservableList<FXMeta<M>> {
|
||||||
|
val nodeKeys = node?.items?.keys?.toSet() ?: emptySet()
|
||||||
|
val descriptorKeys = descriptor?.items?.keys?.map { NameToken(it) } ?: emptyList()
|
||||||
|
val keys: Set<NameToken> = nodeKeys + descriptorKeys
|
||||||
|
|
||||||
|
val items = keys.map { token ->
|
||||||
|
val actualItem = node?.items?.get(token)
|
||||||
|
val actualDescriptor = descriptor?.items?.get(token.body)
|
||||||
|
|
||||||
|
if (actualItem is MetaItem.NodeItem || actualDescriptor is NodeDescriptor) {
|
||||||
|
FXMetaNode(token, this@FXMetaNode)
|
||||||
|
} else {
|
||||||
|
FXMetaValue(token, this@FXMetaNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return items.filter(filter).observable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (parent != null) {
|
||||||
|
parent.descriptorProperty.onChange { descriptorProperty.invalidate() }
|
||||||
|
parent.nodeProperty.onChange { nodeProperty.invalidate() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FXMetaValue(
|
class FXMetaValue<M : MetaNode<M>>(
|
||||||
override val name: NameToken,
|
override val name: NameToken,
|
||||||
override val parent: FXMetaNode<*>,
|
override val parent: FXMetaNode<M>
|
||||||
value: Value? = null
|
) : FXMeta<M>() {
|
||||||
) : FXMeta() {
|
|
||||||
|
|
||||||
val descriptorProperty = parent.descriptorProperty.objectBinding {
|
val descriptorProperty = parent.descriptorProperty.objectBinding {
|
||||||
it?.values?.get(name.body)
|
it?.values?.get(name.body)
|
||||||
@ -82,15 +148,15 @@ class FXMetaValue(
|
|||||||
/**
|
/**
|
||||||
* A descriptor that could be manually set to the node
|
* A descriptor that could be manually set to the node
|
||||||
*/
|
*/
|
||||||
val descriptor by descriptorProperty
|
override val descriptor: ValueDescriptor? by descriptorProperty
|
||||||
|
|
||||||
private val innerValueProperty = SimpleObjectProperty(value)
|
//private val innerValueProperty = SimpleObjectProperty(value)
|
||||||
|
|
||||||
val valueProperty = descriptorProperty.objectBinding { descriptor ->
|
val valueProperty = descriptorProperty.objectBinding { descriptor ->
|
||||||
parent.node[name].value ?: descriptor?.default
|
parent.node[name].value ?: descriptor?.default
|
||||||
}
|
}
|
||||||
|
|
||||||
override val hasValue: ObservableBooleanValue = valueProperty.booleanBinding { it != null }
|
override val hasValue: ObservableBooleanValue = parent.nodeProperty.booleanBinding { it[name] != null }
|
||||||
|
|
||||||
val value by valueProperty
|
val value by valueProperty
|
||||||
|
|
||||||
@ -102,18 +168,36 @@ fun <M : MutableMeta<M>> FXMetaNode<M>.remove(name: NameToken) {
|
|||||||
children.invalidate()
|
children.invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FXMeta.remove() {
|
private fun <M : MutableMeta<M>> M.createEmptyNode(token: NameToken): M {
|
||||||
(parent?.node as? MutableMeta<*>)?.remove(name.asName())
|
this.setNode(token.asName(), EmptyMeta)
|
||||||
|
//FIXME possible concurrency bug
|
||||||
|
return get(token).node!!
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> FXMetaNode<M>.addValue(key: String){
|
fun <M : MutableMeta<M>> FXMetaNode<out M>.getOrCreateNode(): M {
|
||||||
TODO()
|
val node = node
|
||||||
|
return when {
|
||||||
|
node != null -> node
|
||||||
|
parent != null -> parent.getOrCreateNode().createEmptyNode(this.name).also {
|
||||||
|
parent.children.invalidate()
|
||||||
|
}
|
||||||
|
else -> kotlin.error("Orphan empty node is not allowed")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> FXMetaNode<M>.addNode(key: String){
|
fun <M : MutableMeta<M>> FXMeta<M>.remove() {
|
||||||
TODO()
|
parent?.node?.remove(name.asName())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FXMetaValue.set(value: Value?){
|
fun <M : MutableMeta<M>> FXMetaNode<M>.addValue(key: String) {
|
||||||
TODO()
|
getOrCreateNode()[key] = Null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <M : MutableMeta<M>> FXMetaNode<M>.addNode(key: String) {
|
||||||
|
getOrCreateNode()[key] = EmptyMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <M : MutableMeta<M>> FXMetaValue<M>.set(value: Value?) {
|
||||||
|
parent.getOrCreateNode()[this.name] = value
|
||||||
}
|
}
|
@ -17,7 +17,6 @@
|
|||||||
package hep.dataforge.vis.fx.meta
|
package hep.dataforge.vis.fx.meta
|
||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.seal
|
|
||||||
import hep.dataforge.vis.fx.dfIconView
|
import hep.dataforge.vis.fx.dfIconView
|
||||||
import javafx.beans.property.SimpleStringProperty
|
import javafx.beans.property.SimpleStringProperty
|
||||||
import javafx.scene.control.TreeItem
|
import javafx.scene.control.TreeItem
|
||||||
@ -25,15 +24,17 @@ import javafx.scene.control.TreeSortMode
|
|||||||
import javafx.scene.control.TreeTableView
|
import javafx.scene.control.TreeTableView
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
|
|
||||||
open class MetaViewer(val meta: Meta, title: String = "Meta viewer") : Fragment(title, dfIconView) {
|
class MetaViewer(val rootNode: FXMetaNode<*>, title: String = "Meta viewer") : Fragment(title, dfIconView) {
|
||||||
|
constructor(meta: Meta, title: String = "Meta viewer"): this(FXMeta.root(meta))
|
||||||
|
|
||||||
override val root = borderpane {
|
override val root = borderpane {
|
||||||
center {
|
center {
|
||||||
treetableview<FXMeta> {
|
treetableview<FXMeta<*>> {
|
||||||
isShowRoot = false
|
isShowRoot = false
|
||||||
root = TreeItem(FXMeta.root(meta.seal()))
|
root = TreeItem(rootNode)
|
||||||
populate {
|
populate {
|
||||||
when (val fxMeta = it.value) {
|
when (val fxMeta = it.value) {
|
||||||
is FXMetaNode<*> -> {
|
is FXMetaNode -> {
|
||||||
fxMeta.children
|
fxMeta.children
|
||||||
}
|
}
|
||||||
is FXMetaValue -> null
|
is FXMetaValue -> null
|
||||||
@ -42,11 +43,11 @@ open class MetaViewer(val meta: Meta, title: String = "Meta viewer") : Fragment(
|
|||||||
root.isExpanded = true
|
root.isExpanded = true
|
||||||
sortMode = TreeSortMode.ALL_DESCENDANTS
|
sortMode = TreeSortMode.ALL_DESCENDANTS
|
||||||
columnResizePolicy = TreeTableView.CONSTRAINED_RESIZE_POLICY
|
columnResizePolicy = TreeTableView.CONSTRAINED_RESIZE_POLICY
|
||||||
column("Name", FXMeta::name)
|
column("Name", FXMeta<*>::name)
|
||||||
column<FXMeta, String>("Value"){
|
column<FXMeta<*>, String>("Value") { cellDataFeatures ->
|
||||||
when(val item = it.value.value){
|
when (val item = cellDataFeatures.value.value) {
|
||||||
is FXMetaValue -> item.valueProperty.stringBinding{it?.string?: ""}
|
is FXMetaValue -> item.valueProperty.stringBinding { it?.string ?: "" }
|
||||||
is FXMetaNode<*> -> SimpleStringProperty("[node]")
|
is FXMetaNode -> SimpleStringProperty("[node]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,9 @@ include(
|
|||||||
//if(file("../dataforge-core").exists()) {
|
//if(file("../dataforge-core").exists()) {
|
||||||
// includeBuild("../dataforge-core"){
|
// includeBuild("../dataforge-core"){
|
||||||
// dependencySubstitution {
|
// dependencySubstitution {
|
||||||
// substitute(module("hep.dataforge:dataforge-output")).with(project(":dataforge-output"))
|
// //substitute(module("hep.dataforge:dataforge-output")).with(project(":dataforge-output"))
|
||||||
|
// substitute(module("hep.dataforge:dataforge-output-jvm")).with(project(":dataforge-output"))
|
||||||
|
// substitute(module("hep.dataforge:dataforge-output-js")).with(project(":dataforge-output"))
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
Loading…
Reference in New Issue
Block a user