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"
|
||||
|
||||
group 'hep.dataforge'
|
||||
version '0.1.0-SNAPSHOT'
|
||||
version '0.1.1-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
@ -1,5 +1,8 @@
|
||||
package hep.dataforge.meta
|
||||
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.plus
|
||||
|
||||
//TODO add validator to configuration
|
||||
|
||||
/**
|
||||
@ -10,35 +13,25 @@ class Configuration : MutableMetaNode<Configuration>() {
|
||||
/**
|
||||
* 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 ->
|
||||
items.mapValues { entry ->
|
||||
meta.items.mapValues { entry ->
|
||||
val item = entry.value
|
||||
builder[entry.key] = when (item) {
|
||||
is MetaItem.ValueItem -> MetaItem.ValueItem(item.value)
|
||||
is MetaItem.SingleNodeItem -> MetaItem.SingleNodeItem(wrap(item.node))
|
||||
is MetaItem.MultiNodeItem -> MetaItem.MultiNodeItem(item.nodes.map { wrap(it) })
|
||||
is MetaItem.SingleNodeItem -> MetaItem.SingleNodeItem(wrap(name + entry.key, item.node))
|
||||
is MetaItem.MultiNodeItem -> MetaItem.MultiNodeItem(item.nodes.map { wrap(name + entry.key, it) })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
override fun empty(): Configuration = Configuration()
|
||||
}
|
||||
|
||||
interface Configurable {
|
||||
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 */
|
||||
|
||||
//TODO add caching for sealed nodes
|
||||
|
||||
class ValueDelegate(private val key: String? = null, private val default: Value? = null) : ReadOnlyProperty<Metoid, Value?> {
|
||||
override fun getValue(thisRef: Metoid, property: KProperty<*>): Value? {
|
||||
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) {
|
||||
0 -> error("Can't resolve element from empty name")
|
||||
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
|
||||
*/
|
||||
abstract class MetaNode<M: MetaNode<M>>: Meta{
|
||||
abstract class MetaNode<M : MetaNode<M>> : Meta {
|
||||
abstract override val items: Map<String, MetaItem<M>>
|
||||
|
||||
operator fun get(name: Name): MetaItem<M>? {
|
||||
return when (name.length) {
|
||||
0 -> error("Can't resolve element from empty name")
|
||||
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)
|
||||
|
||||
object EmptyMeta : Meta {
|
||||
override val items: Map<String, MetaItem<out Meta>> = emptyMap()
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic meta-holder object
|
||||
*/
|
||||
interface Metoid{
|
||||
interface Metoid {
|
||||
val meta: Meta
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
package hep.dataforge.meta
|
||||
|
||||
import hep.dataforge.names.Name
|
||||
|
||||
/**
|
||||
* DSL builder for meta. Is not intended to store mutable state
|
||||
*/
|
||||
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()
|
||||
|
||||
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 {
|
||||
override val items: Map<String, 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
|
||||
*/
|
||||
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))
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all listeners belonging to given owner
|
||||
*/
|
||||
fun removeListener(owner: Any) {
|
||||
override fun removeListener(owner: Any) {
|
||||
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
|
||||
* @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
|
||||
*/
|
||||
protected abstract fun empty(): M
|
||||
abstract fun empty(): M
|
||||
|
||||
override operator fun set(name: Name, item: MetaItem<M>?) {
|
||||
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) }))
|
||||
}
|
||||
|
||||
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 set(name: String, meta: Meta) = set(name.toName(), MetaItem.SingleNodeItem(wrap(meta)))
|
||||
operator fun set(name: String, metas: List<Meta>) = set(name.toName(), 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 <M : MutableMeta<M>> M.set(name: Name, value: Value) = set(name, MetaItem.ValueItem(value))
|
||||
operator fun <M : MutableMetaNode<M>> M.set(name: Name, meta: Meta) = set(name, MetaItem.SingleNodeItem(wrap(name, meta)))
|
||||
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