Updated project further
Updated scala version to 2.13.4 Compiles to Java 11 now Updated sbt to 1.4.3 Updated scalafx version to 14 Removed unneeded dependencies Removed Akka code Added lint and fatal warnings scalac options Added parantheses to side effecting methods Added >> and << methods to observables
This commit is contained in:
parent
7c00f26760
commit
7484570e40
7
.gitignore
vendored
7
.gitignore
vendored
@ -46,3 +46,10 @@ bin
|
|||||||
/log
|
/log
|
||||||
/*.script
|
/*.script
|
||||||
typescript
|
typescript
|
||||||
|
|
||||||
|
.metals
|
||||||
|
.sbt
|
||||||
|
.vscode
|
||||||
|
.bsp
|
||||||
|
.bloop
|
||||||
|
metals.sbt
|
1
.sbtopts
1
.sbtopts
@ -1,4 +1,3 @@
|
|||||||
-J-Xmx4G
|
-J-Xmx4G
|
||||||
-J-XX:MaxMetaspaceSize=4g
|
-J-XX:MaxMetaspaceSize=4g
|
||||||
-J-XX:+UnlockCommercialFeatures
|
|
||||||
-J-XX:+FlightRecorder
|
-J-XX:+FlightRecorder
|
||||||
|
16
build.sbt
16
build.sbt
@ -27,21 +27,21 @@ lazy val root = (project in file ("."))
|
|||||||
jclBridge % "runtime,optional",
|
jclBridge % "runtime,optional",
|
||||||
log4jBridge % "runtime,optional",
|
log4jBridge % "runtime,optional",
|
||||||
logback % "runtime,optional",
|
logback % "runtime,optional",
|
||||||
gerweckUtil,
|
// gerweckUtil,
|
||||||
scalaJava8,
|
// scalaJava8,
|
||||||
scalaFx,
|
scalaFx,
|
||||||
cats,
|
cats,
|
||||||
shapeless
|
shapeless
|
||||||
),
|
),
|
||||||
|
|
||||||
libraryDependencies ++= javaFXModules.map( m =>
|
libraryDependencies ++= javaFXModules.map( m =>
|
||||||
"org.openjfx" % s"javafx-$m" % "12.0.2" classifier osName
|
"org.openjfx" % s"javafx-$m" % "11.0.2" classifier osName
|
||||||
),
|
),
|
||||||
|
|
||||||
/* Akka dependencies */
|
/* Akka dependencies */
|
||||||
libraryDependencies ++= Seq (
|
// libraryDependencies ++= Seq (
|
||||||
akkaActor % "optional",
|
// akkaActor % "optional",
|
||||||
akkaStream % "optional",
|
// akkaStream % "optional",
|
||||||
gerweckUtilAkka % "optional"
|
// gerweckUtilAkka % "optional"
|
||||||
)
|
// )
|
||||||
)
|
)
|
||||||
|
@ -73,6 +73,8 @@ trait BasicSettings extends ProjectSettings { st: SettingTemplate =>
|
|||||||
var options = Seq.empty[String]
|
var options = Seq.empty[String]
|
||||||
val sv = sver.value
|
val sv = sver.value
|
||||||
|
|
||||||
|
options :+= "-Xlint"
|
||||||
|
options :+= "-Xfatal-warnings"
|
||||||
options :+= "-unchecked"
|
options :+= "-unchecked"
|
||||||
options :+= "-feature"
|
options :+= "-feature"
|
||||||
if (deprecation) {
|
if (deprecation) {
|
||||||
@ -160,8 +162,8 @@ trait BasicSettings extends ProjectSettings { st: SettingTemplate =>
|
|||||||
|
|
||||||
if (sv.requireJava8) {
|
if (sv.requireJava8) {
|
||||||
options ++= Seq[String](
|
options ++= Seq[String](
|
||||||
"-target", "1.8",
|
"-target", "11",
|
||||||
"-source", "1.8"
|
"-source", "11"
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
options ++= Seq[String](
|
options ++= Seq[String](
|
||||||
|
@ -34,10 +34,10 @@ object Dependencies {
|
|||||||
val logback = "ch.qos.logback" % "logback-classic" % logbackVersion
|
val logback = "ch.qos.logback" % "logback-classic" % logbackVersion
|
||||||
val spire = "org.spire-math" %% "spire" % spireVersion
|
val spire = "org.spire-math" %% "spire" % spireVersion
|
||||||
val commonsIo = "commons-io" % "commons-io" % commonsIoVersion
|
val commonsIo = "commons-io" % "commons-io" % commonsIoVersion
|
||||||
val groovy = "org.codehaus.groovy" % "groovy-all" % groovyVersion
|
// val groovy = "org.codehaus.groovy" % "groovy-all" % groovyVersion
|
||||||
val gerweckUtil = "org.gerweck.scala" %% "gerweck-utils" % gerweckUtilVersion
|
val gerweckUtil = "org.gerweck.scala" %% "gerweck-utils" % gerweckUtilVersion
|
||||||
val gerweckUtilAkka = "org.gerweck.scala" %% "gerweck-utils-akka" % gerweckUtilVersion
|
val gerweckUtilAkka = "org.gerweck.scala" %% "gerweck-utils-akka" % gerweckUtilVersion
|
||||||
val scalaJava8 = "org.scala-lang.modules" %% "scala-java8-compat" % scalaJava8Version
|
// val scalaJava8 = "org.scala-lang.modules" %% "scala-java8-compat" % scalaJava8Version
|
||||||
val cats = "org.typelevel" %% "cats-core" % catsVersion
|
val cats = "org.typelevel" %% "cats-core" % catsVersion
|
||||||
val shapeless = "com.chuusai" %% "shapeless" % shapelessVersion
|
val shapeless = "com.chuusai" %% "shapeless" % shapelessVersion
|
||||||
val scallop = "org.rogach" %% "scallop" % scallopVersion
|
val scallop = "org.rogach" %% "scallop" % scallopVersion
|
||||||
@ -81,8 +81,7 @@ object Dependencies {
|
|||||||
/* ********************************************************************** */
|
/* ********************************************************************** */
|
||||||
/* ScalaFX */
|
/* ScalaFX */
|
||||||
/* ********************************************************************** */
|
/* ********************************************************************** */
|
||||||
// final val scalaFxVersion = "8.0.144-R12"
|
final val scalaFxVersion = "14-R19"
|
||||||
final val scalaFxVersion = "12.0.2-R18"
|
|
||||||
|
|
||||||
val scalaFx = "org.scalafx" %% "scalafx" % scalaFxVersion
|
val scalaFx = "org.scalafx" %% "scalafx" % scalaFxVersion
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ trait ProjectSettings
|
|||||||
override final val githubOrganization = "sarahgerweck"
|
override final val githubOrganization = "sarahgerweck"
|
||||||
override final val githubProject = "scalafx-utils"
|
override final val githubProject = "scalafx-utils"
|
||||||
|
|
||||||
override final val buildScalaVersion = "2.13.1"
|
override final val buildScalaVersion = "2.13.4"
|
||||||
override final val extraScalaVersions = Seq("2.11.12", "2.12.5")
|
override final val extraScalaVersions = Seq("2.11.12", "2.12.5")
|
||||||
override final val defaultOptimize = true
|
override final val defaultOptimize = true
|
||||||
override final val defaultOptimizeGlobal = false
|
override final val defaultOptimizeGlobal = false
|
||||||
|
@ -1 +1 @@
|
|||||||
sbt.version=1.3.8
|
sbt.version=1.4.3
|
||||||
|
1
project/plugins.sbt
Normal file
1
project/plugins.sbt
Normal file
@ -0,0 +1 @@
|
|||||||
|
addSbtPlugin("com.thoughtworks.sbt-api-mappings" % "sbt-api-mappings" % "2.0.2")
|
@ -1,74 +1,74 @@
|
|||||||
package org.gerweck.scalafx.akka
|
// package org.gerweck.scalafx.akka
|
||||||
|
|
||||||
import scala.concurrent._
|
// import scala.concurrent._
|
||||||
|
|
||||||
import akka.Done
|
// import akka.Done
|
||||||
import akka.stream.OverflowStrategy
|
// import akka.stream.OverflowStrategy
|
||||||
import akka.stream.scaladsl._
|
// import akka.stream.scaladsl._
|
||||||
|
|
||||||
import scalafx.application.Platform.runLater
|
// import scalafx.application.Platform.runLater
|
||||||
import scalafx.beans.property.Property
|
// import scalafx.beans.property.Property
|
||||||
import scalafx.beans.value.ObservableValue
|
// import scalafx.beans.value.ObservableValue
|
||||||
|
|
||||||
/** A master object that exposes all the Akka-ScalaFX bridges.
|
// /** A master object that exposes all the Akka-ScalaFX bridges.
|
||||||
*
|
// *
|
||||||
* @author Sarah Gerweck <sarah.a180@gmail.com>
|
// * @author Sarah Gerweck <sarah.a180@gmail.com>
|
||||||
*/
|
// */
|
||||||
object AkkaFX extends AkkaStreamFX with AkkaFXCollections
|
// object AkkaFX extends AkkaStreamFX with AkkaFXCollections
|
||||||
|
|
||||||
trait AkkaStreamFX extends Any {
|
// trait AkkaStreamFX extends Any {
|
||||||
/** A [[akka.stream.scaladsl.Sink]] that sends all values to a
|
// /** A [[akka.stream.scaladsl.Sink]] that sends all values to a
|
||||||
* [[scalafx.beans.property.Property]].
|
// * [[scalafx.beans.property.Property]].
|
||||||
*
|
// *
|
||||||
* Each event that's written into the `Sink` will trigger an update of the
|
// * Each event that's written into the `Sink` will trigger an update of the
|
||||||
* `Property` with the streamed value.
|
// * `Property` with the streamed value.
|
||||||
*/
|
// */
|
||||||
def observableSink[A](prop: Property[A, _]): Sink[A, Future[Done]] = {
|
// def observableSink[A](prop: Property[A, _]): Sink[A, Future[Done]] = {
|
||||||
Sink.foreach[A] { a =>
|
// Sink.foreach[A] { a =>
|
||||||
runLater {
|
// runLater {
|
||||||
prop.value = a
|
// prop.value = a
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/** A [[akka.stream.scaladsl.Source]] that generates an event for each
|
// /** A [[akka.stream.scaladsl.Source]] that generates an event for each
|
||||||
* change of an [[scalafx.beans.value.ObservableValue]].
|
// * change of an [[scalafx.beans.value.ObservableValue]].
|
||||||
*
|
// *
|
||||||
* This source adds an `onChange` handler to the given `ObservableValue`.
|
// * This source adds an `onChange` handler to the given `ObservableValue`.
|
||||||
* Each time it observes a change, the new value is pushed from the
|
// * Each time it observes a change, the new value is pushed from the
|
||||||
* `Source`. The change handler is registered as soon as the source is
|
// * `Source`. The change handler is registered as soon as the source is
|
||||||
* materialized into a graph. It should be safe to use a single source
|
// * materialized into a graph. It should be safe to use a single source
|
||||||
* in several graphs, as each will register its own change listener upon
|
// * in several graphs, as each will register its own change listener upon
|
||||||
* materialization.
|
// * materialization.
|
||||||
*
|
// *
|
||||||
* @param prop The value to observe.
|
// * @param prop The value to observe.
|
||||||
*
|
// *
|
||||||
* @param queueSize The maximum number of values to queue while waiting for
|
// * @param queueSize The maximum number of values to queue while waiting for
|
||||||
* the downstream flow to consume more data.
|
// * the downstream flow to consume more data.
|
||||||
*
|
// *
|
||||||
* @param overflow What to do when the queue is full because the downstream
|
// * @param overflow What to do when the queue is full because the downstream
|
||||||
* flow cannot keep up. The default behavior is to block, slowing the UI's
|
// * flow cannot keep up. The default behavior is to block, slowing the UI's
|
||||||
* main thread until some events are consumed, freeing space in the queue.
|
// * main thread until some events are consumed, freeing space in the queue.
|
||||||
*/
|
// */
|
||||||
def observableSource[A](prop: ObservableValue[_, A],
|
// def observableSource[A](prop: ObservableValue[_, A],
|
||||||
queueSize: Int = 10,
|
// queueSize: Int = 10,
|
||||||
overflow: OverflowStrategy = OverflowStrategy.backpressure
|
// overflow: OverflowStrategy = OverflowStrategy.backpressure
|
||||||
)(implicit ec: ExecutionContext) = {
|
// )(implicit ec: ExecutionContext) = {
|
||||||
val src = Source
|
// val src = Source
|
||||||
.queue[A](queueSize, overflow)
|
// .queue[A](queueSize, overflow)
|
||||||
.mapMaterializedValue { m =>
|
// .mapMaterializedValue { m =>
|
||||||
val sub = {
|
// val sub = {
|
||||||
prop.onChange { (dta, oldV, newV) =>
|
// prop.onChange { (dta, oldV, newV) =>
|
||||||
m.offer(newV)
|
// m.offer(newV)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
m.watchCompletion foreach { c =>
|
// m.watchCompletion() foreach { c =>
|
||||||
runLater {
|
// runLater {
|
||||||
sub.cancel()
|
// sub.cancel()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
m
|
// m
|
||||||
}
|
// }
|
||||||
src
|
// src
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1,72 +1,72 @@
|
|||||||
package org.gerweck.scalafx.akka
|
// package org.gerweck.scalafx.akka
|
||||||
|
|
||||||
import language.implicitConversions
|
// import language.implicitConversions
|
||||||
|
|
||||||
import scala.collection.mutable.{ Clearable, Growable }
|
// import scala.collection.mutable.{ Clearable, Growable }
|
||||||
import scala.concurrent._
|
// import scala.concurrent._
|
||||||
import scala.concurrent.duration._
|
// import scala.concurrent.duration._
|
||||||
import scala.util._
|
// import scala.util._
|
||||||
|
|
||||||
import akka.{ Done, NotUsed }
|
// import akka.{ Done, NotUsed }
|
||||||
import akka.stream.Materializer
|
// import akka.stream.Materializer
|
||||||
import akka.stream.scaladsl._
|
// import akka.stream.scaladsl._
|
||||||
|
|
||||||
import scalafx.application.Platform.runLater
|
// import scalafx.application.Platform.runLater
|
||||||
import scalafx.beans.Observable
|
// import scalafx.beans.Observable
|
||||||
import scalafx.beans.property._
|
// import scalafx.beans.property._
|
||||||
|
|
||||||
import org.gerweck.scalafx.util.FutureObservable
|
// import org.gerweck.scalafx.util.FutureObservable
|
||||||
|
|
||||||
trait AkkaFXCollections extends Any {
|
// trait AkkaFXCollections extends Any {
|
||||||
implicit def sourceToRichSource[A, B](source: Source[A, B]) = new AkkaFXCollections.RichSource(source)
|
// implicit def sourceToRichSource[A, B](source: Source[A, B]) = new AkkaFXCollections.RichSource(source)
|
||||||
}
|
// }
|
||||||
|
|
||||||
object AkkaFXCollections {
|
// object AkkaFXCollections {
|
||||||
def collectionWriterSink[A]
|
// def collectionWriterSink[A]
|
||||||
(buffer: Observable with Growable[A] with Clearable,
|
// (buffer: Observable with Growable[A] with Clearable,
|
||||||
clearFirst: Boolean,
|
// clearFirst: Boolean,
|
||||||
groupingSize: Int = 50, groupingTimeout: FiniteDuration = 100.milliseconds)
|
// groupingSize: Int = 50, groupingTimeout: FiniteDuration = 100.milliseconds)
|
||||||
: Sink[A, Future[Done]] = {
|
// : Sink[A, Future[Done]] = {
|
||||||
sealed trait PopulateAction
|
// sealed trait PopulateAction
|
||||||
case class InsertRows(data: Seq[A]) extends PopulateAction
|
// case class InsertRows(data: Seq[A]) extends PopulateAction
|
||||||
case object ClearData extends PopulateAction
|
// case object ClearData extends PopulateAction
|
||||||
|
|
||||||
val grouping = {
|
// val grouping = {
|
||||||
Flow[A]
|
// Flow[A]
|
||||||
.groupedWithin(groupingSize, groupingTimeout)
|
// .groupedWithin(groupingSize, groupingTimeout)
|
||||||
.map(InsertRows)
|
// .map(InsertRows)
|
||||||
.named("GroupInsertActions")
|
// .named("GroupInsertActions")
|
||||||
}
|
// }
|
||||||
|
|
||||||
val clearData = {
|
// val clearData = {
|
||||||
if (clearFirst)
|
// if (clearFirst)
|
||||||
Source.single(ClearData)
|
// Source.single(ClearData)
|
||||||
else
|
// else
|
||||||
Source.empty
|
// Source.empty
|
||||||
}.named("OptionalClearAction")
|
// }.named("OptionalClearAction")
|
||||||
|
|
||||||
val combinedSource: Flow[A, PopulateAction, NotUsed] = grouping.prepend(clearData)
|
// val combinedSource: Flow[A, PopulateAction, NotUsed] = grouping.prepend(clearData)
|
||||||
combinedSource .toMat {
|
// combinedSource .toMat {
|
||||||
Sink .foreach[PopulateAction] {
|
// Sink .foreach[PopulateAction] {
|
||||||
case ClearData => runLater { buffer.clear() }
|
// case ClearData => runLater { buffer.clear() }
|
||||||
case InsertRows(data) => runLater { buffer ++= data }
|
// case InsertRows(data) => runLater { buffer ++= data }
|
||||||
} .named("BufferWriter")
|
// } .named("BufferWriter")
|
||||||
}(Keep.right)
|
// }(Keep.right)
|
||||||
}
|
// }
|
||||||
|
|
||||||
class RichSource[A, B](val inner: Source[A, B]) extends AnyVal {
|
// class RichSource[A, B](val inner: Source[A, B]) extends AnyVal {
|
||||||
def populateCollection[C >: A]
|
// def populateCollection[C >: A]
|
||||||
(buffer: Observable with Growable[C] with Clearable,
|
// (buffer: Observable with Growable[C] with Clearable,
|
||||||
clearFirst: Boolean,
|
// clearFirst: Boolean,
|
||||||
groupingSize: Int = 50, groupingTimeout: FiniteDuration = 100.milliseconds)
|
// groupingSize: Int = 50, groupingTimeout: FiniteDuration = 100.milliseconds)
|
||||||
(implicit mat: Materializer, ec: ExecutionContext)
|
// (implicit mat: Materializer, ec: ExecutionContext)
|
||||||
: ReadOnlyObjectProperty[Option[Try[Done]]] = {
|
// : ReadOnlyObjectProperty[Option[Try[Done]]] = {
|
||||||
|
|
||||||
val sink = collectionWriterSink(buffer, clearFirst, groupingSize, groupingTimeout)
|
// val sink = collectionWriterSink(buffer, clearFirst, groupingSize, groupingTimeout)
|
||||||
|
|
||||||
val graph = inner.toMat(sink)(Keep.right)
|
// val graph = inner.toMat(sink)(Keep.right)
|
||||||
|
|
||||||
FutureObservable.ofTryOption(graph.run())
|
// FutureObservable.ofTryOption(graph.run())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -46,7 +46,7 @@ abstract class SingletonStage {
|
|||||||
/** Create the stage, or give it focus if it already exists.
|
/** Create the stage, or give it focus if it already exists.
|
||||||
*
|
*
|
||||||
* This needs to be executed within the UI thread. If you're not already within some kind
|
* This needs to be executed within the UI thread. If you're not already within some kind
|
||||||
* of event handler, you need to use [[scalafx.application.Platform.runLater]].
|
* of event handler, you need to use [[scalafx.application.Platform$.runLater[R](op:=>R):Unit*]].
|
||||||
*/
|
*/
|
||||||
def showStage(): Unit = {
|
def showStage(): Unit = {
|
||||||
State.currentStage match {
|
State.currentStage match {
|
||||||
|
@ -28,7 +28,7 @@ object HorizontalControlPanel {
|
|||||||
alignment = Pos.CenterRight
|
alignment = Pos.CenterRight
|
||||||
}
|
}
|
||||||
case SeparatorEntry =>
|
case SeparatorEntry =>
|
||||||
Separators.vertical
|
Separators.vertical()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,9 +56,6 @@ object ControlPanel {
|
|||||||
def apply(controls: ControlPanelEntry*): Pane = VerticalControlPanel(controls: _*)
|
def apply(controls: ControlPanelEntry*): Pane = VerticalControlPanel(controls: _*)
|
||||||
|
|
||||||
private[this] lazy val defaultFont = new Font(Font.default)
|
private[this] lazy val defaultFont = new Font(Font.default)
|
||||||
private[this] lazy val boldFont = {
|
|
||||||
Font(defaultFont.family, FontWeight.Bold, defaultFont.size)
|
|
||||||
}
|
|
||||||
|
|
||||||
private[this] lazy val labelsFont = defaultFont
|
private[this] lazy val labelsFont = defaultFont
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import org.log4s._
|
|||||||
|
|
||||||
import scalafx.Includes._
|
import scalafx.Includes._
|
||||||
import scalafx.event.ActionEvent
|
import scalafx.event.ActionEvent
|
||||||
import scalafx.event.ActionEvent
|
|
||||||
import scalafx.geometry.Insets
|
import scalafx.geometry.Insets
|
||||||
import scalafx.scene.Node
|
import scalafx.scene.Node
|
||||||
import scalafx.scene.control._
|
import scalafx.scene.control._
|
||||||
@ -13,7 +12,6 @@ import scalafx.scene.layout._
|
|||||||
import scalafx.stage.Stage
|
import scalafx.stage.Stage
|
||||||
import javafx.scene.{ Node => JNode }
|
import javafx.scene.{ Node => JNode }
|
||||||
import javafx.scene.layout.{ Region => JRegion }
|
import javafx.scene.layout.{ Region => JRegion }
|
||||||
import scalafx.delegate.SFXDelegate
|
|
||||||
|
|
||||||
/** A standard button bar with the major dialog buttons.
|
/** A standard button bar with the major dialog buttons.
|
||||||
*
|
*
|
||||||
@ -72,7 +70,7 @@ class DialogButtons(stage: Stage, showOk: Boolean = true, showApply: Boolean = t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected[control] def mainLayout = new VBox(Separators.horizontal, bar) {
|
protected[control] def mainLayout = new VBox(Separators.horizontal(), bar) {
|
||||||
hgrow = Priority.Always
|
hgrow = Priority.Always
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ private object ObservableImplicits {
|
|||||||
val prop = ObjectProperty[B](originalValue)
|
val prop = ObjectProperty[B](originalValue)
|
||||||
|
|
||||||
var prevValue = originalValue
|
var prevValue = originalValue
|
||||||
def changeHandler = prop.synchronized {
|
def changeHandler() = prop.synchronized {
|
||||||
val newVal = recalculate()
|
val newVal = recalculate()
|
||||||
if (prevValue != newVal) {
|
if (prevValue != newVal) {
|
||||||
prop.value = newVal
|
prop.value = newVal
|
||||||
@ -50,7 +50,7 @@ private object ObservableImplicits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a onChange changeHandler
|
a onChange changeHandler()
|
||||||
prop
|
prop
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ private object ObservableImplicits {
|
|||||||
|
|
||||||
var prevValue = originalValue
|
var prevValue = originalValue
|
||||||
|
|
||||||
def changeHandler = prop.synchronized {
|
def changeHandler() = prop.synchronized {
|
||||||
val newVal = recalculate()
|
val newVal = recalculate()
|
||||||
if (prevValue != newVal) {
|
if (prevValue != newVal) {
|
||||||
prop.value = newVal
|
prop.value = newVal
|
||||||
@ -76,8 +76,8 @@ private object ObservableImplicits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fa onChange changeHandler
|
fa onChange changeHandler()
|
||||||
f onChange changeHandler
|
f onChange changeHandler()
|
||||||
|
|
||||||
prop
|
prop
|
||||||
}
|
}
|
||||||
@ -110,7 +110,7 @@ private object ObservableImplicits {
|
|||||||
prevValue = newVal
|
prevValue = newVal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var innerSub = oa() onChange innerHandle
|
var innerSub = oa() onChange innerHandle()
|
||||||
|
|
||||||
var prevOuter = oa()
|
var prevOuter = oa()
|
||||||
def outerHandle() = prop.synchronized {
|
def outerHandle() = prop.synchronized {
|
||||||
@ -118,13 +118,13 @@ private object ObservableImplicits {
|
|||||||
/* We need reference equality here: we're subscribing to a specific object. */
|
/* We need reference equality here: we're subscribing to a specific object. */
|
||||||
if (prevOuter ne newOuter) {
|
if (prevOuter ne newOuter) {
|
||||||
innerSub.cancel()
|
innerSub.cancel()
|
||||||
innerSub = newOuter onChange innerHandle
|
innerSub = newOuter onChange innerHandle()
|
||||||
prevOuter = newOuter
|
prevOuter = newOuter
|
||||||
innerHandle()
|
innerHandle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ooa onChange outerHandle
|
ooa onChange outerHandle()
|
||||||
|
|
||||||
prop
|
prop
|
||||||
}
|
}
|
||||||
@ -159,7 +159,7 @@ private object ObservableImplicits {
|
|||||||
prevValue = newVal
|
prevValue = newVal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var innerSub = oa() onChange innerHandle
|
var innerSub = oa() onChange innerHandle()
|
||||||
|
|
||||||
var prevOuter = oa()
|
var prevOuter = oa()
|
||||||
def outerHandle() = prop.synchronized {
|
def outerHandle() = prop.synchronized {
|
||||||
@ -167,13 +167,13 @@ private object ObservableImplicits {
|
|||||||
/* We need reference equality here: we're subscribing to a specific object. */
|
/* We need reference equality here: we're subscribing to a specific object. */
|
||||||
if (prevOuter ne newOuter) {
|
if (prevOuter ne newOuter) {
|
||||||
innerSub.cancel()
|
innerSub.cancel()
|
||||||
innerSub = newOuter onChange innerHandle
|
innerSub = newOuter onChange innerHandle()
|
||||||
prevOuter = newOuter
|
prevOuter = newOuter
|
||||||
innerHandle()
|
innerHandle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ooa onChange outerHandle
|
ooa onChange outerHandle()
|
||||||
|
|
||||||
prop
|
prop
|
||||||
}
|
}
|
||||||
@ -218,6 +218,8 @@ final class RichObservable[A, C](val self: ObservableValue[A, C]) extends AnyVal
|
|||||||
def tuple[B](f: Observable[B]): Observable[(A,B)] = oapp.tuple2(self, f)
|
def tuple[B](f: Observable[B]): Observable[(A,B)] = oapp.tuple2(self, f)
|
||||||
final def *>[B](fb: ObjObs[B]): Observable[B] = oapp.map2(self,fb)((_,b) => b)
|
final def *>[B](fb: ObjObs[B]): Observable[B] = oapp.map2(self,fb)((_,b) => b)
|
||||||
final def <*[B](fb: ObjObs[B]): Observable[A] = oapp.map2(self,fb)((a,_) => a)
|
final def <*[B](fb: ObjObs[B]): Observable[A] = oapp.map2(self,fb)((a,_) => a)
|
||||||
|
final def >>[B](fb: => ObjObs[B]): Observable[B] = oapp.map2(self, fb)((_, b) => b)
|
||||||
|
final def <<[B](fb: => ObjObs[B]): Observable[A] = oapp.map2(self, fb)((a, _) => a)
|
||||||
|
|
||||||
final def |@|[B, B1](fb: ObservableValue[B, B1]) = ObservableTupler(self, fb)
|
final def |@|[B, B1](fb: ObservableValue[B, B1]) = ObservableTupler(self, fb)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package org.gerweck.scalafx.util
|
package org.gerweck.scalafx.util
|
||||||
|
|
||||||
import scala.compat.java8.FunctionConverters._
|
// import scala.compat.java8.FunctionConverters._
|
||||||
|
|
||||||
import java.util.function.{ Predicate => JPredicate }
|
import java.util.function.{ Predicate => JPredicate }
|
||||||
|
|
||||||
@ -58,9 +58,9 @@ final class RichObservableBuffer[A](val obs: ObservableBuffer[A]) extends AnyVal
|
|||||||
fb.predicate <== predicate
|
fb.predicate <== predicate
|
||||||
fb
|
fb
|
||||||
}
|
}
|
||||||
def observeFiltered[B >: A](predicate: Observable[B => Boolean]): FilteredBuffer[A] = {
|
// def observeFiltered[B >: A](predicate: Observable[B => Boolean]): FilteredBuffer[A] = {
|
||||||
observeFiltered(predicate.map[JPredicate[A]](asJavaPredicate))
|
// observeFiltered(predicate.map[JPredicate[A]](asJavaPredicate))
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
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] {
|
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] {
|
||||||
|
@ -1,62 +1,62 @@
|
|||||||
package org.gerweck.scalafx.util
|
// package org.gerweck.scalafx.util
|
||||||
package prefs
|
// package prefs
|
||||||
|
|
||||||
import java.util.prefs._
|
// import java.util.prefs._
|
||||||
|
|
||||||
import scalafx.application.Platform.runLater
|
// import scalafx.application.Platform.runLater
|
||||||
import scalafx.beans.property.ObjectProperty
|
// import scalafx.beans.property.ObjectProperty
|
||||||
|
|
||||||
import org.gerweck.scala.util.prefs._
|
// import org.gerweck.scala.util.prefs._
|
||||||
|
|
||||||
/* TODO: take an implicit that will deteremine whether this is an `ObjectProperty` or what */
|
// /* TODO: take an implicit that will deteremine whether this is an `ObjectProperty` or what */
|
||||||
class ObservablePref[A] protected (path: String)(implicit handler: Pref.AccessHandler[A], prefs: Preferences)
|
// class ObservablePref[A] protected (path: String)(implicit handler: Pref.AccessHandler[A], prefs: Preferences)
|
||||||
extends Pref[A](path) { thisPref =>
|
// extends Pref[A](path) { thisPref =>
|
||||||
|
|
||||||
lazy val observe: ObjectProperty[A] = {
|
// lazy val observe: ObjectProperty[A] = {
|
||||||
val initialValue: A = this()
|
// val initialValue: A = this()
|
||||||
val property = ObjectProperty[A](initialValue)
|
// val property = ObjectProperty[A](initialValue)
|
||||||
|
|
||||||
/* We build two bridges, one that listens for changes in the preferences system and pushes
|
// /* We build two bridges, one that listens for changes in the preferences system and pushes
|
||||||
* them into the observable property, and another that listens for updates to the property and
|
// * them into the observable property, and another that listens for updates to the property and
|
||||||
* pushes them to the preference system. Each bridge is gated so that it only activates if the
|
// * pushes them to the preference system. Each bridge is gated so that it only activates if the
|
||||||
* value has actually changed, which prevents the infinite looping that would otherwise occur
|
// * value has actually changed, which prevents the infinite looping that would otherwise occur
|
||||||
* in a bidirectional bridge. */
|
// * in a bidirectional bridge. */
|
||||||
|
|
||||||
/* Preferences => Property bridge */
|
// /* Preferences => Property bridge */
|
||||||
|
|
||||||
/* In Scala 2.12, the callback could just be bare inside `addPreferenceChangeListener`.
|
// /* In Scala 2.12, the callback could just be bare inside `addPreferenceChangeListener`.
|
||||||
* However, it must be created explicitly since we cross-compile against Scala 2.11. */
|
// * However, it must be created explicitly since we cross-compile against Scala 2.11. */
|
||||||
val changeListener = new PreferenceChangeListener {
|
// val changeListener = new PreferenceChangeListener {
|
||||||
def preferenceChange(pce: PreferenceChangeEvent): Unit = {
|
// def preferenceChange(pce: PreferenceChangeEvent): Unit = {
|
||||||
if (pce.getKey == path) {
|
// if (pce.getKey == path) {
|
||||||
runLater {
|
// runLater {
|
||||||
val currentValue = thisPref()
|
// val currentValue = thisPref()
|
||||||
if (property.value != currentValue) {
|
// if (property.value != currentValue) {
|
||||||
property.value = currentValue
|
// property.value = currentValue
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
prefs.addPreferenceChangeListener(changeListener)
|
// prefs.addPreferenceChangeListener(changeListener)
|
||||||
|
|
||||||
/* Property => Preferences bridge */
|
// /* Property => Preferences bridge */
|
||||||
property.onChange { (_, _, newV) =>
|
// property.onChange { (_, _, newV) =>
|
||||||
if (newV != this()) {
|
// if (newV != this()) {
|
||||||
this() = newV
|
// this() = newV
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/* Return the bridged property */
|
// /* Return the bridged property */
|
||||||
property
|
// property
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
object ObservablePref {
|
// object ObservablePref {
|
||||||
def apply[A](path: String)(implicit handler: PrefHandler[A], prefs: Preferences) = {
|
// def apply[A](path: String)(implicit handler: PrefHandler[A], prefs: Preferences) = {
|
||||||
new ObservablePref(path)(new Pref.AccessHandler.Optional, prefs)
|
// new ObservablePref(path)(new Pref.AccessHandler.Optional, prefs)
|
||||||
}
|
// }
|
||||||
def apply[A](path: String, default: A)(implicit handler: PrefHandler[A], prefs: Preferences) = {
|
// def apply[A](path: String, default: A)(implicit handler: PrefHandler[A], prefs: Preferences) = {
|
||||||
new ObservablePref(path)(new Pref.AccessHandler.Defaulted(default), prefs)
|
// new ObservablePref(path)(new Pref.AccessHandler.Defaulted(default), prefs)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@ -1 +1 @@
|
|||||||
version in ThisBuild := "0.14.4-SNAPSHOT"
|
version in ThisBuild := "0.15.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user