Skip to content

Package: JavaFXApplicationWithSplash

JavaFXApplicationWithSplash

nameinstructionbranchcomplexitylinemethod
JavaFXApplicationWithSplash()
M: 0 C: 13
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
configureFullScreen(Stage)
M: 17 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
createScene(Parent)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
init()
M: 18 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
initialize(Stage, Stage, long)
M: 12 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
lambda$initialize$1(WindowEvent)
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$initialize$2(ActionEvent)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$initialize$3(Stage, Stage, long)
M: 100 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 21 C: 0
0%
M: 1 C: 0
0%
lambda$start$0(Stage, Stage, long)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
onClosing()
M: 1 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
onStageCreated(Stage, NodeAndDelegate)
M: 1 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
start(Stage)
M: 75 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 16 C: 0
0%
M: 1 C: 0
0%
static {...}
M: 0 C: 28
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 7
100%
M: 0 C: 1
100%

Coverage

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.Executors;
30: import java.io.IOException;
31: import javafx.animation.KeyFrame;
32: import javafx.animation.Timeline;
33: import javafx.scene.Parent;
34: import javafx.scene.Scene;
35: import javafx.scene.input.KeyCombination;
36: import javafx.stage.Screen;
37: import javafx.stage.Stage;
38: import javafx.stage.StageStyle;
39: import javafx.util.Duration;
40: import javafx.application.Application;
41: import javafx.application.Platform;
42: import org.slf4j.Logger;
43: import org.slf4j.LoggerFactory;
44: import it.tidalwave.util.Key;
45: import it.tidalwave.util.PreferencesHandler;
46: import lombok.Getter;
47: import lombok.Setter;
48:
49: /***************************************************************************************************************************************************************
50: *
51: * @author Fabrizio Giudici
52: *
53: **************************************************************************************************************************************************************/
54: public abstract class JavaFXApplicationWithSplash extends Application
55: {
56: private static final String K_BASE_NAME = "it.tidalwave.ui.javafx";
57:
58: /** A property representing the initial main window size as a percentual of the screen size. */
59: public static final Key<Double> K_INITIAL_SIZE = Key.of(K_BASE_NAME + ".initialSize", Double.class);
60:
61: /** Whether the application should start maximized. */
62: public static final Key<Boolean> K_MAXIMIZED = Key.of(K_BASE_NAME + ".maximized", Boolean.class);
63:
64: /** Whether the application should start at full screen. */
65: public static final Key<Boolean> K_FULL_SCREEN = Key.of(K_BASE_NAME + ".fullScreen", Boolean.class);
66:
67: /** Whether the application should always stay at full screen. */
68: public static final Key<Boolean> K_FULL_SCREEN_LOCKED = Key.of(K_BASE_NAME + ".fullScreenLocked", Boolean.class);
69:
70: /** The minimum duration of the splash screen. */
71: public static final Key<Duration> K_MIN_SPLASH_DURATION = Key.of(K_BASE_NAME + ".minSplashDuration", Duration.class);
72:
73: /** Whether invocations to presentation delegate methods should be logged at debug level. */
74: public static final Key<Boolean> K_LOG_DELEGATE_INVOCATIONS = Key.of(K_BASE_NAME + ".logDelegateInvocations", Boolean.class);
75:
76: private static final String DEFAULT_APPLICATION_FXML = "Application.fxml";
77:
78: private static final String DEFAULT_SPLASH_FXML = "Splash.fxml";
79:
80: private static final Duration DEFAULT_MIN_SPLASH_DURATION = Duration.seconds(2);
81:
82: // Don't use Slf4j and its static logger - give Main a chance to initialize things
83: private final Logger log = LoggerFactory.getLogger(JavaFXApplicationWithSplash.class);
84:
85: private Splash splash;
86:
87: private boolean maximized;
88:
89: private boolean fullScreen;
90:
91: private boolean fullScreenLocked;
92:
93: @Getter @Setter
94: protected String applicationFxml = DEFAULT_APPLICATION_FXML;
95:
96: @Getter @Setter
97: protected String splashFxml = DEFAULT_SPLASH_FXML;
98:
99: /***********************************************************************************************************************************************************
100: * {@inheritDoc}
101: **********************************************************************************************************************************************************/
102: @Override
103: public void init()
104: {
105: log.info("init()");
106: splash = new Splash(this, splashFxml, this::createScene);
107: splash.init();
108: }
109:
110: /***********************************************************************************************************************************************************
111: * {@inheritDoc}
112: **********************************************************************************************************************************************************/
113: @Override
114: public void start (@Nonnull final Stage stage)
115: {
116: log.info("start({})", stage);
117: final var preferencesHandler = PreferencesHandler.getInstance();
118: fullScreen = preferencesHandler.getProperty(K_FULL_SCREEN).orElse(false);
119: fullScreenLocked = preferencesHandler.getProperty(K_FULL_SCREEN_LOCKED).orElse(false);
120: maximized = preferencesHandler.getProperty(K_MAXIMIZED).orElse(false);
121:
122: final var splashStage = new Stage(StageStyle.TRANSPARENT);
123: stage.setMaximized(maximized);
124: // splashStage.setMaximized(maximized); FIXME: doesn't work
125: configureFullScreen(stage);
126: // configureFullScreen(splashStage); FIXME: deadlocks JDK 1.8.0_40
127:
128:• if (!maximized && !fullScreen)
129: {
130: splashStage.centerOnScreen();
131: }
132:
133: final var splashCreationTime = System.currentTimeMillis();
134: splash.show(splashStage);
135:
136: // try (final var executor = Executors.newSingleThreadExecutor()) TODO: only since JDK 19
137: // {
138: final var executor = Executors.newSingleThreadExecutor(); // can't use Spring executors, Spring is not yet there
139: executor.execute(() -> initialize(stage, splashStage, splashCreationTime));
140: executor.shutdown();
141: // }
142: }
143:
144: /***********************************************************************************************************************************************************
145: *
146: **********************************************************************************************************************************************************/
147: protected void onStageCreated (@Nonnull final Stage stage, @Nonnull final NodeAndDelegate<?> applicationNad)
148: {
149: }
150:
151: /***********************************************************************************************************************************************************
152: *
153: **********************************************************************************************************************************************************/
154: @Nonnull
155: protected abstract NodeAndDelegate<?> createParent()
156: throws IOException;
157:
158: /***********************************************************************************************************************************************************
159: *
160: **********************************************************************************************************************************************************/
161: protected abstract void initializeInBackground();
162:
163: /***********************************************************************************************************************************************************
164: * Invoked when the main {@link Stage} is being closed. This method is called in the JavaFX thread.
165: **********************************************************************************************************************************************************/
166: protected void onClosing()
167: {
168: }
169:
170: /***********************************************************************************************************************************************************
171: *
172: **********************************************************************************************************************************************************/
173: protected Scene createScene (@Nonnull final Parent parent)
174: {
175: return new Scene(parent);
176: }
177:
178: /***********************************************************************************************************************************************************
179: *
180: **********************************************************************************************************************************************************/
181: private void initialize (@Nonnull final Stage stage, @Nonnull final Stage splashStage, final long splashCreationTime)
182: {
183: Thread.currentThread().setName("initializer");
184: initializeInBackground();
185: Platform.runLater(() ->
186: {
187: try
188: {
189: final var preferencesHandler = PreferencesHandler.getInstance();
190: final var applicationNad = createParent();
191: final var scene = createScene((Parent)applicationNad.getNode());
192: stage.setOnCloseRequest(event -> onClosing());
193: stage.setScene(scene);
194: onStageCreated(stage, applicationNad);
195: stage.setFullScreen(fullScreen);
196: final double scale = preferencesHandler.getProperty(K_INITIAL_SIZE).orElse(0.65);
197: final var screenSize = Screen.getPrimary().getBounds();
198: stage.setWidth(scale * screenSize.getWidth());
199: stage.setHeight(scale * screenSize.getHeight());
200: stage.show();
201: splashStage.toFront();
202:
203: final var duration = preferencesHandler.getProperty(K_MIN_SPLASH_DURATION).orElse(DEFAULT_MIN_SPLASH_DURATION);
204: final var delay = Math.max(0, splashCreationTime + duration.toMillis() - System.currentTimeMillis());
205: final var dismissSplash = new Timeline(new KeyFrame(Duration.millis(delay), e -> splash.dismiss()));
206: dismissSplash.play();
207: }
208: catch (IOException e)
209: {
210: log.error("", e);
211: }
212: });
213: }
214:
215: /***********************************************************************************************************************************************************
216: *
217: **********************************************************************************************************************************************************/
218: private void configureFullScreen (@Nonnull final Stage stage)
219: {
220: stage.setFullScreen(fullScreen);
221:
222:• if (fullScreen && fullScreenLocked)
223: {
224: stage.setFullScreenExitHint("");
225: stage.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH);
226: }
227: }
228: }