Created
December 31, 2014 22:03
-
-
Save NightRa/856d11944b3e51967d1a to your computer and use it in GitHub Desktop.
Revisions
-
NightRa created this gist
Dec 31, 2014 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,104 @@ package nightra.reversi.util import scala.ref.WeakReference import scalafx.beans.property.{Property, BooleanProperty, ObjectProperty} import scalafx.beans.value.ObservableValue import scalafx.collections.ObservableBuffer import scalafx.event.subscriptions.Subscription object JavaFXUtil { /** * Memory scheme: * b = a.map(f) * b a strong reference to a, * while a does not hold a strong reference to b; * If b loses all strong references, * the change listener from a will be cleaned, * and b will be garbage collected. **/ def weaklyBindOnChange[A, B](prop: ObservableValue[A, _], to: Property[B, _])(f: A => B): Subscription = { to.onChange({prop;()}) // capture prop as a strong reference in to, so that it won't be released until to is released val weakNewProp: WeakReference[Property[B, _]] = WeakReference(to) // Don't capture 'to in 'prop, so 'to can be cleaned without prop being cleaned. lazy val subscription: Subscription = prop.onChange((_, _, _) => weakNewProp.get match { case None => subscription.cancel() case Some(newProp) => newProp.value = f(prop.value) }) subscription // Force the lazy val to tie the recursive knot. } def liftObservableList[A](prop: ObjectProperty[ObservableBuffer[A]]): ObservableBuffer[A] = { val newList = ObservableBuffer(prop.value) newList.onChange({ prop; () }) // capture the original property in memory. val weakNewList = WeakReference(newList) lazy val subscription: Subscription = prop.onChange { (_, _, _) => weakNewList.get match { case None => subscription.cancel() case Some(solidNewList) => newList.clear() newList ++= prop.value } } subscription // Force the lazy val to tie the recursive knot. newList } /** * Nice that the whole basic hierarchy is here: * Functor, * Applicative, * and Monad. * Actually needed each and every one of them. **/ def flattenProp[A](prop: ObservableValue[ObservableValue[A, _], _]): ObjectProperty[A] = { val newProp: ObjectProperty[A] = ObjectProperty(prop.value.value) var lastSubscription: Subscription = null newProp.onChange({ prop; () }) val weakNewProp = WeakReference(newProp) lazy val subscription: Subscription = prop.onChange { (_, _, _) => val innerProp = prop.value if (lastSubscription != null) lastSubscription.cancel() weakNewProp.get match { case None => subscription.cancel() case Some(solidNewProp) => lastSubscription = weaklyBindOnChange(innerProp, newProp)(s => s) } } subscription newProp } def mapProp[A, B](prop: ObservableValue[A, _])(f: A => B): ObjectProperty[B] = { val newProp: ObjectProperty[B] = ObjectProperty(f(prop.value)) weaklyBindOnChange(prop, newProp)(f) newProp // Strong reference. } def map2Prop[A, B, C](prop1: ObservableValue[A, _], prop2: ObservableValue[B, _])(f: (A, B) => C): ObjectProperty[C] = { val newProp: ObjectProperty[C] = ObjectProperty(f(prop1.value, prop2.value)) weaklyBindOnChange(prop1, newProp)(s1 => f(s1, prop2.value)) weaklyBindOnChange(prop2, newProp)(s2 => f(prop1.value, s2)) newProp // Strong reference. } def map3Prop[A, B, C, D](prop1: ObservableValue[A, _], prop2: ObservableValue[B, _], prop3: ObservableValue[C, _])(f: (A, B, C) => D): ObjectProperty[D] = { val newProp: ObjectProperty[D] = ObjectProperty(f(prop1.value, prop2.value, prop3.value)) weaklyBindOnChange(prop1, newProp)(s1 => f(s1, prop2.value, prop3.value)) weaklyBindOnChange(prop2, newProp)(s2 => f(prop1.value, s2, prop3.value)) weaklyBindOnChange(prop3, newProp)(s3 => f(prop1.value, prop2.value, s3)) newProp // Strong reference. } def merge[A](props: Vector[ObjectProperty[A]]): ObjectProperty[A] = { val newProp: ObjectProperty[A] = ObjectProperty(props.head.value) props.foreach(prop => weaklyBindOnChange(prop, newProp)(s => s)) newProp // Strong reference. } def toBooleanProp(prop: ObjectProperty[Boolean]): BooleanProperty = { val newProp: BooleanProperty = BooleanProperty(prop.value) weaklyBindOnChange(prop, newProp)(s => s) newProp // Strong reference. } }