All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.itangcent.intellij.extend.rx.AutoComputer.kt Maven / Gradle / Ivy

Go to download

Help for developing plugins for JetBrains products. KotlinAnAction:provide ActionContext(support inject guice) for actionPerformed

The newest version!
package com.itangcent.intellij.extend.rx

import com.google.common.cache.Cache
import com.google.common.cache.CacheBuilder
import com.intellij.util.containers.Stack
import com.itangcent.common.utils.IDUtils
import com.itangcent.common.utils.changePropertyValue
import com.itangcent.common.utils.getPropertyValue
import com.itangcent.intellij.extend.rx.AutoComputerUtils.mergeFilter
import org.apache.commons.lang3.StringUtils
import java.awt.Component
import java.awt.EventQueue
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import javax.swing.*
import javax.swing.event.*
import javax.swing.text.JTextComponent
import kotlin.jvm.internal.CallableReference
import kotlin.reflect.*
import kotlin.reflect.jvm.isAccessible

class AutoComputer {

    private val throttleHelper: ThrottleHelper = ThrottleHelper()

    private val listeners = ConcurrentHashMap, () -> Unit>()

    private val passiveListeners = ConcurrentHashMap, () -> Unit>()

    private val wrapCache: Cache = CacheBuilder
        .newBuilder()
        .build()

    private var pool: (() -> Unit) -> Unit = { it() }

    private var mode = Mode.ALL

    fun mode(mode: Mode): AutoComputer {
        this.mode = mode
        return this
    }

    fun withMode(mode: Mode, action: () -> Unit): AutoComputer {
        val olderMode = this.mode
        this.mode = mode
        try {
            action()
        } finally {
            this.mode = olderMode
        }
        return this
    }

    /**
     * set value,and compute
     */
    fun  value(property: KMutableProperty0, value: T) {
        property.safeSet(value)
        val getter: AGetter = this.wrapGetter(property)
        call(getter)
    }

    /**
     * set value,and compute
     */
    @Suppress("UNCHECKED_CAST")
    fun  value(setter: ASetter, value: T?) {
        if (!mode.allowed(setter)) {
            return
        }
        setter.set(value)
        if (setter is AGetter<*>) {
            call(setter as AGetter)
        }
    }

    /**
     * set value,and compute
     */
    public fun  value(target: Any, property: String, value: T?) {
        value(wrapBeanProperty(target, property), value)
    }

    //region try compute---------------------------------------------------------------
    internal fun call(getter: AGetter) {
        if (!this.mode.allowed(getter)) {
            return
        }
        val action = listeners[getter as AGetter<*>]
        var doAction = false
        try {
            if (action != null) {
                doAction = pushAction(action)
                if (doAction) {
                    //入栈成功,可执行
                    val actionStack = actionThreadLocal.get()
                    val rootThread = Thread.currentThread()
                    pool {
                        if (Thread.currentThread() != rootThread) {
                            actionThreadLocal.set(actionStack)
                            try {
                                action()
                            } finally {
                                actionThreadLocal.remove()
                            }
                        } else {
                            action()
                        }
                    }
                }
                //如果入栈失败,说明此Action在本次响应中已执行,则不再循环执行
            }

            //call relative
            listeners.keys
                .filter { isRelative(it, getter) }
                .forEach { listeners[it]?.invoke() }

            //call relative,重新计算子节点
            passiveListeners.keys
                .filter { isSon(it, getter) }
                .forEach { passiveListeners[it]?.invoke() }
        } finally {
            if (doAction) {
                popAction()
            }
        }

    }

    private val actionThreadLocal: ThreadLocal Unit>> = ThreadLocal Unit>>()

    private fun pushAction(action: () -> Unit): Boolean {
        var actionStack = actionThreadLocal.get()
        return when {
            actionStack == null -> {
                actionStack = Stack(1)
                actionThreadLocal.set(actionStack)
                actionStack.push(action)
                true
            }

            actionStack.contains(action) -> false
            else -> {
                actionStack.push(action)
                true
            }
        }
    }

    private fun popAction() {
        val actionStack = actionThreadLocal.get()
        actionStack.pop()
        if (actionStack.isEmpty()) {
            actionThreadLocal.remove()
        }
    }
    //endregion try compute---------------------------------------------------------------

    private fun isRelative(getter: AGetter<*>, anotherGetter: AGetter<*>): Boolean {
        return when {
            getter == anotherGetter -> false
            getter !is HasProperty<*> -> false
            anotherGetter !is HasProperty<*> -> false
            getter.getProperty().target() != anotherGetter.getProperty().target() -> false
            getter.getProperty().name().startsWith(anotherGetter.getProperty().name() + ".") -> true
            anotherGetter.getProperty().name().startsWith(getter.getProperty().name() + ".") -> true
            else -> false
        }
    }

    /**
     * setter is son of getter
     */
    private fun isSon(setter: ASetter<*>, getter: AGetter<*>): Boolean {
        return when {
            setter == getter -> false
            setter !is HasProperty<*> -> false
            getter !is HasProperty<*> -> false
            setter.getProperty().target() != getter.getProperty().target() -> false
            setter.getProperty().name().startsWith(getter.getProperty().name() + ".") -> true
            else -> false
        }
    }

    fun  bind(property: KMutableProperty0): AutoBind0 {
        val wrapSetter = wrapSetter(property)
        return buildBind(this, wrapSetter)
    }

    fun bind(component: JTextComponent): AutoBind0 {
        val wrapSetter = wrapJTextComponent(component)
        return buildBind(this, wrapSetter)
    }

    fun bindText(component: AbstractButton): AutoBind0 {
        val wrapSetter = wrapJButtonTextComponent(component)
        return buildBind(this, wrapSetter)
    }

    fun bind(component: JCheckBox): AutoBind0 {
        val wrapSetter = wrapJCheckBoxComponentWrap(component)
        return buildBind(this, wrapSetter)
    }

    fun bind(component: JLabel): AutoBind0 {
        val wrapSetter = wrapJLabel(component)
        return buildBind(this, wrapSetter)
    }

    fun bindEnable(component: JComponent): AutoBind0 {
        val wrapSetter = wrapComponentEnable(component)
        return buildBind(this, wrapSetter)
    }

    fun bindVisible(component: JComponent): AutoBind0 {
        val wrapSetter = wrapComponentVisible(component)
        return buildBind(this, wrapSetter)
    }

    fun bindName(component: JComponent): AutoBind0 {
        val wrapSetter = wrapComponentName(component)
        return buildBind(this, wrapSetter)
    }

    fun bindIndex(component: JList<*>): AutoBind0 {
        val wrapSetter = wrapJListIndexComponent(component)
        return buildBind(this, wrapSetter)
    }

    fun bind(component: JList<*>): AutoBind0?> {
        val wrapSetter = wrapJListComponent(component)
        return buildBind(this, wrapSetter)
    }

    fun bindIndex(component: JComboBox<*>): AutoBind0 {
        val wrapSetter = wrapJComboBoxIndexComponent(component)
        return buildBind(this, wrapSetter)
    }

    fun  bind(component: JComboBox): AutoBind0 {
        val wrapSetter = wrapJComboBoxComponent(component)
        return buildBind(this, wrapSetter)
    }

    fun  bind(target: Any, property: String): AutoBind0 {
        val wrapSetter: ASetter = wrapBeanProperty(target, property)
        return buildBind(this, wrapSetter)
    }

    fun  bind(target: Any, property: String, type: KClass): AutoBind0 {
        val wrapSetter: ASetter = wrapBeanProperty(target, property)
        return buildBind(this, wrapSetter)
    }

    //region ***************listen***************-------------------------------

    fun  listen(property: KMutableProperty0): ListenAble {
        val wrapGetter = wrapGetter(property)
        return ListenAble(this, wrapGetter)
    }

    fun listen(component: JTextComponent): ListenAble {
        val wrapGetter = wrapJTextComponent(component)
        return ListenAble(this, wrapGetter)
    }

    fun listenText(component: AbstractButton): ListenAble {
        val wrapGetter = wrapJButtonTextComponent(component)
        return ListenAble(this, wrapGetter)
    }

    fun listen(component: JCheckBox): ListenAble {
        val wrapGetter = wrapJCheckBoxComponentWrap(component)
        return ListenAble(this, wrapGetter)
    }

    fun listen(component: JLabel): ListenAble {
        val wrapGetter = wrapJLabel(component)
        return ListenAble(this, wrapGetter)
    }

    fun listenEnable(component: JComponent): ListenAble {
        val wrapGetter = wrapComponentEnable(component)
        return ListenAble(this, wrapGetter)
    }

    fun listenVisible(component: JComponent): ListenAble {
        val wrapGetter = wrapComponentVisible(component)
        return ListenAble(this, wrapGetter)
    }

    fun listenName(component: JComponent): ListenAble {
        val wrapGetter = wrapComponentName(component)
        return ListenAble(this, wrapGetter)
    }

    fun listenIndex(component: JList<*>): ListenAble {
        val wrapGetter = wrapJListIndexComponent(component)
        return ListenAble(this, wrapGetter)
    }

    fun listen(component: JList<*>): ListenAble> {
        val wrapGetter = wrapJListComponent(component)
        return ListenAble(this, wrapGetter)
    }

    fun listenIndex(component: JComboBox<*>): ListenAble {
        val wrapGetter = wrapJComboBoxIndexComponent(component)
        return ListenAble(this, wrapGetter)
    }

    fun  listen(component: JComboBox): ListenAble {
        val wrapGetter = wrapJComboBoxComponent(component)
        return ListenAble(this, wrapGetter)
    }

    fun  listen(target: Any, property: String): ListenAble {
        val wrapGetter: AGetter = wrapBeanProperty(target, property)
        return ListenAble(this, wrapGetter)
    }

    fun  listen(
        target: Any,
        property: String,
        type: KClass
    ): ListenAble {
        val wrapGetter: AGetter = wrapBeanProperty(target, property)
        return ListenAble(this, wrapGetter)
    }

    @Suppress("UNCHECKED_CAST")
    internal fun  singleListen(
        wrapGetter: AGetter,
        action: (T?) -> Unit
    ) {
        addListeners({
            action(wrapGetter.get())
        }, wrapGetter as AGetter)
    }

    //endregion ***************listen***************-------------------------------

    @Suppress("UNCHECKED_CAST")
    private fun  wrapSetter(property: KMutableProperty0): ASetter {
        return wrapCache.get(property) {
            KMutableProperty0Wrap(property, parseProperty(property))
        } as ASetter
    }

    private fun wrapComponentEnable(component: Component): ComponentEnableWrap {
        return wrapCache.get(component to "enable") {
            ComponentEnableWrap(component)
        } as ComponentEnableWrap
    }

    private fun wrapComponentVisible(component: Component): ComponentVisibleWrap {
        return wrapCache.get(component to "visible") {
            ComponentVisibleWrap(component)
        } as ComponentVisibleWrap
    }

    private fun wrapComponentName(component: Component): ComponentNameWrap {
        return wrapCache.get(component to "name") {
            ComponentNameWrap(component)
        } as ComponentNameWrap
    }

    internal fun wrapJTextComponent(component: JTextComponent): JTextComponentWrap {
        return wrapCache.get(component) {
            JTextComponentWrap(component)
        } as JTextComponentWrap
    }

    internal fun wrapJButtonTextComponent(component: AbstractButton): JButtonTextComponentWrap {
        return wrapCache.get(component) {
            JButtonTextComponentWrap(component)
        } as JButtonTextComponentWrap
    }

    internal fun wrapJCheckBoxComponentWrap(component: JCheckBox): JCheckBoxComponentWrap {
        return wrapCache.get(component) {
            JCheckBoxComponentWrap(component)
        } as JCheckBoxComponentWrap
    }

    internal fun wrapJLabel(component: JLabel): JLabelWrap {
        return wrapCache.get(component) {
            JLabelWrap(component)
        } as JLabelWrap
    }

    internal fun wrapJListIndexComponent(component: JList<*>): JListComponentIndexWrap {
        return wrapCache.get(component to "index") {
            JListComponentIndexWrap(component)
        } as JListComponentIndexWrap
    }

    internal fun wrapJListComponent(component: JList<*>): JListComponentWrap {
        return wrapCache.get(component) {
            JListComponentWrap(component)
        } as JListComponentWrap
    }

    internal fun wrapJComboBoxIndexComponent(component: JComboBox<*>): JComboBoxComponentIndexWrap {
        return wrapCache.get(component to "index") {
            JComboBoxComponentIndexWrap(component)
        } as JComboBoxComponentIndexWrap
    }

    @Suppress("UNCHECKED_CAST")
    internal fun  wrapJComboBoxComponent(component: JComboBox): JComboBoxComponentWrap {
        return wrapCache.get(component) {
            JComboBoxComponentWrap(component)
        } as JComboBoxComponentWrap
    }

    @Suppress("UNCHECKED_CAST")
    internal fun  wrapBeanProperty(target: Any, property: String): BeanPropertyWrap {
        return wrapCache.get(Pair(target, property)) {
            val tinyProperty = StringUtils.removeStart(property, "this.")
            val lastDot = StringUtils.lastIndexOf(tinyProperty, ".")
            val targetExp = StringUtils.substring(tinyProperty, 0, lastDot)
            val propertyExp = StringUtils.substring(tinyProperty, lastDot + 1)

            val targetGetter: () -> Any?
            when {
                //空,直接取target
                StringUtils.isBlank(targetExp) -> targetGetter = { target }
                //一级,直接读属性
                targetExp.indexOf('.') == -1 -> targetGetter = { target.getPropertyValue(targetExp) }
                //多级,多次读属性,有一级为空,即返回null
                else -> {
                    val properties = targetExp.split('.')
                    targetGetter = {
                        var result: Any? = null
                        for (p in properties) {
                            result = target.getPropertyValue(p)
                            if (result == null)
                                break
                        }
                        result
                    }
                }
            }

            val propertySetter: (Any, T?) -> Unit = { any: Any, t: T? -> any.changePropertyValue(propertyExp, t) }

            val propertyGetter: ((Any) -> T?) = { any -> any.getPropertyValue(propertyExp) as T? }

            BeanPropertyWrap(targetGetter, propertySetter, propertyGetter, BeanProperty(target, tinyProperty))
        } as BeanPropertyWrap
    }

    @Suppress("UNCHECKED_CAST")
    internal fun  wrapGetter(property: KProperty0): AGetter {
        return if (property is KMutableProperty0) {
            wrapCache.get(property) {
                KMutableProperty0Wrap(property, parseProperty(property))
            } as AGetter
        } else {
            wrapCache.get(property) {
                KProperty0Wrap(property, parseProperty(property))
            } as AGetter
        }
    }

    private fun parseProperty(property: KProperty0<*>): AProperty {
        return when (property) {
            is CallableReference -> BeanProperty(property.boundReceiver, property.name)
            else -> BeanProperty(null, property.name)
        }
    }

    private fun addListeners(exp: () -> Unit, vararg properties: AGetter) {
        for (property in properties) {
            mergeListeners(exp, property)
        }
    }

    private fun addListeners(exp: () -> Unit, properties: List>) {
        for (property in properties) {
            mergeListeners(exp, property)
        }
    }

    private fun mergeListeners(exp: () -> Unit, property: AGetter) {
        val old = listeners[property]
        if (old == null) {
            property.onListen(this)
            listeners[property] = exp
        } else {
            listeners[property] = {
                old()
                exp()
            }
        }
    }

    private fun addPassiveListeners(property: ASetter, exp: () -> Unit) {
        val old = passiveListeners[property]
        if (old == null) {
            passiveListeners[property] = exp
        } else {
            passiveListeners[property] = {
                old()
                exp()
            }
        }
//        val put = passiveListeners.put(property, exp)
//        Assert.assertNull("a property should not bind twice!", put)
    }

    fun listenOn(pool: (() -> Unit) -> Unit): AutoComputer {
        this.pool = pool
        return this
    }

    class AutoBindData {

        var computer: AutoComputer

        var filter: (Filter)? = null

        var property: ASetter

        var params: MutableList>

        var linkedParams: MutableList>? = null

        constructor(computer: AutoComputer, property: ASetter, params: MutableList>) {
            this.computer = computer
            this.property = property
            this.params = params
        }
    }

    abstract class AutoBind {

        protected var core: AutoBindData

        constructor(core: AutoBindData) {
            this.core = core
        }

        @Suppress("UNCHECKED_CAST")
        fun link(param: KProperty0): C {
            val getter: AGetter = core.computer.wrapGetter(param)
            if (core.linkedParams == null) {
                core.linkedParams = ArrayList()
                core.linkedParams!!.add(getter)
            }
            return this as C
        }

        @Suppress("UNCHECKED_CAST")
        open fun eval(exp: E) {
//            val evalFun: () -> Unit = { pool { evalFun(exp) } }
            var evalFun: () -> Unit = evalFun(exp)
            val wrapPool = pool
            if (wrapPool != null) {
                val wrapFun = evalFun
                evalFun = { wrapPool(wrapFun) }
            }
            val wrapFilter = core.filter
            if (wrapFilter != null) {
                val wrapFun = evalFun
                evalFun = {
                    if (wrapFilter()) {
                        wrapFun()
                    }
                }
            }

            core.computer.addPassiveListeners(core.property as ASetter, evalFun)
            core.computer.addListeners(evalFun, core.params)
            if (core.linkedParams != null) {
                for (kProperty in (core.linkedParams as List>)) {
                    core.computer.addListeners(evalFun, kProperty)
                }
            }
        }

        fun throttle(cd: Long): C {
            return throttle(core.property, cd)
        }

        fun throttle(specialKey: Any, cd: Long): C {
            val throttleFilter = { computer().throttleHelper.acquire(specialKey, cd) }
            return filter(throttleFilter)
        }

        @Suppress("UNCHECKED_CAST")
        fun filter(newFilter: Filter): C {
            val filter = this.core.filter
            if (filter == null) {
                this.core.filter = newFilter
            } else {
                this.core.filter = {
                    filter() && newFilter()
                }
            }
            return this as C
        }

        private var pool: ((() -> Unit) -> Unit)? = null

        @Suppress("UNCHECKED_CAST")
        fun listenOn(pool: (() -> Unit) -> Unit): C {
            this.pool = pool
            return this as C
        }

        protected fun computer(): AutoComputer {
            return core.computer
        }

        protected abstract fun evalFun(exp: E): () -> Unit
    }

    class AutoBind0 : AutoBind T, AutoBind0> {
        constructor(core: AutoBindData) : super(core)

        @Suppress("UNCHECKED_CAST")
        fun 

with(param: KProperty0

): AutoBind1 { val wrapGetter: AGetter

= computer().wrapGetter(param) as AGetter

return withGetter(wrapGetter) } @Suppress("UNCHECKED_CAST") fun

with(target: Any, property: String): AutoBind1 { val wrapGetter: AGetter

= computer().wrapBeanProperty

(target, property) as AGetter

return withGetter(wrapGetter) } fun

with(target: Any, property: String, type: KClass

): AutoBind1 { return with(target, property) } @Suppress("UNCHECKED_CAST") fun with(param: JTextComponent): AutoBind1 { val wrapGetter: AGetter = computer().wrapJTextComponent(param) return withGetter(wrapGetter) } @Suppress("UNCHECKED_CAST") fun with(param: JLabel): AutoBind1 { val wrapGetter: AGetter = computer().wrapJLabel(param) return withGetter(wrapGetter) } @Suppress("UNCHECKED_CAST") fun withIndex(param: JList<*>): AutoBind1 { val wrapGetter: AGetter = computer().wrapJListIndexComponent(param) return withGetter(wrapGetter) } fun withEnable(component: JComponent): AutoBind1 { val wrapGetter: AGetter = computer().wrapComponentEnable(component) return withGetter(wrapGetter) } fun withVisible(component: JComponent): AutoBind1 { val wrapGetter: AGetter = computer().wrapComponentVisible(component) return withGetter(wrapGetter) } fun withName(component: JComponent): AutoBind1 { val wrapGetter: AGetter = computer().wrapComponentName(component) return withGetter(wrapGetter) } fun with(component: JList<*>): AutoBind1?> { val wrapGetter: AGetter?> = computer().wrapJListComponent(component) return withGetter(wrapGetter) } fun withIndex(component: JComboBox<*>): AutoBind1 { val wrapGetter: AGetter = computer().wrapJComboBoxIndexComponent(component) return withGetter(wrapGetter) } fun

with(component: JComboBox

): AutoBind1 { val wrapGetter: AGetter = computer().wrapJComboBoxComponent(component) return withGetter(wrapGetter) } @Suppress("UNCHECKED_CAST") fun

withGetter(getter: AGetter

): AutoBind1 { this.core.params.add(getter as AGetter) return AutoBind1(core) } internal fun peakCore(): AutoBindData { return core } override fun evalFun(exp: () -> T): () -> Unit { return { computer().value(core.property, exp()) } } } @Suppress("UNCHECKED_CAST") class AutoBind1 : AutoBind T, AutoBind1> { constructor(core: AutoBindData) : super(core) @Suppress("UNCHECKED_CAST") fun with(param: KProperty0): AutoBind2 { val wrapGetter: AGetter = computer().wrapGetter(param) as AGetter return withGetter(wrapGetter) } @Suppress("UNCHECKED_CAST") fun with(target: Any, property: String): AutoBind2 { val wrapGetter: AGetter = computer().wrapBeanProperty(target, property) as AGetter return withGetter(wrapGetter) } fun with(target: Any, property: String, type: KClass): AutoBind2 { return with(target, property) } @Suppress("UNCHECKED_CAST") fun with(param: JTextComponent): AutoBind2 { val wrapGetter: AGetter = computer().wrapJTextComponent(param) return withGetter(wrapGetter) } @Suppress("UNCHECKED_CAST") fun with(param: JLabel): AutoBind2 { val wrapGetter: AGetter = computer().wrapJLabel(param) return withGetter(wrapGetter) } @Suppress("UNCHECKED_CAST") fun withIndex(param: JList<*>): AutoBind2 { val wrapGetter: AGetter = computer().wrapJListIndexComponent(param) return withGetter(wrapGetter) } fun withEnable(component: JComponent): AutoBind2 { val wrapGetter: AGetter = computer().wrapComponentEnable(component) return withGetter(wrapGetter) } fun withVisible(component: JComponent): AutoBind2 { val wrapGetter: AGetter = computer().wrapComponentVisible(component) return withGetter(wrapGetter) } fun withName(component: JComponent): AutoBind2 { val wrapGetter: AGetter = computer().wrapComponentName(component) return withGetter(wrapGetter) } fun with(component: JList<*>): AutoBind2?> { val wrapGetter: AGetter?> = computer().wrapJListComponent(component) return withGetter(wrapGetter) } fun withIndex(component: JComboBox<*>): AutoBind2 { val wrapGetter: AGetter = computer().wrapJComboBoxIndexComponent(component) return withGetter(wrapGetter) } fun with(component: JComboBox): AutoBind2 { val wrapGetter: AGetter = computer().wrapJComboBoxComponent(component) return withGetter(wrapGetter) } @Suppress("UNCHECKED_CAST") fun withGetter(getter: AGetter): AutoBind2 { this.core.params.add(getter as AGetter) return AutoBind2(core) } override fun evalFun(exp: (P1) -> T): () -> Unit { return { computer().value(core.property, exp(core.params[0].get() as P1)) } } } class AutoBind2 : AutoBind T?, AutoBind2> { constructor(core: AutoBindData) : super(core) @Suppress("UNCHECKED_CAST") fun

with(param: KProperty0

): AutoBind3 { val wrapGetter: AGetter = computer().wrapGetter(param) as AGetter this.core.params.add(wrapGetter) return AutoBind3(core) } @Suppress("UNCHECKED_CAST") fun

with(target: Any, property: String): AutoBind3 { val wrapGetter: AGetter = computer().wrapBeanProperty

(target, property) as AGetter this.core.params.add(wrapGetter) return AutoBind3(core) } fun

with(target: Any, property: String, type: KClass

): AutoBind3 { return with(target, property) } @Suppress("UNCHECKED_CAST") fun with(param: JTextComponent): AutoBind3 { val wrapGetter: AGetter = computer().wrapJTextComponent(param) this.core.params.add(wrapGetter as AGetter) return AutoBind3(core) } @Suppress("UNCHECKED_CAST") fun with(param: JLabel): AutoBind3 { val wrapGetter: AGetter = computer().wrapJLabel(param) this.core.params.add(wrapGetter as AGetter) return AutoBind3(core) } @Suppress("UNCHECKED_CAST") fun withIndex(param: JList): AutoBind3 { val wrapGetter: AGetter = computer().wrapJListIndexComponent(param) return withGetter(wrapGetter) } fun withEnable(component: JComponent): AutoBind3 { val wrapGetter: AGetter = computer().wrapComponentEnable(component) return withGetter(wrapGetter) } fun withVisible(component: JComponent): AutoBind3 { val wrapGetter: AGetter = computer().wrapComponentVisible(component) return withGetter(wrapGetter) } fun withName(component: JComponent): AutoBind3 { val wrapGetter: AGetter = computer().wrapComponentName(component) return withGetter(wrapGetter) } fun with(component: JList<*>): AutoBind3?> { val wrapGetter: AGetter?> = computer().wrapJListComponent(component) return withGetter(wrapGetter) } fun withIndex(component: JComboBox<*>): AutoBind3 { val wrapGetter: AGetter = computer().wrapJComboBoxIndexComponent(component) return withGetter(wrapGetter) } fun with(component: JComboBox): AutoBind3 { val wrapGetter: AGetter = computer().wrapJComboBoxComponent(component) return withGetter(wrapGetter) } @Suppress("UNCHECKED_CAST") private fun withGetter(wrapGetter: AGetter): AutoBind3 { this.core.params.add(wrapGetter as AGetter) return AutoBind3(core) } @Suppress("UNCHECKED_CAST") override fun evalFun(exp: (P1?, P2?) -> T?): () -> Unit { return { computer().value( core.property, exp(this.core.params[0].get() as P1, this.core.params[1].get() as P2) ) } } } class AutoBind3(core: AutoBindData) : AutoBind T?, AutoBind3>(core) { @Suppress("UNCHECKED_CAST") override fun evalFun(exp: (P1?, P2?, P3?) -> T?): () -> Unit { return { computer().value( core.property, exp( this.core.params[0].get() as P1, this.core.params[1].get() as P2, this.core.params[2].get() as P3 ) ) } } } class ListenAble { private val computer: AutoComputer private val wrapGetter: AGetter private var filter: (Filter)? = null constructor(computer: AutoComputer, wrapGetter: AGetter) { this.wrapGetter = wrapGetter this.computer = computer } fun throttle(cd: Long): ListenAble { return throttle(wrapGetter to IDUtils.shortUUID(), cd) } fun throttle(specialKey: Any, cd: Long): ListenAble { val throttleFilter = { computer.throttleHelper.acquire(specialKey, cd) } mergeFilter(this::filter, throttleFilter) return this } fun filter(filter: Filter): ListenAble { mergeFilter(this::filter, filter) return this } fun action(action: (T?) -> Unit) { var buildAction = action if (this.filter != null) { val wrapAction = buildAction val filter = this.filter!! buildAction = { if (filter()) { wrapAction(it) } } } this.computer.singleListen(wrapGetter, buildAction) } } companion object { fun buildBind(computer: AutoComputer, property: ASetter): AutoBind0 { val data: AutoBindData = AutoBindData(computer, property, ArrayList()) return AutoBind0(data) } } } fun KMutableProperty.safeSet(value: T?) { if (!this.isAccessible) { this.isAccessible = true } this.setter.call(value) } fun KProperty.safeGet(): T? { if (!this.isAccessible) { this.isAccessible = true } return this.getter.call() } fun KProperty.safeGet(target: Any): T? { if (!this.isAccessible) { this.isAccessible = true } return this.getter.call(target) } //region define interface------------------------------------------------------- enum class Mode { REPAINT_UI_ONLY { /** * allow change from data */ override fun allowed(getter: AGetter<*>): Boolean { return getter is DataListener } /** * allow setter of ui */ override fun allowed(setter: ASetter<*>): Boolean { return setter is UIListener } }, UPDATE_DATA_ONLY { /** * allow change from ui */ override fun allowed(getter: AGetter<*>): Boolean { return getter is UIListener } /** * allow setter of data */ override fun allowed(setter: ASetter<*>): Boolean { return setter is DataListener } }, ALL { override fun allowed(getter: AGetter<*>): Boolean { return true } override fun allowed(setter: ASetter<*>): Boolean { return true } }; abstract fun allowed(getter: AGetter<*>): Boolean abstract fun allowed(setter: ASetter<*>): Boolean } interface ASetter { fun set(value: T?) } interface AGetter { fun get(): T? fun onListen(computer: AutoComputer) { } } interface AProperty { fun target(): Any? fun name(): String } interface HasProperty { fun getProperty(): AProperty } class BeanProperty : AProperty { private var target: Any? = null private var name: String? = null constructor() constructor(target: Any?, name: String?) { this.target = target this.name = name } override fun target(): Any { return target!! } override fun name(): String { return name!! } override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as BeanProperty if (target != other.target) return false if (name != other.name) return false return true } override fun hashCode(): Int { var result = target?.hashCode() ?: 0 result = 31 * result + (name?.hashCode() ?: 0) return result } override fun toString(): String { return "BeanProperty(target=$target, name=$name)" } } private interface UIListener private interface DataListener //endregion define interface------------------------------------------------------- //region wraps------------------------------------------------------------------ class KMutableProperty0Wrap : ASetter, AGetter, HasProperty, DataListener { private val actualProperty: KMutableProperty0 private val aProperty: AProperty constructor(property: KMutableProperty0, aProperty: AProperty) { this.actualProperty = property this.aProperty = aProperty } override fun set(value: T?) { this.actualProperty.safeSet(value) } override fun get(): T? { return this.actualProperty.safeGet() } override fun getProperty(): AProperty { return this.aProperty } override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is HasProperty<*>) return false if (aProperty != other.getProperty()) return false return true } override fun hashCode(): Int { return aProperty.hashCode() } override fun toString(): String { return "KMutableProperty0Wrap(aProperty=$aProperty)" } } class KProperty0Wrap : AGetter, HasProperty, DataListener { private val actualProperty: KProperty0 private val aProperty: AProperty constructor(property: KProperty0, aProperty: AProperty) { this.actualProperty = property this.aProperty = aProperty } override fun get(): T? { return this.actualProperty.safeGet() } override fun getProperty(): AProperty { return this.aProperty } override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is HasProperty<*>) return false if (aProperty != other.getProperty()) return false return true } override fun hashCode(): Int { return aProperty.hashCode() } } class JTextComponentWrap : ASetter, AGetter, UIListener { private val component: JTextComponent constructor(component: JTextComponent) { this.component = component } @Volatile private var cache: String? = null @Volatile private var manual: Boolean = false override fun set(value: String?) { cache = value EventQueue.invokeLater { if (this.component.text != value) { manual = true try { this.component.text = value } finally { manual = false } } } } override fun get(): String? { return when { cache != null -> cache else -> this.component.text } } override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as JTextComponentWrap if (component != other.component) return false return true } override fun hashCode(): Int { return component.hashCode() } private var hasListen = false override fun onListen(computer: AutoComputer) { listenChange(computer) } @Suppress("UNCHECKED_CAST") private fun listenChange(computer: AutoComputer) { if (!hasListen) { val jTextComponentWrap: AGetter = this as AGetter component.document.addDocumentListener(object : DocumentListener { override fun insertUpdate(e: DocumentEvent) { if (manual) { return } cache = null computer.call(jTextComponentWrap) } override fun removeUpdate(e: DocumentEvent) { if (manual) { return } cache = null computer.call(jTextComponentWrap) } override fun changedUpdate(e: DocumentEvent) { cache = null computer.call(jTextComponentWrap) } }) hasListen = true } } } class JButtonTextComponentWrap : ASetter, AGetter, UIListener { val component: AbstractButton constructor(component: AbstractButton) { this.component = component } @Volatile private var cache: String? = null @Volatile private var manual: Boolean = false override fun set(value: String?) { cache = value EventQueue.invokeLater { if (this.component.text != value) { manual = true try { this.component.text = value } finally { manual = false } } } } override fun get(): String? { return when { cache != null -> cache else -> this.component.text } } override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as JButtonTextComponentWrap if (component != other.component) return false return true } override fun hashCode(): Int { return component.hashCode() } private var hasListen = false override fun onListen(computer: AutoComputer) { listenChange(computer) } @Suppress("UNCHECKED_CAST") private fun listenChange(computer: AutoComputer) { if (!hasListen) { val jTextComponentWrap: AGetter = this as AGetter component.addChangeListener(ChangeListener { if (manual) { return@ChangeListener } cache = null computer.call(jTextComponentWrap) }) hasListen = true } } } class JCheckBoxComponentWrap : ASetter, AGetter, UIListener { private val component: JCheckBox constructor(component: JCheckBox) { this.component = component } @Volatile private var cache: Boolean? = null @Volatile private var manual: Boolean = false override fun set(value: Boolean?) { cache = value EventQueue.invokeLater { val selected = value ?: false if (this.component.isSelected != selected) { manual = true try { this.component.isSelected = selected } finally { manual = false } } } } override fun get(): Boolean? { return when { cache != null -> cache else -> this.component.isSelected } } override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as JCheckBoxComponentWrap if (component != other.component) return false return true } override fun hashCode(): Int { return component.hashCode() } private var hasListen = false override fun onListen(computer: AutoComputer) { listenChange(computer) } @Suppress("UNCHECKED_CAST") private fun listenChange(computer: AutoComputer) { if (!hasListen) { val jCheckBoxComponentWrap: AGetter = this as AGetter component.addActionListener { if (manual) { return@addActionListener } cache = null computer.call(jCheckBoxComponentWrap) } hasListen = true } } } class JLabelWrap : ASetter, AGetter, UIListener { private val component: JLabel constructor(component: JLabel) { this.component = component } @Volatile private var cache: String? = null @Volatile private var manual: Boolean = false override fun set(value: String?) { cache = value EventQueue.invokeLater { if (this.component.text != value) { manual = true try { this.component.text = value } finally { manual = false } } } } override fun get(): String? { return when { cache != null -> cache else -> this.component.text } } override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as JLabelWrap if (component != other.component) return false return true } override fun hashCode(): Int { return component.hashCode() } } abstract class NoListenComponentWrap : ASetter, AGetter, UIListener { private val component: Component constructor(component: Component) { this.component = component } override fun set(value: T?) { if (value != null) { EventQueue.invokeLater { if (get() != value) { set(this.component, value) } } } } abstract fun set(component: Component, value: T?) override fun get(): T? { return get(this.component) } abstract fun get(component: Component): T? override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as NoListenComponentWrap<*> if (component != other.component) return false return true } abstract fun magicHashCode(): Int override fun hashCode(): Int { return magicHashCode() xor component.hashCode() } } class ComponentEnableWrap(component: Component) : NoListenComponentWrap(component) { override fun set(component: Component, value: Boolean?) { value?.let { component.isEnabled = it } } override fun get(component: Component): Boolean? { return component.isEnabled } override fun magicHashCode(): Int { return "enable".hashCode() } } class ComponentVisibleWrap(component: Component) : NoListenComponentWrap(component) { override fun set(component: Component, value: Boolean?) { value?.let { component.isVisible = it } } override fun get(component: Component): Boolean? { return component.isVisible } override fun magicHashCode(): Int { return "visible".hashCode() } } class ComponentNameWrap(component: Component) : NoListenComponentWrap(component) { override fun set(component: Component, value: String?) { value?.let { component.name = it } } override fun get(component: Component): String? { return component.name } override fun magicHashCode(): Int { return "name".hashCode() } } class JListComponentIndexWrap : ASetter, AGetter, UIListener { private val component: JList<*> constructor(component: JList<*>) { this.component = component } @Volatile private var cache: Int? = null @Volatile private var manual: Boolean = false override fun set(value: Int?) { if (value != null) { cache = value EventQueue.invokeLater { if (this.component.selectedIndex != value) { manual = true try { this.component.selectedIndex = value } finally { manual = false } } } } } override fun get(): Int? { return when { cache != null -> cache else -> this.component.selectedIndex } } private var hasListen = false override fun onListen(computer: AutoComputer) { listenChange(computer) } @Suppress("UNCHECKED_CAST") private fun listenChange(computer: AutoComputer) { if (!hasListen) { val componentWrap: AGetter = this as AGetter component.addListSelectionListener { cache = null if (!manual) { computer.call(componentWrap) } } hasListen = true } } override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as JListComponentIndexWrap if (component != other.component) return false return true } override fun hashCode(): Int { return "index".hashCode() xor component.hashCode() } } class JListComponentWrap : ASetter?>, AGetter?>, UIListener { private val component: JList<*> constructor(component: JList<*>) { this.component = component } @Volatile private var cache: List<*>? = null @Volatile private var manual: Boolean = false override fun set(value: List<*>?) { if (value != null) { cache = value EventQueue.invokeLater { if (getModelElements() != value) { manual = true try { this.component.model = DefaultComboBoxModel(value.toTypedArray()) } finally { manual = false } } } } } override fun get(): List<*>? { if (cache != null) return cache return getModelElements() } private fun getModelElements(): List { val model = this.component.model if (model is List<*>) { return model } val modelElements: ArrayList = ArrayList() (0 until model.size).forEach { modelElements.add(model.getElementAt(it)) } cache = modelElements return modelElements } private var hasListen = false override fun onListen(computer: AutoComputer) { listenChange(computer) } @Suppress("UNCHECKED_CAST") private fun listenChange(computer: AutoComputer) { if (!hasListen) { val componentWrap: AGetter = this as AGetter component.model.addListDataListener(object : ListDataListener { override fun contentsChanged(e: ListDataEvent?) { cache = null if (!manual) { computer.call(componentWrap) } } override fun intervalRemoved(e: ListDataEvent?) { cache = null if (!manual) { computer.call(componentWrap) } } override fun intervalAdded(e: ListDataEvent?) { cache = null if (!manual) { computer.call(componentWrap) } } }) hasListen = true } } override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as JListComponentWrap if (component != other.component) return false return true } override fun hashCode(): Int { return component.hashCode() } } class JComboBoxComponentIndexWrap : ASetter, AGetter, UIListener { private val component: JComboBox<*> constructor(component: JComboBox<*>) { this.component = component } @Volatile private var cache: Int? = null @Volatile private var manual: Boolean = false override fun set(value: Int?) { if (value != null) { cache = value EventQueue.invokeLater { if (this.component.selectedIndex != value) { manual = true try { this.component.selectedIndex = value } finally { manual = false } } } } } override fun get(): Int? { return when { cache != null -> cache else -> this.component.selectedIndex } } private var hasListen = false override fun onListen(computer: AutoComputer) { listenChange(computer) } @Suppress("UNCHECKED_CAST") private fun listenChange(computer: AutoComputer) { if (!hasListen) { val componentWrap: AGetter = this as AGetter component.addItemListener { cache = null if (!manual) { computer.call(componentWrap) } } hasListen = true } } override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as JComboBoxComponentIndexWrap if (component != other.component) return false return true } override fun hashCode(): Int { return "index".hashCode() xor component.hashCode() } } class JComboBoxComponentWrap : ASetter, AGetter, UIListener { private val component: JComboBox constructor(component: JComboBox) { this.component = component } @Volatile private var cache: T? = null @Volatile private var manual: Boolean = false override fun set(value: T?) { if (value != null) { EventQueue.invokeLater { if (this.component.selectedItem != value) { manual = true try { this.component.selectedItem = value } finally { manual = false } } } } } @Suppress("UNCHECKED_CAST") override fun get(): T? { if (cache != null) return cache cache = this.component.selectedItem as T? return cache } private var hasListen = false override fun onListen(computer: AutoComputer) { listenChange(computer) } @Suppress("UNCHECKED_CAST") private fun listenChange(computer: AutoComputer) { if (!hasListen) { val componentWrap: AGetter = this as AGetter component.model.addListDataListener(object : ListDataListener { override fun contentsChanged(e: ListDataEvent?) { cache = null if (!manual) { computer.call(componentWrap) } } override fun intervalRemoved(e: ListDataEvent?) { cache = null if (!manual) { computer.call(componentWrap) } } override fun intervalAdded(e: ListDataEvent?) { cache = null if (!manual) { computer.call(componentWrap) } } }) hasListen = true } } override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as JComboBoxComponentWrap<*> if (component != other.component) return false return true } override fun hashCode(): Int { return component.hashCode() } } class BeanPropertyWrap : ASetter, AGetter, HasProperty, DataListener { private val targetGetter: (() -> Any?) private val propertySetter: ((Any, T?) -> Unit) private val propertyGetter: ((Any) -> T?) private val aProperty: AProperty constructor( targetGetter: () -> Any?, propertySetter: (Any, T?) -> Unit, propertyGetter: (Any) -> T?, aProperty: AProperty ) { this.targetGetter = targetGetter this.propertySetter = propertySetter this.propertyGetter = propertyGetter this.aProperty = aProperty } override fun set(value: T?) { targetGetter()?.let { propertySetter(it, value) } } override fun get(): T? { return targetGetter()?.let { this.propertyGetter(it) } } override fun getProperty(): AProperty { return this.aProperty } override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is HasProperty<*>) return false if (aProperty != other.getProperty()) return false return true } override fun hashCode(): Int { return aProperty.hashCode() } override fun toString(): String { return "BeanPropertyWrap(aProperty=$aProperty)" } } //endregion wraps------------------------------------------------------------------ //region enhance AutoBind0------------------------------------------------------------ // [consistent]: One-to-one direct binding of two identical type values // [from]:Take a value from the same type property directly // [option]: Automatic convert source value to Optional // [eval]:Simplify operation [eval] fun AutoComputer.AutoBind0.from(param: KProperty0) { this.with(param).eval() } fun AutoComputer.AutoBind0.from(target: Any, property: String) { this.with(target, property).eval() } fun AutoComputer.AutoBind0.from(param: JTextComponent) { this.with(param).eval() } fun AutoComputer.AutoBind0.from(param: JLabel) { this.with(param).eval() } fun AutoComputer.AutoBind0.from(param: JList<*>) { this.withIndex(param).eval() } fun AutoComputer.AutoBind1.option(exp: (Optional

) -> T) { this.eval { p -> val optional: Optional<*> = Optional.ofNullable(p) exp(optional as Optional

) } } fun AutoComputer.AutoBind1.eval() { this.eval { r -> r } } @Suppress("UNCHECKED_CAST") fun AutoComputer.AutoBind0.mutual(param: KProperty0) { with(param).eval { r -> r } val core = peakCore() if (param is KMutableProperty0 && core.property is AGetter<*>) { core.computer.bind(param).withGetter(core.property as AGetter).eval { r -> r } } } @Suppress("UNCHECKED_CAST") fun AutoComputer.AutoBind0.mutual(target: Any, property: String) { with(target, property).eval { r -> r } val core = peakCore() if (core.property is AGetter<*>) { core.computer.bind(target, property).withGetter(core.property as AGetter).eval { r -> r } } } @Suppress("UNCHECKED_CAST") fun AutoComputer.AutoBind0.mutual(param: JTextComponent) { val core = peakCore() val wrapGetter: AGetter = core.computer.wrapJTextComponent(param) withGetter(wrapGetter).eval { s -> s } if (core.property is AGetter<*>) { core.computer.bind(param).withGetter(core.property as AGetter).eval { r -> r } } } @Suppress("UNCHECKED_CAST") fun AutoComputer.AutoBind0.mutual(param: JLabel) { val core = peakCore() val wrapGetter: AGetter = core.computer.wrapJLabel(param) withGetter(wrapGetter).eval { s -> s } if (core.property is AGetter<*>) { core.computer.bind(param).withGetter(core.property as AGetter).eval { r -> r } } } @Suppress("UNCHECKED_CAST") fun AutoComputer.AutoBind0.mutual(param: JList<*>) { val core = peakCore() val wrapGetter: AGetter = core.computer.wrapJListIndexComponent(param) withGetter(wrapGetter).eval { index -> index } if (core.property is AGetter<*>) { core.computer.bindIndex(param).withGetter(core.property as AGetter).eval { r -> r } } } //endregion enhance AutoBind0------------------------------------------------------------ object AutoComputerUtils { fun mergeFilter(filterProperty: KMutableProperty0, filter: Filter) { val oldFilter = filterProperty.get() if (oldFilter == null) { filterProperty.set(filter) } else { filterProperty.set { oldFilter() && filter() } } } fun from(autoBind: AutoComputer.AutoBind0, param: KProperty0) { autoBind.from(param) } fun from(autoBind: AutoComputer.AutoBind0, target: Any, property: String) { autoBind.from(target, property) } fun from(autoBind: AutoComputer.AutoBind0, param: JTextComponent) { autoBind.from(param) } fun from(autoBind: AutoComputer.AutoBind0, param: JLabel) { autoBind.from(param) } fun from(autoBind: AutoComputer.AutoBind0, param: JList<*>) { autoBind.from(param) } fun option(autoBind: AutoComputer.AutoBind1, exp: (Optional

) -> T) { autoBind.option(exp) } fun eval(autoBind: AutoComputer.AutoBind1) { autoBind.eval() } fun mutual(autoBind: AutoComputer.AutoBind0, param: KProperty0) { autoBind.mutual(param) } fun mutual(autoBind: AutoComputer.AutoBind0, target: Any, property: String) { autoBind.mutual(target, property) } fun mutual(autoBind: AutoComputer.AutoBind0, param: JTextComponent) { autoBind.mutual(param) } fun mutual(autoBind: AutoComputer.AutoBind0, param: JLabel) { autoBind.mutual(param) } fun mutual(autoBind: AutoComputer.AutoBind0, param: JList<*>) { autoBind.mutual(param) } } typealias Filter = () -> Boolean





© 2015 - 2024 Weber Informatics LLC | Privacy Policy