You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

76 lines
2.3 KiB

  1. package org.gerweck.scalafx.util
  2. import scalafx.beans.property.{ ObjectProperty, ReadOnlyObjectProperty }
  3. import scalafx.stage.Stage
  4. import org.log4s._
  5. /** A stage that should only be open at most once per application.
  6. *
  7. * To use this, you should do something like this:
  8. * {{{
  9. * class AboutWindow extends SingletonStage {
  10. * type InstanceStage = AboutStage
  11. * protected[this] def makeStage() = new Stage with AboutStage
  12. * trait AboutStage extends super.ParentStage { stage =>
  13. * title = "About My Application"
  14. * scene = new Scene {
  15. * ???
  16. * }
  17. * }
  18. * }
  19. * }}}
  20. */
  21. abstract class SingletonStage {
  22. private[this] val logger = getLogger
  23. /** The specific type of the underlying stage that you'll create. */
  24. type InstanceStage <: ParentStage
  25. private[this] object State {
  26. private[this] val stageProp = ObjectProperty(Option.empty[InstanceStage])
  27. def currentStage = stageProp.value
  28. def currentStage_=(stage: Option[InstanceStage]): Unit = {
  29. stageProp.value = stage
  30. }
  31. def stage = stageProp.readOnly
  32. }
  33. /** Get the current stage (or `None` if it doesn't exist). */
  34. def stage: ReadOnlyObjectProperty[Option[InstanceStage]] = State.stage
  35. protected[this] def singletonStageName = getClass.getSimpleName
  36. protected[this] def makeStage(): InstanceStage
  37. /** Create the stage, or give it focus if it already exists.
  38. *
  39. * This needs to be executed within the UI thread. If you're not already within some kind
  40. * of event handler, you need to use [[scalafx.application.Platform$.runLater[R](op:=>R):Unit*]].
  41. */
  42. def showStage(): Unit = {
  43. State.currentStage match {
  44. case Some(stg) =>
  45. logger.debug("Singleton ${name} stage is already open")
  46. stg.requestFocus()
  47. case None =>
  48. val ns = makeStage()
  49. State.currentStage = Some(ns)
  50. ns.show()
  51. }
  52. }
  53. protected[this] trait ParentStage extends Stage {
  54. require(State.currentStage.isEmpty, s"Cannot have two ${singletonStageName} stages")
  55. logger.trace(s"Creating singleton ${singletonStageName} stage")
  56. /** Override this if you need to provide custom `close` behavior. */
  57. protected[this] def onClose(): Unit = ()
  58. override final def close() = {
  59. State.currentStage = None
  60. onClose()
  61. super.close()
  62. }
  63. }
  64. }