All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scalafx.application.JFXApp.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2011-2015, ScalaFX Project
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the ScalaFX Project nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE SCALAFX PROJECT OR ITS CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package scalafx.application

import javafx.application.Application
import javafx.{application => jfxa, stage => jfxs}

import scala.collection.JavaConversions.{mapAsJavaMap, seqAsJavaList}
import scala.collection.mutable.{Buffer, ListBuffer}
import scala.collection.{Map, Seq, mutable}
import scala.language.implicitConversions
import scalafx.application.JFXApp.{Parameters, PrimaryStage}
import scalafx.delegate.SFXDelegate
import scalafx.stage.Stage

object JFXApp {

  var Stage: jfxs.Stage = null
  @deprecated("Prefer Scala naming convention over Java, use `Stage` instead.", "8.0.60-R10")
  def STAGE: jfxs.Stage = Stage
  @deprecated("Prefer Scala naming convention over Java, use `Stage` instead.", "8.0.60-R10")
  def STAGE_=(stage: jfxs.Stage): Unit = Stage = stage

  var ActiveApp: JFXApp = null
  @deprecated("Prefer Scala naming convention over Java, use `ActiveApp` instead.", "8.0.60-R10")
  def ACTIVE_APP: JFXApp = ActiveApp
  @deprecated("Prefer Scala naming convention over Java, use `ActiveApp` instead.", "8.0.60-R10")
  def ACTIVE_APP_=(app: JFXApp): Unit = ActiveApp = app

  private[application] var ActiveJFXApp: jfxa.Application = null

  var AutoShow: Boolean = true
  @deprecated("Prefer Scala naming convention over Java, use `AutoShow` instead.", "8.0.60-R10")
  def AUTO_SHOW: Boolean = true
  @deprecated("Prefer Scala naming convention over Java, use `AutoShow` instead.", "8.0.60-R10")
  def AUTO_SHOW_=(autoShow: Boolean) = AutoShow = true

  /**
    * Regular expression for parsing name/value parameters.
    */
  private val keyValue =
    """^--([A-Za-z_][^=]*?)=(.*)$""".r

  object Parameters {
    implicit def sfxParameters2jfx(p: Parameters): Application.Parameters = if (p != null) p.delegate else null

    /**
      * Creates a new instance of Parameters
      */
    private[application] def apply(arguments: Seq[String]): Parameters =
      if (arguments.isEmpty) EmptyParameters else new ParametersImpl(arguments)

  }

  /**
    * Wraps
    * [[http://docs.oracle.com/javase/8/javafx/api/javafx/application/Application.Parameters.html Application.Parameters]]
    * class.
    */
  abstract class Parameters extends SFXDelegate[jfxa.Application.Parameters] {

    /**
      * Retrieves a read-only map of the named parameters.
      */
    def named: Map[String, String]

    /**
      * Retrieves a read-only list of the raw arguments.
      */
    def raw: Seq[String]

    /**
      * Retrieves a read-only list of the unnamed parameters.
      */
    def unnamed: Seq[String]

  }

  /**
    * Default implementation for Parameters class.
    */
  private[application] class ParametersImpl(arguments: Seq[String]) extends Parameters {

    private var namedArguments: mutable.Map[String, String] = mutable.Map.empty[String, String]
    private var unnamedArguments                            = Buffer.empty[String]
    private var filled                                      = false

    private def parseArguments() {
      if (!filled) {
        arguments.foreach(arg =>
          keyValue.findFirstMatchIn(arg) match {
            case None => unnamedArguments += arg
            case Some(matcher) => namedArguments(matcher.group(1)) = matcher.group(2)
          })
        filled = true
      }
    }

    def raw = arguments

    def named = {
      parseArguments()
      namedArguments
    }

    def unnamed = {
      parseArguments()
      unnamedArguments
    }

    lazy val delegate = new jfxa.Application.Parameters {
      def getRaw = raw
      def getNamed = named
      def getUnnamed = unnamed
    }

  }

  /**
    * Get the user agent stylesheet used by the whole application.
    * This is used to provide default styling for all ui controls and other nodes.
    * A value of null means the platform default stylesheet is being used.
    *
    * NOTE: This method must be called on the JavaFX Application Thread.
    *
    * @return The URL to the stylesheet as a String.
    */
  def userAgentStylesheet: String = jfxa.Application.getUserAgentStylesheet

  /**
    * Set the user agent stylesheet used by the whole application.
    * This is used to provide default styling for all ui controls and other nodes.
    * Each release of JavaFX may have a new default value for this so if you need to guarantee consistency you will
    * need to call this method and choose what default you would like for your application.
    * A value of null will restore the platform default stylesheet.
    * This property can also be set on the command line with -Djavafx.userAgentStylesheetUrl=[URL]
    * Setting it on the command line overrides anything set using this method in code.
    *
    * NOTE: This method must be called on the JavaFX Application Thread.
    *
    * @param url  The URL to the stylesheet as a String.
    */
  def userAgentStylesheet_=(url: String): Unit = jfxa.Application.setUserAgentStylesheet(url)


  /**
    * Empty parameters for an application
    */
  private[application] object EmptyParameters extends Parameters {
    def raw = Seq.empty[String]
    def named = Map.empty[String, String]
    def unnamed = Seq.empty[String]
    lazy val delegate = new jfxa.Application.Parameters {
      def getRaw = raw
      def getNamed = named
      def getUnnamed = unnamed
    }
  }

  /** Simple helper class for construction of primary application stages.
    *
    * The primary stage has to wrap an instance of a JavaFX primary stage created by JavaFX when application
    * is initialized.
    *
    * {{{
    *   object SimpleScalaFXApp extends JFXApp {
    *      stage = new PrimaryStage {
    *        title = "Simple ScalaFX App"
    *        scene = new Scene {
    *          root = new StackPane {
    *            padding = Insets(20)
    *            content = new Rectangle {
    *              width = 200
    *              height = 200
    *              fill = Color.DEEPSKYBLUE
    *            }
    *          }
    *        }
    *      }
    *   }
    * }}}
    */
  class PrimaryStage extends Stage(JFXApp.Stage)

}

/** ScalaFX applications can extend JFXApp to create properly initialized JavaFX applications.
  *
  * On the back end `JFXApp` first calls [[http://docs.oracle.com/javase/8/javafx/api/javafx/application/Application.html#launch javafx.application.Application.launch]] then executes body of its
  * constructor when
  * [[http://docs.oracle.com/javase/8/javafx/api/javafx/application/Application.html#start(javafx.stage.Stage) javafx.application.Application.start(primaryStage:Stage)]]
  * is called. Here is an example use:
  *
  * {{{
  *   object SimpleScalaFXApp extends JFXApp {
  *      stage = new PrimaryStage {
  *        title = "Simple ScalaFX App"
  *        scene = new Scene {
  *          root = new StackPane {
  *            padding = Insets(20)
  *            content = new Rectangle {
  *              width = 200
  *              height = 200
  *              fill = Color.DEEPSKYBLUE
  *            }
  *          }
  *        }
  *      }
  *   }
  * }}}
  *
  */
trait JFXApp extends DelayedInit {

  // Since JFXApp is now a trait, it is immune from the behavior of the DelayedInit marker trait. All JFXApp
  // initialization code is executed immediately, rather than being passed to delayedInit() and executed when init() is
  // called during JavaFX application startup. Put non-essential initialization in main() prior to the application
  // startup.

  /** JFXApp stage must be an instance of [[scalafx.application.JFXApp.PrimaryStage]] to ensure that it
    * actually is a proper wrapper for the primary stage supplied by JavaFX. */
  var stage: PrimaryStage = null

  private var arguments: Seq[String] = _

  /** Buffer code (constructor/initialization code) for all classes & objects that implement JFXApp. This code is
    * passed in through compiler-generated calls to delayedInit. The resulting code is then executed - in the same
    * order - in main. (Note that traits inheriting or mixed in with JFXApp have their initialization performed
    * immediately. See [[scala.DelayedInit]] for more information.
    */
  private val subClassInitCode = new ListBuffer[() => Unit]

  /**
    * Set of parameters for an application
    */
  protected lazy val parameters: Parameters = Parameters(arguments)

  /** Add class/object construction/initialization code to the code execution buffer.
    *
    * This function is called multiple times (by the Scala compiler) with the initialization/construction code of each
    * class and object (but not trait!) that extends JFXApp. This code is buffered until it can be executed in main().
    *
    * @note You are strongly advised not to override this function.
    *
    * @param x Class/object construction code to be buffered for delayed execution.
    */
  def delayedInit(x: => Unit) {
    subClassInitCode += (() => x)
  }

  /** Perform app-related initialization, and execute initialization/construction code for all classes and objects that
    * extend this trait.
    *
    * @note You are strongly advised not to override this function.
    *
    * @param args Command line arguments.
    */
  def main(args: Array[String]) {
    JFXApp.ActiveApp = this
    arguments = args
    // Put any further non-essential initialization here.
    /* Launch the JFX application.
    */
    jfxa.Application.launch(classOf[AppHelper], args: _*)
  }

  /** Perform sub-class initialization when directed to duing application startup.
    *
    * Execute the construction/initialization code of all classes/objects that extend JFXApp, that was earlier passed
    * to delayedInit() by the compiler.
    */
  private[application] final def init(): Unit = for (initCode <- subClassInitCode) initCode()

  def hostServices: HostServices = ApplicationIncludes.jfxHostServices2sfx(JFXApp.ActiveJFXApp.getHostServices)

  /**
    * This method is called when the application should stop, and provides a convenient place to prepare
    * for application exit and destroy resources.
    *
    * It is called from javafx.Application.stop method.
    * The implementation of this method provided by the JFXApp class does nothing.
    *
    * NOTE: This method is called on the JavaFX Application Thread, the same as javafx.Application.stop method.
    */
  def stopApp() {
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy