Add observableSize operation to collections

Also, bump the version to 0.9 since this change is definitely not binary
compatible: class names and structures have changed. Most clients should
be fine though if they just recompile: the changes are to things that
will generally be used through the implicits system, so most shoudln't
notice the changes.
This commit is contained in:
Sarah Gerweck 2016-06-12 04:09:03 -07:00
parent ce0e5c001e
commit 99ed345be5
3 changed files with 98 additions and 61 deletions

View File

@ -273,63 +273,3 @@ final class RichProperty[A, B](val inner: Property[A, B]) extends AnyVal {
final class RichObjectProperty[A](val inner: ObjectProperty[A]) extends AnyVal {
def readOnly: ReadOnlyObjectProperty[A] = inner
}
sealed trait ToObservableOps[-A, +B] {
def recalculate(a: A): B
def onChange(a: A)(b: => Unit): Unit
}
object ToObservableOps {
implicit def obOps[A] = new ToObservableOps[ObservableBuffer[A], Seq[A]] {
def recalculate(oba: ObservableBuffer[A]) = oba.toVector
def onChange(oba: ObservableBuffer[A])(b: => Unit) = oba onChange b
}
implicit def oaOps[A] = new ToObservableOps[ObservableArray[A, _, _], Seq[A]] {
def recalculate(oaa: ObservableArray[A, _, _]) = oaa.toVector
def onChange(oaa: ObservableArray[A, _, _])(b: => Unit) = oaa onChange b
}
implicit def osOps[A] = new ToObservableOps[ObservableSet[A], collection.immutable.Set[A]] {
def recalculate(os: ObservableSet[A]) = os.toSet
def onChange(os: ObservableSet[A])(b: => Unit) = os onChange b
}
}
object RichToObservable {
@inline final def toObservable[A, B](a: A)(implicit ops: ToObservableOps[A, B]): ReadOnlyObjectProperty[B] = {
@inline def recalculate(): B = ops.recalculate(a)
val originalValue = recalculate()
val prop = ObjectProperty[B](originalValue)
var prevValue = originalValue
ops.onChange(a) {
prop.synchronized {
val newVal = recalculate()
if (prevValue != newVal) {
prop.value = newVal
prevValue = newVal
}
}
}
prop
}
}
sealed trait RichObservableSeqLike[A] extends Any {
def observableSeqValue: ReadOnlyObjectProperty[Seq[A]]
}
final class RichObservableBuffer[A](val obs: ObservableBuffer[A]) extends AnyVal with RichObservableSeqLike[A] {
def observableSeqValue: ReadOnlyObjectProperty[Seq[A]] = {
RichToObservable.toObservable(obs)
}
}
final class RichObservableArray[A, B <: ObservableArray[A, B, C], C <: javafx.collections.ObservableArray[C]](val oaa: ObservableArray[A, B, C]) extends AnyVal with RichObservableSeqLike[A] {
def observableSeqValue: ReadOnlyObjectProperty[Seq[A]] = {
RichToObservable.toObservable(oaa)
}
}
final class RichObservableSet[A](val os: ObservableSet[A]) extends AnyVal {
def observableSetValue: ReadOnlyObjectProperty[Set[A]] = {
RichToObservable.toObservable(os)
}
}

View File

@ -0,0 +1,97 @@
package org.gerweck.scalafx.util
import language.implicitConversions
import scalafx.beans.property._
import scalafx.collections._
sealed trait ToFlatObservable[-A, +B] extends Calculable[A, B]
object ToFlatObservable extends CalculableObservable[ToFlatObservable[_, _]] {
implicit def obOps[A] = new ToFlatObservable[ObservableBuffer[A], Seq[A]] {
def recalculate(oba: ObservableBuffer[A]) = oba.toVector
}
implicit def oaOps[A] = new ToFlatObservable[ObservableArray[A, _, _], Seq[A]] {
def recalculate(oaa: ObservableArray[A, _, _]) = oaa.toVector
}
implicit def osOps[A] = new ToFlatObservable[ObservableSet[A], collection.immutable.Set[A]] {
def recalculate(os: ObservableSet[A]) = os.toSet
}
}
sealed trait ObservableSized[-A] extends Calculable[A, Int]
object ObservableSized extends CalculableObservable[ObservableSized[_]] {
implicit def obSize[A] = new ObservableSized[ObservableBuffer[A]] {
def recalculate(oba: ObservableBuffer[A]) = oba.size
}
implicit def oaSize[A] = new ObservableSized[ObservableArray[A, _, _]] {
def recalculate(oaa: ObservableArray[A, _, _]) = oaa.size
}
implicit def osSize[A] = new ObservableSized[ObservableSet[A]] {
def recalculate(os: ObservableSet[A]) = os.size
}
}
sealed trait RichObservableSeqLike[A] extends Any {
def observableSeqValue: ReadOnlyObjectProperty[Seq[A]]
def observableSize: ReadOnlyObjectProperty[Int]
}
final class RichObservableBuffer[A](val obs: ObservableBuffer[A]) extends AnyVal with RichObservableSeqLike[A] {
def observableSeqValue: ReadOnlyObjectProperty[Seq[A]] = ToFlatObservable.toObservable(obs)
def observableSize = ObservableSized.toObservable(obs)
}
final class RichObservableArray[A, B <: ObservableArray[A, B, C], C <: javafx.collections.ObservableArray[C]](val oaa: ObservableArray[A, B, C]) extends AnyVal with RichObservableSeqLike[A] {
def observableSeqValue: ReadOnlyObjectProperty[Seq[A]] = ToFlatObservable.toObservable(oaa)
def observableSize = ObservableSized.toObservable(oaa)
}
final class RichObservableSet[A](val os: ObservableSet[A]) extends AnyVal {
def observableSetValue: ReadOnlyObjectProperty[Set[A]] = ToFlatObservable.toObservable(os)
def observableSize = ObservableSized.toObservable(os)
}
class CalculableObservable[O <: Calculable[_, _]] {
final def toObservable[A, B](a: A)(implicit ops: O with Calculable[A, B], cl: ChangeListenable[A]): ReadOnlyObjectProperty[B] = {
@inline def recalculate(): B = ops.recalculate(a)
val originalValue = recalculate()
val prop = ObjectProperty[B](originalValue)
var prevValue = originalValue
cl.onChange(a) {
prop.synchronized {
val newVal = recalculate()
if (prevValue != newVal) {
prop.value = newVal
prevValue = newVal
}
}
}
prop
}
}
/* Type Classes */
trait Calculable[-A, +B] extends Any {
def recalculate(a: A): B
}
sealed trait ChangeListenable[-A] {
def onChange(a: A)(b: => Unit): Unit
}
object ChangeListenable {
implicit def obListenable[A]: ChangeListenable[ObservableBuffer[A]] = new ChangeListenable[ObservableBuffer[A]] {
def onChange(oba: ObservableBuffer[A])(b: => Unit) = oba onChange b
}
implicit def oaListenable[A]: ChangeListenable[ObservableArray[A, _, _]] = new ChangeListenable[ObservableArray[A, _, _]] {
def onChange(oaa: ObservableArray[A, _, _])(b: => Unit) = oaa onChange b
}
implicit def osListenable[A]: ChangeListenable[ObservableSet[A]] = new ChangeListenable[ObservableSet[A]] {
def onChange(osa: ObservableSet[A])(b: => Unit) = osa onChange b
}
}
sealed trait DeriveChanges[A] {
protected val evChange: ChangeListenable[A]
def onChange(a: A)(b: => Unit) = evChange.onChange(a)(b)
}

View File

@ -1 +1 @@
version in ThisBuild := "0.8.4-SNAPSHOT"
version in ThisBuild := "0.9.0-SNAPSHOT"