Browse Source
Rewrite `SingletonStage` for safety & power
Rewrite `SingletonStage` for safety & power
Also, add more documentation so this is actually a usable piece of code.master
Sarah Gerweck
7 years ago
1 changed files with 44 additions and 8 deletions
@ -1,39 +1,75 @@ |
|||
package org.gerweck.scalafx.util |
|||
|
|||
import scalafx.beans.property.{ ObjectProperty, ReadOnlyObjectProperty } |
|||
import scalafx.stage.Stage |
|||
|
|||
import org.log4s._ |
|||
|
|||
/** A stage that should only be open at most once per application. */ |
|||
/** A stage that should only be open at most once per application. |
|||
* |
|||
* To use this, you should do something like this: |
|||
* {{{ |
|||
* class AboutWindow extends SingletonStage { |
|||
* type InstanceStage = AboutStage |
|||
* protected[this] def makeStage() = new Stage with AboutStage |
|||
* trait AboutStage extends super.ParentStage { stage => |
|||
* title = "About My Application" |
|||
* scene = new Scene { |
|||
* ??? |
|||
* } |
|||
* } |
|||
* } |
|||
* }}} |
|||
*/ |
|||
abstract class SingletonStage { |
|||
private[this] val logger = getLogger |
|||
|
|||
/** The specific type of the underlying stage that you'll create. */ |
|||
type InstanceStage <: ParentStage |
|||
|
|||
protected[this] final var singletonStage: Option[InstanceStage] = None |
|||
private[this] object State { |
|||
private[this] val stageProp = ObjectProperty(Option.empty[InstanceStage]) |
|||
def currentStage = stageProp.value |
|||
def currentStage_=(stage: Option[InstanceStage]): Unit = { |
|||
stageProp.value = stage |
|||
} |
|||
def stage = stageProp.readOnly |
|||
} |
|||
|
|||
/** Get the current stage (or `None` if it doesn't exist). */ |
|||
def stage: ReadOnlyObjectProperty[Option[InstanceStage]] = State.stage |
|||
|
|||
protected[this] def singletonStageName = getClass.getSimpleName |
|||
|
|||
protected[this] def makeStage(): Stage with InstanceStage |
|||
protected[this] def makeStage(): InstanceStage |
|||
|
|||
/** 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 |
|||
* of event handler, you need to use [[scalafx.application.Platform.runLater]]. |
|||
*/ |
|||
def showStage(): Unit = { |
|||
singletonStage match { |
|||
State.currentStage match { |
|||
case Some(stg) => |
|||
logger.debug("Singleton ${name} stage is already open") |
|||
stg.requestFocus() |
|||
case None => |
|||
val ns = makeStage() |
|||
singletonStage = Some(ns) |
|||
State.currentStage = Some(ns) |
|||
ns.show() |
|||
} |
|||
} |
|||
|
|||
protected[this] trait ParentStage extends Stage { |
|||
require(singletonStage.isEmpty, s"Cannot have two ${singletonStageName} stages") |
|||
require(State.currentStage.isEmpty, s"Cannot have two ${singletonStageName} stages") |
|||
logger.trace(s"Creating singleton ${singletonStageName} stage") |
|||
|
|||
override def close() = { |
|||
singletonStage = None |
|||
/** Override this if you need to provide custom `close` behavior. */ |
|||
protected[this] def onClose(): Unit = () |
|||
|
|||
override final def close() = { |
|||
State.currentStage = None |
|||
onClose() |
|||
super.close() |
|||
} |
|||
} |
|||
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue