From f76ce0f0ced166190446f0a852be31fa2257536c Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Fri, 8 Sep 2017 17:30:06 +0100 Subject: [PATCH] CORDA-499: Move JavaFX Models functions into Models (#1430) * Move JavaFX Models functions into Models so that there isn't an empty ModelsKt class generated for Java interop. * Move Models functions into their own file as pushing them into the Models class requires significant changes to the Explorer. --- .../net/corda/client/jfx/model/Models.kt | 111 +----------------- .../net/corda/client/jfx/model/ModelsUtils.kt | 43 +++++++ .../corda/client/jfx/model/TrackedDelegate.kt | 79 +++++++++++++ 3 files changed, 128 insertions(+), 105 deletions(-) create mode 100644 client/jfx/src/main/kotlin/net/corda/client/jfx/model/ModelsUtils.kt create mode 100644 client/jfx/src/main/kotlin/net/corda/client/jfx/model/TrackedDelegate.kt diff --git a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/Models.kt b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/Models.kt index 57f939e672..71a6b66733 100644 --- a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/Models.kt +++ b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/Models.kt @@ -11,20 +11,16 @@ import rx.Observer import rx.subjects.Subject import java.util.* import kotlin.reflect.KClass -import kotlin.reflect.KProperty /** - * This file defines a global [Models] store and delegates to inject event streams/sinks. Note that all streams here - * are global. - * - * This allows decoupling of UI logic from stream initialisation and provides us with a central place to inspect data - * flows. It also allows detecting of looping logic by constructing a stream dependency graph TODO do this. + * Global models store to allow decoupling of UI logic from stream initialisation and provide a central place to + * inspect data flows. It also allows detecting of looping logic by constructing a stream dependency graph TODO do this. * * Usage: * // Inject service -> client event stream - * private val serviceToClient: EventStream by eventStream(WalletMonitorModel::serviceToClient) + * private val serviceToClient: EventStream by Models.eventStream(WalletMonitorModel::serviceToClient) * - * Each Screen code should have a code layout like this: + * Each `Screen` code should have a code layout like this: * * class Screen { * val root = (..) @@ -41,12 +37,13 @@ import kotlin.reflect.KProperty * } * * For example if I wanted to display a list of all USD cash states: + * * class USDCashStatesScreen { * val root: Pane by fxml() * * val usdCashStatesListView: ListView by fxid("USDCashStatesListView") * - * val cashStates: ObservableList by observableList(ContractStateModel::cashStates) + * val cashStates: ObservableList by Models.observableList(ContractStateModel::cashStates) * * val usdCashStates = cashStates.filter { it.(..).currency == USD } * @@ -66,37 +63,6 @@ import kotlin.reflect.KProperty * Another advantage of this separation is that once we start adding a lot of screens we can still track data dependencies * in a central place as opposed to ad-hoc wiring up the observables. */ - -inline fun observable(noinline observableProperty: (M) -> Observable) = - TrackedDelegate.ObservableDelegate(M::class, observableProperty) - -inline fun observer(noinline observerProperty: (M) -> Observer) = - TrackedDelegate.ObserverDelegate(M::class, observerProperty) - -inline fun subject(noinline subjectProperty: (M) -> Subject) = - TrackedDelegate.SubjectDelegate(M::class, subjectProperty) - -inline fun eventStream(noinline streamProperty: (M) -> EventStream) = - TrackedDelegate.EventStreamDelegate(M::class, streamProperty) - -inline fun eventSink(noinline sinkProperty: (M) -> EventSink) = - TrackedDelegate.EventSinkDelegate(M::class, sinkProperty) - -inline fun observableValue(noinline observableValueProperty: (M) -> ObservableValue) = - TrackedDelegate.ObservableValueDelegate(M::class, observableValueProperty) - -inline fun writableValue(noinline writableValueProperty: (M) -> WritableValue) = - TrackedDelegate.WritableValueDelegate(M::class, writableValueProperty) - -inline fun objectProperty(noinline objectProperty: (M) -> ObjectProperty) = - TrackedDelegate.ObjectPropertyDelegate(M::class, objectProperty) - -inline fun observableList(noinline observableListProperty: (M) -> ObservableList) = - TrackedDelegate.ObservableListDelegate(M::class, observableListProperty) - -inline fun observableListReadOnly(noinline observableListProperty: (M) -> ObservableList) = - TrackedDelegate.ObservableListReadOnlyDelegate(M::class, observableListProperty) - object Models { private val modelStore = HashMap, Any>() @@ -120,68 +86,3 @@ object Models { inline fun get(origin: KClass<*>): M = get(M::class, origin) } -sealed class TrackedDelegate(val klass: KClass) { - init { - Models.initModel(klass) - } - - class ObservableDelegate(klass: KClass, val observableProperty: (M) -> Observable) : TrackedDelegate(klass) { - operator fun getValue(thisRef: Any, property: KProperty<*>): Observable { - return observableProperty(Models.get(klass, thisRef.javaClass.kotlin)) - } - } - - class ObserverDelegate(klass: KClass, val observerProperty: (M) -> Observer) : TrackedDelegate(klass) { - operator fun getValue(thisRef: Any, property: KProperty<*>): Observer { - return observerProperty(Models.get(klass, thisRef.javaClass.kotlin)) - } - } - - class SubjectDelegate(klass: KClass, val subjectProperty: (M) -> Subject) : TrackedDelegate(klass) { - operator fun getValue(thisRef: Any, property: KProperty<*>): Subject { - return subjectProperty(Models.get(klass, thisRef.javaClass.kotlin)) - } - } - - class EventStreamDelegate(klass: KClass, val eventStreamProperty: (M) -> org.reactfx.EventStream) : TrackedDelegate(klass) { - operator fun getValue(thisRef: Any, property: KProperty<*>): org.reactfx.EventStream { - return eventStreamProperty(Models.get(klass, thisRef.javaClass.kotlin)) - } - } - - class EventSinkDelegate(klass: KClass, val eventSinkProperty: (M) -> org.reactfx.EventSink) : TrackedDelegate(klass) { - operator fun getValue(thisRef: Any, property: KProperty<*>): org.reactfx.EventSink { - return eventSinkProperty(Models.get(klass, thisRef.javaClass.kotlin)) - } - } - - class ObservableValueDelegate(klass: KClass, val observableValueProperty: (M) -> ObservableValue) : TrackedDelegate(klass) { - operator fun getValue(thisRef: Any, property: KProperty<*>): ObservableValue { - return observableValueProperty(Models.get(klass, thisRef.javaClass.kotlin)) - } - } - - class WritableValueDelegate(klass: KClass, val writableValueProperty: (M) -> WritableValue) : TrackedDelegate(klass) { - operator fun getValue(thisRef: Any, property: KProperty<*>): WritableValue { - return writableValueProperty(Models.get(klass, thisRef.javaClass.kotlin)) - } - } - - class ObservableListDelegate(klass: KClass, val observableListProperty: (M) -> ObservableList) : TrackedDelegate(klass) { - operator fun getValue(thisRef: Any, property: KProperty<*>): ObservableList { - return observableListProperty(Models.get(klass, thisRef.javaClass.kotlin)) - } - } - - class ObservableListReadOnlyDelegate(klass: KClass, val observableListReadOnlyProperty: (M) -> ObservableList) : TrackedDelegate(klass) { - operator fun getValue(thisRef: Any, property: KProperty<*>): ObservableList { - return observableListReadOnlyProperty(Models.get(klass, thisRef.javaClass.kotlin)) - } - } - - class ObjectPropertyDelegate(klass: KClass, val objectPropertyProperty: (M) -> ObjectProperty) : TrackedDelegate(klass) { - operator fun getValue(thisRef: Any, property: KProperty<*>): ObjectProperty { - return objectPropertyProperty(Models.get(klass, thisRef.javaClass.kotlin)) - } - } -} diff --git a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/ModelsUtils.kt b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/ModelsUtils.kt new file mode 100644 index 0000000000..836e046887 --- /dev/null +++ b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/ModelsUtils.kt @@ -0,0 +1,43 @@ +@file:JvmName("ModelsUtils") +package net.corda.client.jfx.model + +import javafx.beans.property.ObjectProperty +import javafx.beans.value.ObservableValue +import javafx.beans.value.WritableValue +import javafx.collections.ObservableList +import org.reactfx.EventSink +import org.reactfx.EventStream +import rx.Observable +import rx.Observer +import rx.subjects.Subject +import kotlin.reflect.KClass + +inline fun observable(noinline observableProperty: (M) -> Observable) = + TrackedDelegate.ObservableDelegate(M::class, observableProperty) + +inline fun observer(noinline observerProperty: (M) -> Observer) = + TrackedDelegate.ObserverDelegate(M::class, observerProperty) + +inline fun subject(noinline subjectProperty: (M) -> Subject) = + TrackedDelegate.SubjectDelegate(M::class, subjectProperty) + +inline fun eventStream(noinline streamProperty: (M) -> EventStream) = + TrackedDelegate.EventStreamDelegate(M::class, streamProperty) + +inline fun eventSink(noinline sinkProperty: (M) -> EventSink) = + TrackedDelegate.EventSinkDelegate(M::class, sinkProperty) + +inline fun observableValue(noinline observableValueProperty: (M) -> ObservableValue) = + TrackedDelegate.ObservableValueDelegate(M::class, observableValueProperty) + +inline fun writableValue(noinline writableValueProperty: (M) -> WritableValue) = + TrackedDelegate.WritableValueDelegate(M::class, writableValueProperty) + +inline fun objectProperty(noinline objectProperty: (M) -> ObjectProperty) = + TrackedDelegate.ObjectPropertyDelegate(M::class, objectProperty) + +inline fun observableList(noinline observableListProperty: (M) -> ObservableList) = + TrackedDelegate.ObservableListDelegate(M::class, observableListProperty) + +inline fun observableListReadOnly(noinline observableListProperty: (M) -> ObservableList) = + TrackedDelegate.ObservableListReadOnlyDelegate(M::class, observableListProperty) \ No newline at end of file diff --git a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/TrackedDelegate.kt b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/TrackedDelegate.kt new file mode 100644 index 0000000000..7ee819f2bb --- /dev/null +++ b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/TrackedDelegate.kt @@ -0,0 +1,79 @@ +package net.corda.client.jfx.model + +import javafx.beans.property.ObjectProperty +import javafx.beans.value.ObservableValue +import javafx.beans.value.WritableValue +import javafx.collections.ObservableList +import org.reactfx.EventSink +import org.reactfx.EventStream +import rx.Observable +import rx.Observer +import rx.subjects.Subject +import kotlin.reflect.KClass +import kotlin.reflect.KProperty + +sealed class TrackedDelegate(val klass: KClass) { + init { + Models.initModel(klass) + } + + class ObservableDelegate(klass: KClass, val observableProperty: (M) -> Observable) : TrackedDelegate(klass) { + operator fun getValue(thisRef: Any, property: KProperty<*>): Observable { + return observableProperty(Models.get(klass, thisRef.javaClass.kotlin)) + } + } + + class ObserverDelegate(klass: KClass, val observerProperty: (M) -> Observer) : TrackedDelegate(klass) { + operator fun getValue(thisRef: Any, property: KProperty<*>): Observer { + return observerProperty(Models.get(klass, thisRef.javaClass.kotlin)) + } + } + + class SubjectDelegate(klass: KClass, val subjectProperty: (M) -> Subject) : TrackedDelegate(klass) { + operator fun getValue(thisRef: Any, property: KProperty<*>): Subject { + return subjectProperty(Models.get(klass, thisRef.javaClass.kotlin)) + } + } + + class EventStreamDelegate(klass: KClass, val eventStreamProperty: (M) -> EventStream) : TrackedDelegate(klass) { + operator fun getValue(thisRef: Any, property: KProperty<*>): EventStream { + return eventStreamProperty(Models.get(klass, thisRef.javaClass.kotlin)) + } + } + + class EventSinkDelegate(klass: KClass, val eventSinkProperty: (M) -> EventSink) : TrackedDelegate(klass) { + operator fun getValue(thisRef: Any, property: KProperty<*>): EventSink { + return eventSinkProperty(Models.get(klass, thisRef.javaClass.kotlin)) + } + } + + class ObservableValueDelegate(klass: KClass, val observableValueProperty: (M) -> ObservableValue) : TrackedDelegate(klass) { + operator fun getValue(thisRef: Any, property: KProperty<*>): ObservableValue { + return observableValueProperty(Models.get(klass, thisRef.javaClass.kotlin)) + } + } + + class WritableValueDelegate(klass: KClass, val writableValueProperty: (M) -> WritableValue) : TrackedDelegate(klass) { + operator fun getValue(thisRef: Any, property: KProperty<*>): WritableValue { + return writableValueProperty(Models.get(klass, thisRef.javaClass.kotlin)) + } + } + + class ObservableListDelegate(klass: KClass, val observableListProperty: (M) -> ObservableList) : TrackedDelegate(klass) { + operator fun getValue(thisRef: Any, property: KProperty<*>): ObservableList { + return observableListProperty(Models.get(klass, thisRef.javaClass.kotlin)) + } + } + + class ObservableListReadOnlyDelegate(klass: KClass, val observableListReadOnlyProperty: (M) -> ObservableList) : TrackedDelegate(klass) { + operator fun getValue(thisRef: Any, property: KProperty<*>): ObservableList { + return observableListReadOnlyProperty(Models.get(klass, thisRef.javaClass.kotlin)) + } + } + + class ObjectPropertyDelegate(klass: KClass, val objectPropertyProperty: (M) -> ObjectProperty) : TrackedDelegate(klass) { + operator fun getValue(thisRef: Any, property: KProperty<*>): ObjectProperty { + return objectPropertyProperty(Models.get(klass, thisRef.javaClass.kotlin)) + } + } +} \ No newline at end of file