forked from kscience/visionforge
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 {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
maven("https://kotlin.bintray.com/kotlinx")
|
||||
maven("http://npm.mipt.ru:8081/artifactory/gradle-dev-local")
|
||||
|
@ -9,17 +9,17 @@ kotlin {
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
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 {
|
||||
api("hep.dataforge:dataforge-output-jvm:$dataforgeVersion")
|
||||
// api("hep.dataforge:dataforge-output-jvm:$dataforgeVersion")
|
||||
}
|
||||
}
|
||||
val jsMain by getting{
|
||||
val jsMain by getting {
|
||||
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
|
||||
*/
|
||||
class ConfigEditor(
|
||||
val configuration: Config,
|
||||
title: String = "Configuration editor",
|
||||
val descriptor: NodeDescriptor? = null
|
||||
val rootNode: FXMetaNode<Config>,
|
||||
title: String = "Configuration editor"
|
||||
) : Fragment(title = title, icon = dfIconView) {
|
||||
|
||||
val filter: (FXMeta) -> Boolean = { cfg ->
|
||||
when (cfg) {
|
||||
is FXMetaNode<*> -> !(cfg.descriptor?.tags?.contains(NO_CONFIGURATOR_TAG) ?: false)
|
||||
is FXMetaValue -> !(cfg.descriptor?.tags?.contains(NO_CONFIGURATOR_TAG) ?: false)
|
||||
}
|
||||
}
|
||||
constructor(config: Config, descriptor: NodeDescriptor, title: String = "Configuration editor") :
|
||||
this(FXMeta.root(config, descriptor = descriptor))
|
||||
|
||||
override val root = borderpane {
|
||||
center = treetableview<FXMeta> {
|
||||
root = TreeItem(FXMeta.root(configuration, descriptor))
|
||||
center = treetableview<FXMeta<Config>> {
|
||||
root = TreeItem(rootNode)
|
||||
root.isExpanded = true
|
||||
sortMode = TreeSortMode.ALL_DESCENDANTS
|
||||
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 {
|
||||
object : TextFieldTreeTableCell<FXMeta, NameToken>() {
|
||||
object : TextFieldTreeTableCell<FXMeta<Config>, NameToken>() {
|
||||
override fun updateItem(item: NameToken?, empty: Boolean) {
|
||||
super.updateItem(item, empty)
|
||||
contextMenu?.items?.removeIf { it.text == "Remove" }
|
||||
@ -57,7 +60,7 @@ class ConfigEditor(
|
||||
Color.GRAY
|
||||
}
|
||||
})
|
||||
if (treeTableRow.treeItem.value.hasValue.get()) {
|
||||
if (treeTableRow.treeItem.value.parent != null && treeTableRow.treeItem.value.hasValue.get()) {
|
||||
contextmenu {
|
||||
item("Remove") {
|
||||
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()
|
||||
}.setCellFactory {
|
||||
ValueCell()
|
||||
}
|
||||
|
||||
column("Description") { param: TreeTableColumn.CellDataFeatures<FXMeta, String> -> param.value.value.descriptionProperty }
|
||||
.setCellFactory { param: TreeTableColumn<FXMeta, String> ->
|
||||
val cell = TreeTableCell<FXMeta, String>()
|
||||
column("Description") { param: TreeTableColumn.CellDataFeatures<FXMeta<Config>, String> -> param.value.value.descriptionProperty }
|
||||
.setCellFactory { param: TreeTableColumn<FXMeta<Config>, String> ->
|
||||
val cell = TreeTableCell<FXMeta<Config>, String>()
|
||||
val text = Text()
|
||||
cell.graphic = text
|
||||
cell.prefHeight = Control.USE_COMPUTED_SIZE
|
||||
@ -112,22 +115,20 @@ class ConfigEditor(
|
||||
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 (item != null) {
|
||||
when (item) {
|
||||
is FXMetaValue -> {
|
||||
is FXMetaValue<Config> -> {
|
||||
text = null
|
||||
val chooser = ValueChooser.build(item.valueProperty, item.descriptor) {
|
||||
item.set(it)
|
||||
}
|
||||
graphic = chooser.node
|
||||
}
|
||||
is FXMetaNode<*> -> {
|
||||
item as FXMetaNode<Config>
|
||||
|
||||
is FXMetaNode<Config> -> {
|
||||
text = null
|
||||
graphic = hbox {
|
||||
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
|
||||
|
||||
import hep.dataforge.descriptors.ItemDescriptor
|
||||
import hep.dataforge.descriptors.NodeDescriptor
|
||||
import hep.dataforge.descriptors.ValueDescriptor
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.NameToken
|
||||
import hep.dataforge.names.asName
|
||||
import hep.dataforge.values.Null
|
||||
import hep.dataforge.values.Value
|
||||
import javafx.beans.binding.ListBinding
|
||||
import javafx.beans.binding.ObjectBinding
|
||||
@ -13,67 +17,129 @@ import javafx.beans.value.ObservableStringValue
|
||||
import javafx.collections.ObservableList
|
||||
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 parent: FXMetaNode<*>?
|
||||
abstract val parent: FXMetaNode<M>?
|
||||
abstract val descriptionProperty: ObservableStringValue
|
||||
abstract val descriptor: ItemDescriptor?
|
||||
|
||||
abstract val hasValue: ObservableBooleanValue
|
||||
|
||||
companion object {
|
||||
fun <M : MetaNode<M>> root(node: M, descriptor: NodeDescriptor? = null): FXMetaNode<M> =
|
||||
FXMetaNode(NameToken("root"), null, node, descriptor)
|
||||
override fun compareTo(other: FXMeta<*>): Int {
|
||||
return if (this.hasValue.get() == other.hasValue.get()) {
|
||||
this.name.toString().compareTo(other.name.toString())
|
||||
} else {
|
||||
this.hasValue.get().compareTo(other.hasValue.get())
|
||||
}
|
||||
}
|
||||
|
||||
fun root(node: Meta, descriptor: NodeDescriptor? = null): FXMetaNode<SealedMeta> =
|
||||
root(node.seal(), descriptor)
|
||||
companion object {
|
||||
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>>(
|
||||
override val name: NameToken,
|
||||
override val parent: FXMetaNode<M>?,
|
||||
node: M? = null,
|
||||
descriptor: NodeDescriptor? = null
|
||||
) : FXMeta() {
|
||||
nodeValue: M? = null,
|
||||
descriptorValue: NodeDescriptor? = null
|
||||
) : FXMeta<M>() {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
private val actualDescriptorProperty = objectBinding(descriptorProperty) {
|
||||
val descriptorProperty = objectBinding(innerDescriptorProperty) {
|
||||
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) {
|
||||
value ?: parent?.node?.get(this@FXMetaNode.name.asName()).node
|
||||
value ?: parent?.node?.get(this@FXMetaNode.name).node
|
||||
}
|
||||
|
||||
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 }
|
||||
|
||||
val children = object : ListBinding<FXMeta>() {
|
||||
override fun computeValue(): ObservableList<FXMeta> {
|
||||
TODO()
|
||||
private val filter: (FXMeta<M>) -> Boolean = { cfg ->
|
||||
!(cfg.descriptor?.tags?.contains(ConfigEditor.NO_CONFIGURATOR_TAG) ?: false)
|
||||
}
|
||||
|
||||
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 parent: FXMetaNode<*>,
|
||||
value: Value? = null
|
||||
) : FXMeta() {
|
||||
override val parent: FXMetaNode<M>
|
||||
) : FXMeta<M>() {
|
||||
|
||||
val descriptorProperty = parent.descriptorProperty.objectBinding {
|
||||
it?.values?.get(name.body)
|
||||
@ -82,15 +148,15 @@ class FXMetaValue(
|
||||
/**
|
||||
* 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 ->
|
||||
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
|
||||
|
||||
@ -102,18 +168,36 @@ fun <M : MutableMeta<M>> FXMetaNode<M>.remove(name: NameToken) {
|
||||
children.invalidate()
|
||||
}
|
||||
|
||||
fun FXMeta.remove() {
|
||||
(parent?.node as? MutableMeta<*>)?.remove(name.asName())
|
||||
private fun <M : MutableMeta<M>> M.createEmptyNode(token: NameToken): M {
|
||||
this.setNode(token.asName(), EmptyMeta)
|
||||
//FIXME possible concurrency bug
|
||||
return get(token).node!!
|
||||
}
|
||||
|
||||
fun <M : MutableMeta<M>> FXMetaNode<M>.addValue(key: String){
|
||||
TODO()
|
||||
fun <M : MutableMeta<M>> FXMetaNode<out M>.getOrCreateNode(): M {
|
||||
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){
|
||||
TODO()
|
||||
fun <M : MutableMeta<M>> FXMeta<M>.remove() {
|
||||
parent?.node?.remove(name.asName())
|
||||
}
|
||||
|
||||
fun FXMetaValue.set(value: Value?){
|
||||
TODO()
|
||||
fun <M : MutableMeta<M>> FXMetaNode<M>.addValue(key: String) {
|
||||
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
|
||||
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.seal
|
||||
import hep.dataforge.vis.fx.dfIconView
|
||||
import javafx.beans.property.SimpleStringProperty
|
||||
import javafx.scene.control.TreeItem
|
||||
@ -25,15 +24,17 @@ import javafx.scene.control.TreeSortMode
|
||||
import javafx.scene.control.TreeTableView
|
||||
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 {
|
||||
center {
|
||||
treetableview<FXMeta> {
|
||||
treetableview<FXMeta<*>> {
|
||||
isShowRoot = false
|
||||
root = TreeItem(FXMeta.root(meta.seal()))
|
||||
root = TreeItem(rootNode)
|
||||
populate {
|
||||
when (val fxMeta = it.value) {
|
||||
is FXMetaNode<*> -> {
|
||||
is FXMetaNode -> {
|
||||
fxMeta.children
|
||||
}
|
||||
is FXMetaValue -> null
|
||||
@ -42,11 +43,11 @@ open class MetaViewer(val meta: Meta, title: String = "Meta viewer") : Fragment(
|
||||
root.isExpanded = true
|
||||
sortMode = TreeSortMode.ALL_DESCENDANTS
|
||||
columnResizePolicy = TreeTableView.CONSTRAINED_RESIZE_POLICY
|
||||
column("Name", FXMeta::name)
|
||||
column<FXMeta, String>("Value"){
|
||||
when(val item = it.value.value){
|
||||
is FXMetaValue -> item.valueProperty.stringBinding{it?.string?: ""}
|
||||
is FXMetaNode<*> -> SimpleStringProperty("[node]")
|
||||
column("Name", FXMeta<*>::name)
|
||||
column<FXMeta<*>, String>("Value") { cellDataFeatures ->
|
||||
when (val item = cellDataFeatures.value.value) {
|
||||
is FXMetaValue -> item.valueProperty.stringBinding { it?.string ?: "" }
|
||||
is FXMetaNode -> SimpleStringProperty("[node]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,9 @@ include(
|
||||
//if(file("../dataforge-core").exists()) {
|
||||
// includeBuild("../dataforge-core"){
|
||||
// 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