001/* 002 * ============================================================================ 003 * Copyright © 2002-2024 by Thomas Thrien. 004 * All Rights Reserved. 005 * ============================================================================ 006 * Licensed to the public under the agreements of the GNU Lesser General Public 007 * License, version 3.0 (the "License"). You may obtain a copy of the License at 008 * 009 * http://www.gnu.org/licenses/lgpl.html 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 014 * License for the specific language governing permissions and limitations 015 * under the License. 016 */ 017 018package org.tquadrat.foundation.fx.beans; 019 020import static org.apiguardian.api.API.Status.STABLE; 021import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument; 022 023import java.util.Optional; 024import java.util.function.BiFunction; 025 026import org.apiguardian.api.API; 027import org.tquadrat.foundation.annotation.ClassVersion; 028import org.tquadrat.foundation.fx.internal.FXUserDataBean; 029import javafx.application.Application; 030import javafx.beans.NamedArg; 031import javafx.scene.Node; 032import javafx.scene.Parent; 033import javafx.scene.Scene; 034import javafx.scene.paint.Paint; 035import javafx.stage.Stage; 036 037/** 038 * <p>{@summary The user data bean for instances of 039 * {@link Scene}.}</p> 040 * <p>A JavaFX {@code Scene} instance allows that arbitrary user data can be 041 * attached to it, using the method 042 * {@link Scene#setUserData(Object)}. 043 * This class provides an extensible container for this kind of data.</p> 044 * <p>Through the methods</p> 045 * <ul> 046 * <li>{@link #setProperty(String, Object) setProperty()}</li> 047 * <li>{@link #getProperty(String) getProperty()}</li> 048 * <li>{@link #removeProperty(String) removeProperty()}</li> 049 * <li>{@link #hasProperty(String) hasProperty()}</li> 050 * </ul> 051 * <p>it is already possible to store any type of data into the user data 052 * bean, but it can be easily extended for additional functionality.</p> 053 * 054 * <h2>{@code createScene()} Factory Methods</h2> 055 * <p>The methods</p> 056 * <ul> 057 * <li>{@link #createScene(Application, Stage, Parent)}</li> 058 * <li>{@link #createScene(Application, Stage, Parent, Paint)}</li> 059 * <li>{@link #createScene(Application, Stage, Parent, double, double)}</li> 060 * <li>{@link #createScene(Application, Stage, Parent, double, double, Paint)}</li> 061 * <li>{@link #createScene(SceneUserData, Stage, Parent)}</li> 062 * <li>{@link #createScene(SceneUserData, Stage, Parent, Paint)}</li> 063 * <li>{@link #createScene(SceneUserData, Stage, Parent, double, double)}</li> 064 * <li>{@link #createScene(SceneUserData, Stage, Parent, double, double, Paint)}</li> 065 * <li>{@link #createScene(Application, Stage, Parent, BiFunction)}</li> 066 * <li>{@link #createScene(Application, Stage, Parent, BiFunction, Paint)}</li> 067 * <li>{@link #createScene(Application, Stage, Parent, BiFunction, double, double)}</li> 068 * <li>{@link #createScene(Application, Stage, Parent, BiFunction, double, double, Paint)}</li> 069 * </ul> 070 * <p>can be used to create a 071 * {@link Scene} 072 * instance together with the user data. Those of the factory methods that do 073 * <i>not</i> have a {@code supplier} argument will use an instance of 074 * {@code SceneUserData} (this class); if you want to use an instance of a 075 * derived class, you have to implement the respective supplier and use one of 076 * the methods that take it.</p> 077 * 078 * @param <A> The class of the JavaFX application. 079 * 080 * @version $Id: SceneUserData.java 1110 2024-03-04 15:26:06Z tquadrat $ 081 * @extauthor Thomas Thrien - thomas.thrien@tquadrat.org 082 * @UMLGraph.link 083 * @since 0.1.0 084 */ 085@ClassVersion( sourceVersion = "$Id: SceneUserData.java 1110 2024-03-04 15:26:06Z tquadrat $" ) 086@API( status = STABLE, since = "0.1.0" ) 087public non-sealed class SceneUserData<A extends Application> extends FXUserDataBean<A> 088{ 089 /*------------*\ 090 ====** Attributes **======================================================= 091 \*------------*/ 092 /** 093 * The stage for this scene; this can be the same as the primary stage 094 * in cases where this scene is that for the application's main window. 095 */ 096 private final Stage m_Stage; 097 098 /*--------------*\ 099 ====** Constructors **===================================================== 100 \*--------------*/ 101 /** 102 * Creates a new {@code SceneUserData} instance. 103 * 104 * @param application The reference for the application's main class. 105 * @param primaryStage The reference for the application's primary 106 * stage. 107 */ 108 public SceneUserData( final A application, @SuppressWarnings( "ParameterNameDiffersFromOverriddenParameter" ) final Stage primaryStage ) 109 { 110 this( application, primaryStage, primaryStage ); 111 } // SceneUserData() 112 113 /** 114 * Creates a new {@code SceneUserData} instance. 115 * 116 * @param application The reference for the application's main class. 117 * @param primaryStage The reference for the application's primary 118 * stage. 119 * @param currentStage The reference to the stage for this scene. 120 */ 121 public SceneUserData( final A application, final Stage primaryStage, final Stage currentStage ) 122 { 123 super( application, primaryStage ); 124 125 m_Stage = requireNonNullArgument( currentStage, "currentStage" ); 126 } // SceneUserData() 127 128 /** 129 * Creates a new {@code SceneUserData} instance and copies the references 130 * for the application, the primary and the current stage from the given 131 * user data bean (usually that from the application's main scene). 132 * 133 * @param userDataBean The template user data bean. 134 * @param currentStage The reference to the stage for this scene. 135 */ 136 @SuppressWarnings( "UseOfConcreteClass" ) 137 public SceneUserData( final SceneUserData<? extends A> userDataBean, final Stage currentStage ) 138 { 139 this( requireNonNullArgument( userDataBean, "userDataBean" ).getApplication(), userDataBean.getPrimaryStage(), currentStage ); 140 userDataBean.getApplicationCSS().ifPresent( this::setApplicationCSS ); 141 } // SceneUserData() 142 143 /*---------*\ 144 ====** Methods **========================================================== 145 \*---------*/ 146 /** 147 * Creates a 148 * {@link Scene} 149 * for a specific root 150 * {@link Node}. 151 * 152 * @param <T> The type of the application's main class. 153 * @param application The reference for the application's main class. 154 * @param primaryStage The reference for the application's primary 155 * stage. 156 * @param root The root node of the scene graph. 157 * @return The new scene instance. 158 */ 159 @API( status = STABLE, since = "0.1.0" ) 160 public static final <T extends Application> Scene createScene( @NamedArg( "application" ) final T application, @NamedArg( "primaryStage" ) final Stage primaryStage, @NamedArg( "root" ) final Parent root ) 161 { 162 final var retValue = createScene( application, primaryStage, root, SceneUserData::new ); 163 164 //---* Done *---------------------------------------------------------- 165 return retValue; 166 } // createScene() 167 168 /** 169 * Creates a 170 * {@link Scene} 171 * for a specific root 172 * {@link Node}. 173 * 174 * @param <T> The type of the application's main class. 175 * @param application The reference for the application's main class. 176 * @param primaryStage The reference for the application's primary 177 * stage. 178 * @param root The root node of the scene graph. 179 * @param supplier The supplier for the {@code SceneUserData} 180 * instance. 181 * @return The new scene instance. 182 */ 183 @API( status = STABLE, since = "0.1.0" ) 184 public static final <T extends Application> Scene createScene( @NamedArg( "application" ) final T application, @NamedArg( "primaryStage" ) final Stage primaryStage, @NamedArg( "root" ) final Parent root, @NamedArg( "supplier") final BiFunction<T, ? super Stage, ? extends SceneUserData<T>> supplier ) 185 { 186 final var userData = requireNonNullArgument( supplier, "supplier" ).apply( requireNonNullArgument( application, "application" ), requireNonNullArgument( primaryStage, "primaryStage" ) ); 187 final var retValue = new Scene( requireNonNullArgument( root, "root" ) ); 188 primaryStage.setScene( retValue ); 189 retValue.setUserData( userData ); 190 191 //---* Done *---------------------------------------------------------- 192 return retValue; 193 } // createScene() 194 195 /** 196 * Creates a 197 * {@link Scene} 198 * for a specific root 199 * {@link Node} 200 * with a specific size. 201 * 202 * @param <T> The type of the application's main class. 203 * @param application The reference for the application's main class. 204 * @param primaryStage The reference for the application's primary 205 * stage. 206 * @param root The root node of the scene graph. 207 * @param width The width of the scene. 208 * @param height The height of the scene. 209 * @return The new scene instance. 210 */ 211 @API( status = STABLE, since = "0.1.0" ) 212 public static final <T extends Application> Scene createScene( @NamedArg( "application" ) final T application, @NamedArg( "primaryStage" ) final Stage primaryStage, @NamedArg( "root" ) final Parent root, @NamedArg( "width" ) final double width, @NamedArg( "height" ) final double height ) 213 { 214 final var retValue = createScene( application, primaryStage, root, SceneUserData::new, width, height ); 215 216 //---* Done *---------------------------------------------------------- 217 return retValue; 218 } // createScene() 219 220 /** 221 * Creates a 222 * {@link Scene} 223 * for a specific root 224 * {@link Node} 225 * with a specific size. 226 * 227 * @param <T> The type of the application's main class. 228 * @param application The reference for the application's main class. 229 * @param primaryStage The reference for the application's primary 230 * stage. 231 * @param root The root node of the scene graph. 232 * @param supplier The supplier for the {@code SceneUserData} 233 * instance. 234 * @param width The width of the scene. 235 * @param height The height of the scene. 236 * @return The new scene instance. 237 */ 238 @SuppressWarnings( "MethodWithTooManyParameters" ) 239 @API( status = STABLE, since = "0.1.0" ) 240 public static final <T extends Application> Scene createScene( @NamedArg( "application" ) final T application, @NamedArg( "primaryStage" ) final Stage primaryStage, @NamedArg( "root" ) final Parent root, @NamedArg( "supplier") final BiFunction<T, ? super Stage, ? extends SceneUserData<T>> supplier, @NamedArg( "width" ) final double width, @NamedArg( "height" ) final double height ) 241 { 242 final var userData = requireNonNullArgument( supplier, "supplier" ).apply( requireNonNullArgument( application, "application" ), requireNonNullArgument( primaryStage, "primaryStage" ) ); 243 final var retValue = new Scene( requireNonNullArgument( root, "root" ), width, height ); 244 primaryStage.setScene( retValue ); 245 retValue.setUserData( userData ); 246 247 //---* Done *---------------------------------------------------------- 248 return retValue; 249 } // createScene() 250 251 /** 252 * Creates a 253 * {@link Scene} 254 * for a specific root 255 * {@link Node} 256 * with a fill. 257 * 258 * @param <T> The type of the application's main class. 259 * @param application The reference for the application's main class. 260 * @param primaryStage The reference for the application's primary 261 * stage. 262 * @param root The root node of the scene graph. 263 * @param fill The fill. 264 * @return The new scene instance. 265 */ 266 @API( status = STABLE, since = "0.1.0" ) 267 public static final <T extends Application> Scene createScene( @NamedArg( "application" ) final T application, @NamedArg( "primaryStage" ) final Stage primaryStage, @NamedArg( "root" ) final Parent root, @NamedArg( value = "fill", defaultValue = "WHITE" ) final Paint fill ) 268 { 269 final var retValue = createScene( application, primaryStage, root, SceneUserData::new, fill ); 270 271 //---* Done *---------------------------------------------------------- 272 return retValue; 273 } // createScene() 274 275 /** 276 * Creates a 277 * {@link Scene} 278 * for a specific root 279 * {@link Node} 280 * with a fill. 281 * 282 * @param <T> The type of the application's main class. 283 * @param application The reference for the application's main class. 284 * @param primaryStage The reference for the application's primary 285 * stage. 286 * @param root The root node of the scene graph. 287 * @param supplier The supplier for the {@code SceneUserData} 288 * instance. 289 * @param fill The fill. 290 * @return The new scene instance. 291 */ 292 @API( status = STABLE, since = "0.1.0" ) 293 public static final <T extends Application> Scene createScene( @NamedArg( "application" ) final T application, @NamedArg( "primaryStage" ) final Stage primaryStage, @NamedArg( "root" ) final Parent root, @NamedArg( "supplier") final BiFunction<T, ? super Stage, ? extends SceneUserData<T>> supplier, @NamedArg( value = "fill", defaultValue = "WHITE" ) final Paint fill ) 294 { 295 final var userData = requireNonNullArgument( supplier, "supplier" ).apply( requireNonNullArgument( application, "application" ), requireNonNullArgument( primaryStage, "primaryStage" ) ); 296 final var retValue = new Scene( requireNonNullArgument( root, "root" ), requireNonNullArgument( fill, "fill" ) ); 297 primaryStage.setScene( retValue ); 298 retValue.setUserData( userData ); 299 300 //---* Done *---------------------------------------------------------- 301 return retValue; 302 } // createScene() 303 304 /** 305 * Creates a 306 * {@link Scene} 307 * for a specific root 308 * {@link Node} 309 * with a specific size and fill. 310 * 311 * @param <T> The type of the application's main class. 312 * @param application The reference for the application's main class. 313 * @param primaryStage The reference for the application's primary 314 * stage. 315 * @param root The root node of the scene graph. 316 * @param width The width of the scene. 317 * @param height The height of the scene. 318 * @param fill The fill. 319 * @return The new scene instance. 320 */ 321 @SuppressWarnings( "MethodWithTooManyParameters" ) 322 @API( status = STABLE, since = "0.1.0" ) 323 public static final <T extends Application> Scene createScene( @NamedArg( "application" ) final T application, @NamedArg( "primaryStage" ) final Stage primaryStage, @NamedArg( "root" ) final Parent root, @NamedArg( "width" ) final double width, @NamedArg( "height" ) final double height, @NamedArg( value = "fill", defaultValue = "WHITE" ) final Paint fill ) 324 { 325 final var retValue = createScene( application, primaryStage, root, SceneUserData::new, width, height, fill ); 326 327 //---* Done *---------------------------------------------------------- 328 return retValue; 329 } // createScene() 330 331 /** 332 * Creates a 333 * {@link Scene} 334 * for a specific root 335 * {@link Node} 336 * with a specific size and fill. 337 * 338 * @param <T> The type of the application's main class. 339 * @param application The reference for the application's main class. 340 * @param primaryStage The reference for the application's primary 341 * stage. 342 * @param root The root node of the scene graph. 343 * @param supplier The supplier for the {@code SceneUserData} 344 * instance. 345 * @param width The width of the scene. 346 * @param height The height of the scene. 347 * @param fill The fill. 348 * @return The new scene instance. 349 */ 350 @SuppressWarnings( "MethodWithTooManyParameters" ) 351 @API( status = STABLE, since = "0.1.0" ) 352 public static final <T extends Application> Scene createScene( @NamedArg( "application" ) final T application, @NamedArg( "primaryStage" ) final Stage primaryStage, @NamedArg( "root" ) final Parent root, @NamedArg( "supplier") final BiFunction<T, ? super Stage, ? extends SceneUserData<T>> supplier, @NamedArg( "width" ) final double width, @NamedArg( "height" ) final double height, @NamedArg( value = "fill", defaultValue = "WHITE" ) final Paint fill ) 353 { 354 final var userData = requireNonNullArgument( supplier, "supplier" ).apply( requireNonNullArgument( application, "application" ), requireNonNullArgument( primaryStage, "primaryStage" ) ); 355 final var retValue = new Scene( requireNonNullArgument( root, "root" ), width, height, requireNonNullArgument( fill, "fill" ) ); 356 primaryStage.setScene( retValue ); 357 retValue.setUserData( userData ); 358 359 //---* Done *---------------------------------------------------------- 360 return retValue; 361 } // createScene() 362 363 /** 364 * Creates a 365 * {@link Scene} 366 * for a specific root 367 * {@link Node}. 368 * 369 * @param <T> The type of the application's main class. 370 * @param templateDataBean The user data from the application's main 371 * scene. 372 * @param currentStage The stage for the current scene. 373 * @param root The root node of the scene graph. 374 * @return The new scene instance. 375 */ 376 @SuppressWarnings( "UseOfConcreteClass" ) 377 @API( status = STABLE, since = "0.1.0" ) 378 public static final <T extends Application> Scene createScene( @NamedArg( "templateDataBean" ) final SceneUserData<T> templateDataBean, @NamedArg( "currentStage" ) final Stage currentStage, @NamedArg( "root" ) final Parent root ) 379 { 380 final var newUserDataBean = new SceneUserData<>( templateDataBean, currentStage ); 381 final var retValue = new Scene( requireNonNullArgument( root, "root" ) ); 382 currentStage.setScene( retValue ); 383 retValue.setUserData( newUserDataBean ); 384 newUserDataBean.getApplicationCSS().ifPresent( u -> retValue.getStylesheets().add( u.toExternalForm() ) ); 385 386 //---* Done *---------------------------------------------------------- 387 return retValue; 388 } // createScene() 389 390 /** 391 * Creates a 392 * {@link Scene} 393 * for a specific root 394 * {@link Node} 395 * with a specific size. 396 * 397 * @param <T> The type of the application's main class. 398 * @param templateDataBean The user data from the application's main 399 * scene. 400 * @param currentStage The stage for the current scene. 401 * @param root The root node of the scene graph. 402 * @param width The width of the scene. 403 * @param height The height of the scene. 404 * @return The new scene instance. 405 */ 406 @SuppressWarnings( "UseOfConcreteClass" ) 407 @API( status = STABLE, since = "0.1.0" ) 408 public static final <T extends Application> Scene createScene( @NamedArg( "templateDataBean" ) final SceneUserData<T> templateDataBean, @NamedArg( "currentStage" ) final Stage currentStage, @NamedArg( "root" ) final Parent root, @NamedArg( "width" ) final double width, @NamedArg( "height" ) final double height ) 409 { 410 final var newUserDataBean = new SceneUserData<>( templateDataBean, currentStage ); 411 final var retValue = new Scene( requireNonNullArgument( root, "root" ), width, height ); 412 currentStage.setScene( retValue ); 413 retValue.setUserData( newUserDataBean ); 414 newUserDataBean.getApplicationCSS().ifPresent( u -> retValue.getStylesheets().add( u.toExternalForm() ) ); 415 416 //---* Done *---------------------------------------------------------- 417 return retValue; 418 } // createScene() 419 420 /** 421 * Creates a 422 * {@link Scene} 423 * for a specific root 424 * {@link Node} 425 * with a fill. 426 * 427 * @param <T> The type of the application's main class. 428 * @param templateDataBean The user data from the application's main scene. 429 * @param currentStage The stage for the current scene. 430 * @param root The root node of the scene graph. 431 * @param fill The fill. 432 * @return The new scene instance. 433 */ 434 @SuppressWarnings( "UseOfConcreteClass" ) 435 @API( status = STABLE, since = "0.1.0" ) 436 public static final <T extends Application> Scene createScene( @NamedArg( "templateDataBean" ) final SceneUserData<T> templateDataBean, @NamedArg( "currentStage" ) final Stage currentStage, @NamedArg( "root" ) final Parent root, @NamedArg( value = "fill", defaultValue = "WHITE" ) final Paint fill ) 437 { 438 final var newUserDataBean = new SceneUserData<>( templateDataBean, currentStage ); 439 final var retValue = new Scene( requireNonNullArgument( root, "root" ), requireNonNullArgument( fill, "fill" ) ); 440 currentStage.setScene( retValue ); 441 retValue.setUserData( newUserDataBean ); 442 newUserDataBean.getApplicationCSS().ifPresent( u -> retValue.getStylesheets().add( u.toExternalForm() ) ); 443 444 //---* Done *---------------------------------------------------------- 445 return retValue; 446 } // createScene() 447 448 /** 449 * Creates a 450 * {@link Scene} 451 * for a specific root 452 * {@link Node} 453 * with a specific size and fill. 454 * 455 * @param <T> The type of the application's main class. 456 * @param templateDataBean The user data from the application's main scene. 457 * @param currentStage The stage for the current scene. 458 * @param root The root node of the scene graph. 459 * @param width The width of the scene. 460 * @param height The height of the scene. 461 * @param fill The fill. 462 * @return The new scene instance. 463 */ 464 @SuppressWarnings( {"UseOfConcreteClass", "MethodWithTooManyParameters"} ) 465 @API( status = STABLE, since = "0.1.0" ) 466 public static final <T extends Application> Scene createScene( @NamedArg( "templateDataBean" ) final SceneUserData<T> templateDataBean, @NamedArg( "currentStage" ) final Stage currentStage, @NamedArg( "root" ) final Parent root, @NamedArg( "width" ) final double width, @NamedArg( "height" ) final double height, @NamedArg( value = "fill", defaultValue = "WHITE" ) final Paint fill ) 467 { 468 final var newUserDataBean = new SceneUserData<>( templateDataBean, currentStage ); 469 final var retValue = new Scene( requireNonNullArgument( root, "root" ), width, height, requireNonNullArgument( fill, "fill" ) ); 470 currentStage.setScene( retValue ); 471 retValue.setUserData( newUserDataBean ); 472 newUserDataBean.getApplicationCSS().ifPresent( u -> retValue.getStylesheets().add( u.toExternalForm() ) ); 473 474 //---* Done *---------------------------------------------------------- 475 return retValue; 476 } // createScene() 477 478 /** 479 * Returns the stage for the current scene. If the current scene is the 480 * application's main scene, the returned stage is the primary stage, so 481 * that in this case 482 * {@link #getPrimaryStage()} 483 * will return the same value as this method. 484 * 485 * @return The stage for the current scene. 486 */ 487 public final Stage getStage() { return m_Stage; } 488 489 /** 490 * Retrieves the user data from the given instance of 491 * {@link Scene}. 492 * 493 * @param <T> The type of the application's main class. 494 * @param scene The scene. 495 * @param applicationClass The type of the application's main class. 496 * @return An instance of 497 * {@link Optional} 498 * that holds the user data instance. 499 */ 500 public static final <T extends Application> Optional<SceneUserData<T>> retrieveUserData( final Scene scene, final Class<T> applicationClass ) 501 { 502 Optional<SceneUserData<T>> retValue = Optional.empty(); 503 final var userData = requireNonNullArgument( scene, "scene" ).getUserData(); 504 //noinspection rawtypes 505 if( userData instanceof final SceneUserData userDataBean ) 506 { 507 final var app = userDataBean.getApplication(); 508 if( applicationClass.isInstance( app ) ) 509 { 510 @SuppressWarnings( "unchecked" ) 511 final var data = (SceneUserData<T>) userData; 512 retValue = Optional.of( data ); 513 } 514 } 515 516 //---* Done *---------------------------------------------------------- 517 return retValue; 518 } // retrieveUserData() 519} 520// class SceneUserData 521 522/* 523 * End of File 524 */