Skip to content

Method: lambda$start$1(ActionEvent)

1: /*
2: * *************************************************************************************************************************************************************
3: *
4: * SteelBlue: DCI User Interfaces
5: * http://tidalwave.it/projects/steelblue
6: *
7: * Copyright (C) 2015 - 2025 by Tidalwave s.a.s. (http://tidalwave.it)
8: *
9: * *************************************************************************************************************************************************************
10: *
11: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
12: * You may obtain a copy of the License at
13: *
14: * http://www.apache.org/licenses/LICENSE-2.0
15: *
16: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
17: * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
18: *
19: * *************************************************************************************************************************************************************
20: *
21: * git clone https://bitbucket.org/tidalwave/steelblue-src
22: * git clone https://github.com/tidalwave-it/steelblue-src
23: *
24: * *************************************************************************************************************************************************************
25: */
26: package it.tidalwave.ui.javafx;
27:
28: import jakarta.annotation.Nonnull;
29: import java.util.concurrent.Executor;
30: import java.util.concurrent.Executors;
31: import java.io.IOException;
32: import javafx.animation.KeyFrame;
33: import javafx.animation.Timeline;
34: import javafx.scene.Parent;
35: import javafx.scene.Scene;
36: import javafx.scene.input.KeyCombination;
37: import javafx.stage.Screen;
38: import javafx.stage.Stage;
39: import javafx.stage.StageStyle;
40: import javafx.util.Duration;
41: import javafx.application.Application;
42: import javafx.application.Platform;
43: import org.slf4j.Logger;
44: import org.slf4j.LoggerFactory;
45: import it.tidalwave.util.Key;
46: import it.tidalwave.util.PreferencesHandler;
47: import lombok.Getter;
48: import lombok.Setter;
49:
50: /***************************************************************************************************************************************************************
51: *
52: * @author Fabrizio Giudici
53: *
54: **************************************************************************************************************************************************************/
55: public abstract class JavaFXApplicationWithSplash extends Application
56: {
57: private static final String K_BASE_NAME = "it.tidalwave.ui.javafx";
58:
59: /** A property representing the initial main window size as a percentual of the screen size. */
60: public static final Key<Double> K_INITIAL_SIZE = Key.of(K_BASE_NAME + ".initialSize", Double.class);
61:
62: /** Whether the application should start maximized. */
63: public static final Key<Boolean> K_MAXIMIZED = Key.of(K_BASE_NAME + ".maximized", Boolean.class);
64:
65: /** Whether the application should start at full screen. */
66: public static final Key<Boolean> K_FULL_SCREEN = Key.of(K_BASE_NAME + ".fullScreen", Boolean.class);
67:
68: /** Whether the application should always stay at full screen. */
69: public static final Key<Boolean> K_FULL_SCREEN_LOCKED = Key.of(K_BASE_NAME + ".fullScreenLocked", Boolean.class);
70:
71: /** The minimum duration of the splash screen. */
72: public static final Key<Duration> K_MIN_SPLASH_DURATION = Key.of(K_BASE_NAME + ".minSplashDuration", Duration.class);
73:
74: /** Whether invocations to presentation delegate methods should be logged at debug level. */
75: public static final Key<Boolean> K_LOG_DELEGATE_INVOCATIONS = Key.of(K_BASE_NAME + ".logDelegateInvocations", Boolean.class);
76:
77: private static final String DEFAULT_APPLICATION_FXML = "Application.fxml";
78:
79: private static final String DEFAULT_SPLASH_FXML = "Splash.fxml";
80:
81: private static final Duration DEFAULT_MIN_SPLASH_DURATION = Duration.seconds(2);
82:
83: // Don't use Slf4j and its static logger - give Main a chance to initialize things
84: private final Logger log = LoggerFactory.getLogger(JavaFXApplicationWithSplash.class);
85:
86: private Splash splash;
87:
88: private boolean maximized;
89:
90: private boolean fullScreen;
91:
92: private boolean fullScreenLocked;
93:
94: @Getter @Setter
95: protected String applicationFxml = DEFAULT_APPLICATION_FXML;
96:
97: @Getter @Setter
98: protected String splashFxml = DEFAULT_SPLASH_FXML;
99:
100: /***********************************************************************************************************************************************************
101: * {@inheritDoc}
102: **********************************************************************************************************************************************************/
103: @Override
104: public void init()
105: {
106: log.info("init()");
107: splash = new Splash(this, splashFxml, this::createScene);
108: splash.init();
109: }
110:
111: /***********************************************************************************************************************************************************
112: * {@inheritDoc}
113: **********************************************************************************************************************************************************/
114: @Override
115: public void start (@Nonnull final Stage stage)
116: {
117: log.info("start({})", stage);
118: final var preferencesHandler = PreferencesHandler.getInstance();
119: fullScreen = preferencesHandler.getProperty(K_FULL_SCREEN).orElse(false);
120: fullScreenLocked = preferencesHandler.getProperty(K_FULL_SCREEN_LOCKED).orElse(false);
121: maximized = preferencesHandler.getProperty(K_MAXIMIZED).orElse(false);
122:
123: final var splashStage = new Stage(StageStyle.TRANSPARENT);
124: stage.setMaximized(maximized);
125: // splashStage.setMaximized(maximized); FIXME: doesn't work
126: configureFullScreen(stage);
127: // configureFullScreen(splashStage); FIXME: deadlocks JDK 1.8.0_40
128:
129: if (!maximized && !fullScreen)
130: {
131: splashStage.centerOnScreen();
132: }
133:
134: final var splashCreationTime = System.currentTimeMillis();
135: splash.show(splashStage);
136:
137: getExecutor().execute(() -> // FIXME: use JavaFX Worker?
138: {
139: initializeInBackground();
140: Platform.runLater(() ->
141: {
142: try
143: {
144: final var applicationNad = createParent();
145: final var scene = createScene((Parent)applicationNad.getNode());
146: stage.setOnCloseRequest(event -> onClosing());
147: stage.setScene(scene);
148: onStageCreated(stage, applicationNad);
149: stage.setFullScreen(fullScreen);
150: final double scale = preferencesHandler.getProperty(K_INITIAL_SIZE).orElse(0.65);
151: final var screenSize = Screen.getPrimary().getBounds();
152: stage.setWidth(scale * screenSize.getWidth());
153: stage.setHeight(scale * screenSize.getHeight());
154: stage.show();
155: splashStage.toFront();
156:
157: final var duration = preferencesHandler.getProperty(K_MIN_SPLASH_DURATION).orElse(DEFAULT_MIN_SPLASH_DURATION);
158: final var delay = Math.max(0, splashCreationTime + duration.toMillis() - System.currentTimeMillis());
159: final var dismissSplash = new Timeline(new KeyFrame(Duration.millis(delay), e -> splash.dismiss()));
160: Platform.runLater(dismissSplash::play);
161: }
162: catch (IOException e)
163: {
164: log.error("", e);
165: }
166: });
167: });
168: }
169:
170: /***********************************************************************************************************************************************************
171: *
172: **********************************************************************************************************************************************************/
173: protected void onStageCreated (@Nonnull final Stage stage, @Nonnull final NodeAndDelegate<?> applicationNad)
174: {
175: }
176:
177: /***********************************************************************************************************************************************************
178: *
179: **********************************************************************************************************************************************************/
180: @Nonnull
181: protected abstract NodeAndDelegate<?> createParent()
182: throws IOException;
183:
184: /***********************************************************************************************************************************************************
185: *
186: **********************************************************************************************************************************************************/
187: protected abstract void initializeInBackground();
188:
189: /***********************************************************************************************************************************************************
190: * Invoked when the main {@link Stage} is being closed.
191: **********************************************************************************************************************************************************/
192: protected void onClosing()
193: {
194: }
195:
196: /***********************************************************************************************************************************************************
197: *
198: **********************************************************************************************************************************************************/
199: @Nonnull
200: protected Executor getExecutor()
201: {
202: return Executors.newSingleThreadExecutor();
203: }
204:
205: /***********************************************************************************************************************************************************
206: *
207: **********************************************************************************************************************************************************/
208: protected Scene createScene (@Nonnull final Parent parent)
209: {
210: return new Scene(parent);
211: }
212:
213: /***********************************************************************************************************************************************************
214: *
215: **********************************************************************************************************************************************************/
216: private void configureFullScreen (@Nonnull final Stage stage)
217: {
218: stage.setFullScreen(fullScreen);
219:
220: if (fullScreen && fullScreenLocked)
221: {
222: stage.setFullScreenExitHint("");
223: stage.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH);
224: }
225: }
226: }