Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git

save and restore Stage state (window bounds, maximized, fullScreen)

AuthorKarl Tauber <email>
Date2015-07-24 13:15:49 GMT+0200
Commite4c1139cde84789e2f020d18f6974366383d9dd8
Parent07a89ce
Delta127 lines added, 0 lines removed, 127-line increase
src/main/java/org/markdownwriterfx/util/StageState.java
+/*
+ * Copyright (c) 2015 Karl Tauber <karl at jformdesigner dot com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * o 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.
+ *
+ * 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 COPYRIGHT
+ * HOLDER OR 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 org.markdownwriterfx.util;
+
+import java.util.prefs.Preferences;
+import javafx.application.Platform;
+import javafx.scene.shape.Rectangle;
+import javafx.stage.Stage;
+import javafx.stage.WindowEvent;
+
+/**
+ * Saves and restores Stage state (window bounds, maximized, fullScreen).
+ *
+ * @author Karl Tauber
+ */
+public class StageState
+{
+ private final Stage stage;
+ private final Preferences state;
+
+ private Rectangle normalBounds;
+ private boolean runLaterPending;
+
+ public StageState(Stage stage, Preferences state) {
+ this.stage = stage;
+ this.state = state;
+
+ restore();
+
+ stage.addEventHandler(WindowEvent.WINDOW_HIDING, e -> save());
+
+ stage.xProperty().addListener((ob, o, n) -> boundsChanged());
+ stage.yProperty().addListener((ob, o, n) -> boundsChanged());
+ stage.widthProperty().addListener((ob, o, n) -> boundsChanged());
+ stage.heightProperty().addListener((ob, o, n) -> boundsChanged());
+ }
+
+ private void save() {
+ Rectangle bounds = isNormalState() ? getStageBounds() : normalBounds;
+ if (bounds != null) {
+ state.putDouble("windowX", bounds.getX());
+ state.putDouble("windowY", bounds.getY());
+ state.putDouble("windowWidth", bounds.getWidth());
+ state.putDouble("windowHeight", bounds.getHeight());
+ }
+ state.putBoolean("windowMaximized", stage.isMaximized());
+ state.putBoolean("windowFullScreen", stage.isFullScreen());
+ }
+
+ private void restore() {
+ double x = state.getDouble("windowX", Double.NaN);
+ double y = state.getDouble("windowY", Double.NaN);
+ double w = state.getDouble("windowWidth", Double.NaN);
+ double h = state.getDouble("windowHeight", Double.NaN);
+ boolean maximized = state.getBoolean("windowMaximized", false);
+ boolean fullScreen = state.getBoolean("windowFullScreen", false);
+
+ if (!Double.isNaN(x) && !Double.isNaN(y)) {
+ stage.setX(x);
+ stage.setY(y);
+ } // else: default behavior is center on screen
+
+ if (!Double.isNaN(w) && !Double.isNaN(h)) {
+ stage.setWidth(w);
+ stage.setHeight(h);
+ } // else: default behavior is use scene size
+
+ if (fullScreen != stage.isFullScreen())
+ stage.setFullScreen(fullScreen);
+ if (maximized != stage.isMaximized())
+ stage.setMaximized(maximized);
+ }
+
+ /**
+ * Remembers the window bounds when the window
+ * is not iconified, maximized or in fullScreen.
+ */
+ private void boundsChanged() {
+ // avoid too many (and useless) runLater() invocations
+ if (runLaterPending)
+ return;
+ runLaterPending = true;
+
+ // must use runLater() to ensure that change of all properties
+ // (x, y, width, height, iconified, maximized and fullScreen)
+ // has finished
+ Platform.runLater(() -> {
+ runLaterPending = false;
+
+ if (isNormalState())
+ normalBounds = getStageBounds();
+ });
+ }
+
+ private boolean isNormalState() {
+ return !stage.isIconified() && !stage.isMaximized() && !stage.isFullScreen();
+ }
+
+ private Rectangle getStageBounds() {
+ return new Rectangle(stage.getX(), stage.getY(), stage.getWidth(), stage.getHeight());
+ }
+}