Styleable and updates to Configuration

This commit is contained in:
Alexander Nozik 2018-09-17 16:11:33 +03:00
parent 9395b6fa5f
commit 8829795a12
7 changed files with 113 additions and 34 deletions

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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) {

View File

@ -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))
}
}

View 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
}