
com.dukescript.api.kt.impl.HtmlJava.kt Maven / Gradle / Ivy
package com.dukescript.api.kt.impl
import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
import com.dukescript.api.kt.Model
import net.java.html.BrwsrCtx
import net.java.html.json.Models
import org.netbeans.html.json.spi.Proto
internal fun impl(thiz : Model): ModelImpl {
return thiz as ModelImpl
}
internal object Token {
}
internal final class ModelImpl constructor(private val javaObj: Any) : Model(Token) {
internal val values: MutableList = mutableListOf();
/*-
* #%L
* %%
* Copyright (C) 2017 Dukehoff GmbH
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
private val computed: MutableList<(() -> Any?)?> = mutableListOf()
private val fns: MutableList<((Any?) -> Unit)?> = mutableListOf()
internal val proto: Proto by lazy {
val context = BrwsrCtx.findDefault(javaObj::class.java)
type.type.createProto(javaObj, context)
}
internal val type: ProtoType by lazy {
val p = ProtoType.allModels[javaObj::class]
p!!
}
internal fun addComputedProp(index: Int, fn: (() -> Any?)?, value: Any?) {
while (computed.size <= index) {
computed.add(null)
}
computed[index] = fn;
while (values.size <= index) {
values.add(null)
}
values[index] = value
}
internal fun addFn(index: Int, fn: ((Any?) -> Unit)?) {
while (fns.size <= index) {
fns.add(null)
}
fns[index] = fn;
}
internal fun getValue(prop: KProperty<*>): Any? {
val index = type.props.indexOf(prop)
return getValue(index)
}
internal fun getValue(index: Int): Any? {
val name = type.props[index].name
val fn = computed[index]
val p = proto
if (fn != null) {
try {
p.acquireLock(name)
return fn()
} finally {
p.releaseLock()
}
}
while (values.size <= index) {
values.add(null)
}
p.accessProperty(name)
return values[index];
}
internal fun setValue(p: KProperty<*>, value: Any?) {
val index = type.props.indexOf(p)
setValue(index, value)
}
internal fun setValue(index: Int, value: Any?) {
val old = values[index]
values[index] = value
val name = type.props[index].name
proto.valueHasMutated(name, old, value)
val on = type.onChange[index]
if (on != null) {
on()
}
}
internal fun invoke(index: Int, data: Any?, event: Any?) {
val fn = fns[index]
if (fn != null) {
fn(data)
}
}
internal fun extractValue(clazz: Class, value: Any?): T? {
val obj = if (Models.isModel(clazz)) {
proto.toModel(clazz, value)
} else {
value
}
return type.extractValue(clazz, obj)
}
internal fun valueHasMutated(index: Int) {
proto.valueHasMutated(type.props[index].name, null, values[index])
val on = type.onChange[index]
if (on != null) {
on()
}
}
}
internal class ProtoType constructor(val clazz: Class) {
companion object {
public val allModels: MutableMap = mutableMapOf()
public fun registerPrototype(owner: Model.Provider): ProtoType {
val m: ProtoType? = allModels[owner::class]
if (m == null) {
val r = ProtoType(owner::class.java)
allModels[owner::class] = r
return r
} else {
return m
}
}
}
val props: MutableList> = mutableListOf()
val types: MutableList?> = mutableListOf()
val array: MutableList = mutableListOf()
val fns: MutableList> = mutableListOf()
val onChange: MutableList<(()->Unit)?> = mutableListOf()
val type: Html4JavaType by lazy {
Html4JavaType(this, clazz, props, fns)
}
init {
Html4JavaType(this, clazz, mutableListOf(), mutableListOf())
}
fun extractValue(clazz: Class, value: Any?): T? {
return type.extractValue(clazz, value)
}
fun addProp(
objs: Model, isA: Boolean,
type : Class<*>?, p: KProperty<*>,
fn: (() -> Any?)? = null,
init: Any? = null,
change: (() -> Unit)? = null
): Int {
var index = props.indexOf(p)
if (index == -1) {
props.add(p)
types.add(type)
array.add(isA)
onChange.add(change)
index = props.lastIndex
} else {
types[index] = type
array[index] = isA
onChange[index] = change;
}
impl(objs).addComputedProp(index, fn, init)
return index
}
fun addFn(objs: Model, p: KProperty<*>, fn: ((Any?) -> Unit)?): Int {
var index = fns.indexOf(p)
if (index == -1) {
fns.add(p)
index = fns.lastIndex
}
impl(objs).addFn(index, fn);
return index
}
}
internal class Html4JavaType : Proto.Type {
val kType: ProtoType
constructor (
kotlinType: ProtoType,
type: Class,
props: List>,
fns: List>
) : super(type, type, props.size, fns.size) {
kType = kotlinType
var cnt = 0
for (p in props) {
registerProperty(p.name, cnt++, false)
}
cnt = 0;
for (f in fns) {
registerFunction(f.name, cnt++)
}
}
override fun cloneTo(model: Model.Provider?, ctx: BrwsrCtx?): Model.Provider? {
throw UnsupportedOperationException()
}
override fun protoFor(obj: Any?): Proto? {
if (obj is Model.Provider) {
val m: Model.Provider = obj
return impl(m.objs).proto
}
return null;
}
override fun call(model: Model.Provider, index: Int, data: Any?, event: Any?) {
impl(model.objs).invoke(index, data, event)
}
public override fun getValue(model: Model.Provider, index: Int): Any? {
return impl(model.objs).getValue(index)
}
override fun onChange(model: Model.Provider, index: Int) {
impl(model.objs).valueHasMutated(index)
}
public override fun setValue(model: Model.Provider, index: Int, value: Any?) {
return impl(model.objs).setValue(index, value)
}
override fun read(c: BrwsrCtx?, json: Any?): Model.Provider? {
val data = this.kType.clazz.newInstance() as Model.Provider
val propertySize = this.kType.props.size
val names : Array = Array(propertySize, { i ->
kType.props[i].name
})
val tmp : Array = arrayOfNulls(propertySize)
val proto = impl(data.objs).proto
proto.extract(json, names, tmp)
val values = impl(data.objs).values
for (index in 0 .. propertySize - 1) {
val type = this.kType.types[index]
if (type != null) {
if (this.kType.array[index]) {
val list = if (values[index] == null) {
val l : MutableList = proto.createList(names[index], index)
values[index] = l
l
} else {
val l = values[index] as MutableList
l.clear()
l
}
if (tmp[index] != null) {
val arr = tmp[index] as Array<*>
for (elem in arr) {
val v = extractData(proto, type, elem)
list.add(v)
}
}
} else {
values[index] = extractData(proto, type, tmp[index])
}
}
}
return data
}
private fun extractData(proto: Proto, type: Class<*>, elem: Any?): Any? {
return if (Models.isModel(type)) {
proto.read(type, elem)
} else {
extractValue(type, elem)
}
}
override fun onMessage(model: Model.Provider, index: Int, type: Int, data: Any?, params: Array) {
val clazz: Class<*> = params[0] as Class<*>
val onSuccess: (Any) -> Unit = params[1] as (Any) -> Unit
deliverMessage(clazz, model, index, type, data as Array, onSuccess)
}
private fun deliverMessage(clazz : Class, model: Model.Provider, index: Int, type: Int, data: Array, onSuccess: (List) -> Unit) {
val ctx = impl(model.objs).proto.context
val copy : Array = arrayOfNulls(data.size)
impl(model.objs).type.type.copyJSON(ctx, data, clazz, copy as Array)
val list : List = copy.toList()
onSuccess(list)
}
}
/**
* Activates providing model for given element.
* @param model the model to activate
* @param id optional id of element to activate the model at, if missing activate
* the model to the whole UI
*/
fun applyBindings(model : Model.Provider, id : String? = null) {
Models.applyBindings(model, id)
}
internal object ObservableP : ReadWriteProperty {
override fun getValue(thisRef: Model.Provider, property: KProperty<*>): Any? = impl(thisRef.objs).getValue(property)
override fun setValue(thisRef: Model.Provider, property: KProperty<*>, value: Any?): Unit = impl(thisRef.objs).setValue(property, value)
}
internal object ComputedP : ReadOnlyProperty {
override fun getValue(thisRef: Model.Provider, property: KProperty<*>): Any? = impl(thisRef.objs).getValue(property)
}
internal class ListP constructor (
private val js : Model,
private val name: String,
private val index: Int,
items : Array
): ReadOnlyProperty> {
val list : MutableList by lazy {
var list = if (impl(js).getValue(index) == null) {
val newList = impl(js).proto.createList(name, index)
impl(js).setValue(index, newList)
newList.addAll(items)
newList
} else {
impl(js).getValue(index) as MutableList
}
list
}
override fun getValue(thisRef: Model.Provider, property: KProperty<*>): MutableList {
impl(js).proto.accessProperty(name)
return list
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy