Styleable and updates to Configuration
This commit is contained in:
parent
9395b6fa5f
commit
8829795a12
@ -5,7 +5,7 @@ plugins {
|
|||||||
description = "The basic interfaces for DataForge meta-data"
|
description = "The basic interfaces for DataForge meta-data"
|
||||||
|
|
||||||
group 'hep.dataforge'
|
group 'hep.dataforge'
|
||||||
version '0.1.0-SNAPSHOT'
|
version '0.1.1-SNAPSHOT'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package hep.dataforge.meta
|
package hep.dataforge.meta
|
||||||
|
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
import hep.dataforge.names.plus
|
||||||
|
|
||||||
//TODO add validator to configuration
|
//TODO add validator to configuration
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -10,35 +13,25 @@ class Configuration : MutableMetaNode<Configuration>() {
|
|||||||
/**
|
/**
|
||||||
* Attach configuration node instead of creating one
|
* Attach configuration node instead of creating one
|
||||||
*/
|
*/
|
||||||
override fun wrap(meta: Meta): Configuration {
|
override fun wrap(name: Name, meta: Meta): Configuration {
|
||||||
return meta as? Configuration ?: Configuration().also { builder ->
|
return meta as? Configuration ?: Configuration().also { builder ->
|
||||||
items.mapValues { entry ->
|
meta.items.mapValues { entry ->
|
||||||
val item = entry.value
|
val item = entry.value
|
||||||
builder[entry.key] = when (item) {
|
builder[entry.key] = when (item) {
|
||||||
is MetaItem.ValueItem -> MetaItem.ValueItem(item.value)
|
is MetaItem.ValueItem -> MetaItem.ValueItem(item.value)
|
||||||
is MetaItem.SingleNodeItem -> MetaItem.SingleNodeItem(wrap(item.node))
|
is MetaItem.SingleNodeItem -> MetaItem.SingleNodeItem(wrap(name + entry.key, item.node))
|
||||||
is MetaItem.MultiNodeItem -> MetaItem.MultiNodeItem(item.nodes.map { wrap(it) })
|
is MetaItem.MultiNodeItem -> MetaItem.MultiNodeItem(item.nodes.map { wrap(name + entry.key, it) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun empty(): Configuration = Configuration()
|
|
||||||
|
|
||||||
/**
|
override fun empty(): Configuration = Configuration()
|
||||||
* Universal set method
|
|
||||||
*/
|
|
||||||
operator fun set(key: String, value: Any?) {
|
|
||||||
when (value) {
|
|
||||||
null -> remove(key)
|
|
||||||
is Meta -> set(key, value)
|
|
||||||
else -> set(key, Value.of(value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Configurable {
|
interface Configurable {
|
||||||
val config: Configuration
|
val config: Configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
open class SimpleConfigurable(override val config:Configuration): Configurable
|
open class SimpleConfigurable(override val config: Configuration) : Configurable
|
@ -7,6 +7,8 @@ import kotlin.reflect.KProperty
|
|||||||
|
|
||||||
/* Meta delegates */
|
/* Meta delegates */
|
||||||
|
|
||||||
|
//TODO add caching for sealed nodes
|
||||||
|
|
||||||
class ValueDelegate(private val key: String? = null, private val default: Value? = null) : ReadOnlyProperty<Metoid, Value?> {
|
class ValueDelegate(private val key: String? = null, private val default: Value? = null) : ReadOnlyProperty<Metoid, Value?> {
|
||||||
override fun getValue(thisRef: Metoid, property: KProperty<*>): Value? {
|
override fun getValue(thisRef: Metoid, property: KProperty<*>): Value? {
|
||||||
return thisRef.meta[key ?: property.name]?.value ?: default
|
return thisRef.meta[key ?: property.name]?.value ?: default
|
||||||
|
@ -38,7 +38,7 @@ operator fun Meta.get(name: Name): MetaItem<out Meta>? {
|
|||||||
return when (name.length) {
|
return when (name.length) {
|
||||||
0 -> error("Can't resolve element from empty name")
|
0 -> error("Can't resolve element from empty name")
|
||||||
1 -> items[name.first()!!.body]
|
1 -> items[name.first()!!.body]
|
||||||
else -> name.first()!!.let{ token -> items[token.body]?.nodes?.get(token.query)}?.get(name.cutFirst())
|
else -> name.first()!!.let { token -> items[token.body]?.nodes?.get(token.query) }?.get(name.cutFirst())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,14 +48,14 @@ operator fun Meta.get(key: String): MetaItem<out Meta>? = get(key.toName())
|
|||||||
/**
|
/**
|
||||||
* A meta node that ensures that all of its descendants has at least the same type
|
* A meta node that ensures that all of its descendants has at least the same type
|
||||||
*/
|
*/
|
||||||
abstract class MetaNode<M: MetaNode<M>>: Meta{
|
abstract class MetaNode<M : MetaNode<M>> : Meta {
|
||||||
abstract override val items: Map<String, MetaItem<M>>
|
abstract override val items: Map<String, MetaItem<M>>
|
||||||
|
|
||||||
operator fun get(name: Name): MetaItem<M>? {
|
operator fun get(name: Name): MetaItem<M>? {
|
||||||
return when (name.length) {
|
return when (name.length) {
|
||||||
0 -> error("Can't resolve element from empty name")
|
0 -> error("Can't resolve element from empty name")
|
||||||
1 -> items[name.first()!!.body]
|
1 -> items[name.first()!!.body]
|
||||||
else -> name.first()!!.let{ token -> items[token.body]?.nodes?.get(token.query)}?.get(name.cutFirst())
|
else -> name.first()!!.let { token -> items[token.body]?.nodes?.get(token.query) }?.get(name.cutFirst())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,9 +87,13 @@ class SealedMeta(meta: Meta) : MetaNode<SealedMeta>() {
|
|||||||
*/
|
*/
|
||||||
fun Meta.seal(): SealedMeta = this as? SealedMeta ?: SealedMeta(this)
|
fun Meta.seal(): SealedMeta = this as? SealedMeta ?: SealedMeta(this)
|
||||||
|
|
||||||
|
object EmptyMeta : Meta {
|
||||||
|
override val items: Map<String, MetaItem<out Meta>> = emptyMap()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic meta-holder object
|
* Generic meta-holder object
|
||||||
*/
|
*/
|
||||||
interface Metoid{
|
interface Metoid {
|
||||||
val meta: Meta
|
val meta: Meta
|
||||||
}
|
}
|
@ -1,10 +1,12 @@
|
|||||||
package hep.dataforge.meta
|
package hep.dataforge.meta
|
||||||
|
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DSL builder for meta. Is not intended to store mutable state
|
* DSL builder for meta. Is not intended to store mutable state
|
||||||
*/
|
*/
|
||||||
class MetaBuilder : MutableMetaNode<MetaBuilder>() {
|
class MetaBuilder : MutableMetaNode<MetaBuilder>() {
|
||||||
override fun wrap(meta: Meta): MetaBuilder = meta.builder()
|
override fun wrap(name: Name, meta: Meta): MetaBuilder = meta.builder()
|
||||||
override fun empty(): MetaBuilder = MetaBuilder()
|
override fun empty(): MetaBuilder = MetaBuilder()
|
||||||
|
|
||||||
infix fun String.to(value: Any) {
|
infix fun String.to(value: Any) {
|
||||||
|
@ -10,7 +10,10 @@ class MetaListener(val owner: Any? = null, val action: (name: Name, oldItem: Met
|
|||||||
|
|
||||||
|
|
||||||
interface MutableMeta<M : MutableMeta<M>> : Meta {
|
interface MutableMeta<M : MutableMeta<M>> : Meta {
|
||||||
|
override val items: Map<String, MetaItem<M>>
|
||||||
operator fun set(name: Name, item: MetaItem<M>?)
|
operator fun set(name: Name, item: MetaItem<M>?)
|
||||||
|
fun onChange(owner: Any? = null, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit)
|
||||||
|
fun removeListener(owner: Any)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,14 +25,14 @@ abstract class MutableMetaNode<M : MutableMetaNode<M>> : MetaNode<M>(), MutableM
|
|||||||
/**
|
/**
|
||||||
* Add change listener to this meta. Owner is declared to be able to remove listeners later. Listener without owner could not be removed
|
* Add change listener to this meta. Owner is declared to be able to remove listeners later. Listener without owner could not be removed
|
||||||
*/
|
*/
|
||||||
fun onChange(owner: Any? = null, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit) {
|
override fun onChange(owner: Any?, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit) {
|
||||||
listeners.add(MetaListener(owner, action))
|
listeners.add(MetaListener(owner, action))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all listeners belonging to given owner
|
* Remove all listeners belonging to given owner
|
||||||
*/
|
*/
|
||||||
fun removeListener(owner: Any) {
|
override fun removeListener(owner: Any) {
|
||||||
listeners.removeAll { it.owner === owner }
|
listeners.removeAll { it.owner === owner }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,13 +64,15 @@ abstract class MutableMetaNode<M : MutableMetaNode<M>> : MetaNode<M>(), MutableM
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform given meta to node type of this meta tree
|
* Transform given meta to node type of this meta tree
|
||||||
|
* @param name the name of the node where meta should be attached. Needed for correct assignment validators and styles
|
||||||
|
* @param meta the node itself
|
||||||
*/
|
*/
|
||||||
protected abstract fun wrap(meta: Meta): M
|
abstract fun wrap(name: Name, meta: Meta): M
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create empty node
|
* Create empty node
|
||||||
*/
|
*/
|
||||||
protected abstract fun empty(): M
|
abstract fun empty(): M
|
||||||
|
|
||||||
override operator fun set(name: Name, item: MetaItem<M>?) {
|
override operator fun set(name: Name, item: MetaItem<M>?) {
|
||||||
when (name.length) {
|
when (name.length) {
|
||||||
@ -87,14 +92,29 @@ abstract class MutableMetaNode<M : MutableMetaNode<M>> : MetaNode<M>(), MutableM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun remove(name: String) = set(name.toName(), null)
|
|
||||||
|
|
||||||
operator fun set(name: Name, value: Value) = set(name, MetaItem.ValueItem(value))
|
}
|
||||||
operator fun set(name: Name, meta: Meta) = set(name, MetaItem.SingleNodeItem(wrap(meta)))
|
|
||||||
operator fun set(name: Name, metas: List<Meta>) = set(name, MetaItem.MultiNodeItem(metas.map { wrap(it) }))
|
fun <M : MutableMeta<M>> M.remove(name: Name) = set(name, null)
|
||||||
|
fun <M : MutableMeta<M>> M.remove(name: String) = remove(name.toName())
|
||||||
operator fun set(name: String, item: MetaItem<M>) = set(name.toName(), item)
|
|
||||||
operator fun set(name: String, value: Value) = set(name.toName(), MetaItem.ValueItem(value))
|
operator fun <M : MutableMeta<M>> M.set(name: Name, value: Value) = set(name, MetaItem.ValueItem(value))
|
||||||
operator fun set(name: String, meta: Meta) = set(name.toName(), MetaItem.SingleNodeItem(wrap(meta)))
|
operator fun <M : MutableMetaNode<M>> M.set(name: Name, meta: Meta) = set(name, MetaItem.SingleNodeItem(wrap(name, meta)))
|
||||||
operator fun set(name: String, metas: List<Meta>) = set(name.toName(), MetaItem.MultiNodeItem(metas.map { wrap(it) }))
|
operator fun <M : MutableMetaNode<M>> M.set(name: Name, metas: List<Meta>) = set(name, MetaItem.MultiNodeItem(metas.map { wrap(name, it) }))
|
||||||
|
|
||||||
|
operator fun <M : MutableMeta<M>> M.set(name: String, item: MetaItem<M>) = set(name.toName(), item)
|
||||||
|
operator fun <M : MutableMeta<M>> M.set(name: String, value: Value) = set(name.toName(), MetaItem.ValueItem(value))
|
||||||
|
operator fun <M : MutableMetaNode<M>> M.set(name: String, meta: Meta) = set(name.toName(), meta)
|
||||||
|
operator fun <M : MutableMetaNode<M>> M.set(name: String, metas: List<Meta>) = set(name.toName(), metas)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Universal set method
|
||||||
|
*/
|
||||||
|
operator fun <M : MutableMeta<M>> M.set(key: String, value: Any?) {
|
||||||
|
when (value) {
|
||||||
|
null -> remove(key)
|
||||||
|
is Meta -> set(key, value)
|
||||||
|
else -> set(key, Value.of(value))
|
||||||
|
}
|
||||||
}
|
}
|
58
src/main/kotlin/hep/dataforge/meta/Styleable.kt
Normal file
58
src/main/kotlin/hep/dataforge/meta/Styleable.kt
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package hep.dataforge.meta
|
||||||
|
|
||||||
|
import hep.dataforge.names.Name
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A configuration decorator with applied style
|
||||||
|
*/
|
||||||
|
class StyledConfig(val config: Configuration, val style: Meta = EmptyMeta) : MutableMeta<StyledConfig> {
|
||||||
|
|
||||||
|
override fun onChange(owner: Any?, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit) {
|
||||||
|
config.onChange(owner, action)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeListener(owner: Any) {
|
||||||
|
config.removeListener(owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun set(name: Name, item: MetaItem<StyledConfig>?) {
|
||||||
|
when (item) {
|
||||||
|
null -> config.remove(name)
|
||||||
|
is MetaItem.ValueItem -> config[name] = item.value
|
||||||
|
is MetaItem.SingleNodeItem -> config[name] = item.node
|
||||||
|
is MetaItem.MultiNodeItem -> config[name] = item.nodes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val items: Map<String, MetaItem<StyledConfig>>
|
||||||
|
get() = (config.items.keys + style.items.keys).associate { key ->
|
||||||
|
val value = config.items[key]
|
||||||
|
val styleValue = style[key]
|
||||||
|
val item: MetaItem<StyledConfig> = when (value) {
|
||||||
|
null -> when (styleValue) {
|
||||||
|
null -> error("Should be unreachable")
|
||||||
|
is MetaItem.ValueItem -> MetaItem.ValueItem(styleValue.value)
|
||||||
|
is MetaItem.SingleNodeItem -> MetaItem.SingleNodeItem(StyledConfig(config.empty(), styleValue.node))
|
||||||
|
is MetaItem.MultiNodeItem -> MetaItem.MultiNodeItem(styleValue.nodes.map { StyledConfig(config.empty(), it) })
|
||||||
|
}
|
||||||
|
is MetaItem.ValueItem -> MetaItem.ValueItem(value.value)
|
||||||
|
is MetaItem.SingleNodeItem -> MetaItem.SingleNodeItem(
|
||||||
|
StyledConfig(value.node, styleValue?.node ?: EmptyMeta)
|
||||||
|
)
|
||||||
|
is MetaItem.MultiNodeItem -> MetaItem.MultiNodeItem(value.nodes.map {
|
||||||
|
StyledConfig(it, styleValue?.node ?: EmptyMeta)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
key to item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Styleable : Configurable {
|
||||||
|
val styledConfig: StyledConfig
|
||||||
|
|
||||||
|
override val config
|
||||||
|
get() = styledConfig.config
|
||||||
|
|
||||||
|
val style
|
||||||
|
get() = styledConfig.style
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user