From c74c748a441c9fe6b991e7780c790a7f5b46be1e Mon Sep 17 00:00:00 2001 From: Sarah Gerweck Date: Wed, 15 Apr 2015 00:03:35 -0700 Subject: [PATCH] Add some new magic object builders. --- .../org/gerweck/scalafx/util/Parseable.scala | 35 +++++++++++ .../scalafx/util/ParsedTextField.scala | 39 ++++++++++++ .../scalafx/util/PropertyBuilder.scala | 63 +++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 src/main/scala/org/gerweck/scalafx/util/Parseable.scala create mode 100644 src/main/scala/org/gerweck/scalafx/util/ParsedTextField.scala create mode 100644 src/main/scala/org/gerweck/scalafx/util/PropertyBuilder.scala diff --git a/src/main/scala/org/gerweck/scalafx/util/Parseable.scala b/src/main/scala/org/gerweck/scalafx/util/Parseable.scala new file mode 100644 index 0000000..f9989bf --- /dev/null +++ b/src/main/scala/org/gerweck/scalafx/util/Parseable.scala @@ -0,0 +1,35 @@ +/* + * Copyright AtScale, Inc. 2015. All Rights Reserved. + * + * No part of this project or any of its contents may be reproduced, copied, + * modified or adapted, without the prior written consent of AtScale, Inc.. + */ + +package org.gerweck.scalafx.util + +/** A property that can be parsed from a TextField. + * + * @author Sarah Gerweck + */ +trait Parseable[A] { + val builder: PropertyBuilder[A] + + type Prop = builder.Prop + + def toString(a: A): String = a.toString + def fromString(s: String): A + + def makeNew(default: A) = builder.makeNew(default) +} + +object Parseable { + private[this] def parseable[A](from: String => A)(implicit build: PropertyBuilder[A]) = new Parseable[A] { + val builder = build + def fromString(s: String): A = from(s) + } + implicit val IntParseable = parseable[Int](_.toInt) + implicit val LongParseable = parseable[Long](_.toLong) + implicit val FloatParseable = parseable[Float](_.toFloat) + implicit val DoubleParseable = parseable[Double](_.toDouble) + implicit val BooleanParseable = parseable[Boolean](_.toBoolean) +} diff --git a/src/main/scala/org/gerweck/scalafx/util/ParsedTextField.scala b/src/main/scala/org/gerweck/scalafx/util/ParsedTextField.scala new file mode 100644 index 0000000..50ab109 --- /dev/null +++ b/src/main/scala/org/gerweck/scalafx/util/ParsedTextField.scala @@ -0,0 +1,39 @@ +/* + * Copyright AtScale, Inc. 2015. All Rights Reserved. + * + * No part of this project or any of its contents may be reproduced, copied, + * modified or adapted, without the prior written consent of AtScale, Inc.. + */ + +package org.gerweck.scalafx.util + +import scalafx.scene.control.TextField + +import org.log4s._ + +/** + * + * @author Sarah Gerweck + */ +class ParsedTextField[A,B <: Parseable[A]](default: A)(implicit val parser: B) { + + private val logger = getLogger("org.gerweck.scalafx.util.ParsedTextField") + + val field = new TextField + val property: parser.Prop = parser.makeNew(default) + + field.text = parser.toString(default) + + field.text onChange { + val s: String = field.text() + try { + property.value = parser.fromString(s) + } catch { + case nfe: IllegalArgumentException => + // This is pretty normal while you're entering text: no need to make it loud + logger.trace(s"String doesn't parse successfully: $s") + case re: RuntimeException => + logger.warn(re)(s"Error while parsing string: $s") + } + } +} diff --git a/src/main/scala/org/gerweck/scalafx/util/PropertyBuilder.scala b/src/main/scala/org/gerweck/scalafx/util/PropertyBuilder.scala new file mode 100644 index 0000000..fc0ec17 --- /dev/null +++ b/src/main/scala/org/gerweck/scalafx/util/PropertyBuilder.scala @@ -0,0 +1,63 @@ +/* + * Copyright AtScale, Inc. 2015. All Rights Reserved. + * + * No part of this project or any of its contents may be reproduced, copied, + * modified or adapted, without the prior written consent of AtScale, Inc.. + */ + +package org.gerweck.scalafx.util + +import scalafx.beans.property._ + +/** A property builder is something that knows how to build a JavaFX Property + * for a given type of object. + * + * @author Sarah Gerweck + */ +trait PropertyBuilder[A] { + type Prop <: Property[A, _] + def makeNew(default: A): Prop +} + +sealed trait PropertyBuilderLP { + implicit def objectPropertyBuilder[A]: PropertyBuilder[A] = new PropertyBuilder[A] { + type Prop = ObjectProperty[A] + def makeNew(default: A) = ObjectProperty[A](default) + } +} + +object PropertyBuilder extends PropertyBuilderLP { + implicit object IntPropertyBuilder extends PropertyBuilder[Int] { + type Prop = IntegerProperty + def makeNew(default: Int) = IntegerProperty(default) + } + implicit object LongPropertyBuilder extends PropertyBuilder[Long] { + type Prop = LongProperty + def makeNew(default: Long) = LongProperty(default) + } + implicit object FloatPropertyBuilder extends PropertyBuilder[Float] { + type Prop = FloatProperty + def makeNew(default: Float) = FloatProperty(default) + } + implicit object DoublePropertyBuilder extends PropertyBuilder[Double] { + type Prop = DoubleProperty + def makeNew(default: Double) = DoubleProperty(default) + } + implicit object BooleanPropertyBuilder extends PropertyBuilder[Boolean] { + type Prop = BooleanProperty + def makeNew(default: Boolean) = BooleanProperty(default) + } + implicit object StringPropertyBuilder extends PropertyBuilder[String] { + type Prop = StringProperty + def makeNew(default: String) = StringProperty(default) + } + + def apply[A](default: A)(implicit builder: PropertyBuilder[A]): Property[A, _] = { + builder.makeNew(default) + } + + val a = this(1) + val b = this("hello") + val c = this(Set(1, 2)) + val d = this(false) +}