├── .gitignore
├── src
├── test
│ ├── resources
│ │ ├── mockito-extensions
│ │ │ └── org.mockito.plugins.MockMaker
│ │ └── views
│ │ │ ├── load_view_without_controller.fxml
│ │ │ └── load_view_with_controller.fxml
│ └── java
│ │ └── com
│ │ └── github
│ │ └── spring
│ │ └── boot
│ │ └── javafx
│ │ ├── controllers
│ │ └── MyTestController.java
│ │ ├── stage
│ │ ├── BorderlessStageWrapperTest.java
│ │ └── BorderlessStageTest.java
│ │ ├── TestConfiguration.java
│ │ ├── font
│ │ ├── FontRegistryImplTest.java
│ │ └── controls
│ │ │ ├── IconSolidTest.java
│ │ │ ├── IconRegularTest.java
│ │ │ └── IconTest.java
│ │ ├── JavaFxAutoConfigurationTest.java
│ │ ├── view
│ │ └── ViewLoaderImplTest.java
│ │ └── ui
│ │ └── scale
│ │ └── ScaleAwareImplTest.java
└── main
│ ├── resources
│ ├── META-INF
│ │ └── spring
│ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
│ └── fonts
│ │ ├── fontawesome-regular.ttf
│ │ ├── fontawesome-solid.ttf
│ │ └── fontawesome-webfont.woff
│ └── java
│ └── com
│ └── github
│ └── spring
│ └── boot
│ └── javafx
│ ├── view
│ ├── ViewManagerPolicy.java
│ ├── ViewNotFoundException.java
│ ├── StageNotFoundException.java
│ ├── ViewException.java
│ ├── ViewProperties.java
│ ├── config
│ │ └── ViewConfiguration.java
│ ├── ViewManager.java
│ ├── ViewLoader.java
│ ├── ViewManagerImpl.java
│ └── ViewLoaderImpl.java
│ ├── text
│ ├── Message.java
│ ├── config
│ │ └── LocaleTextConfiguration.java
│ ├── LocaleText.java
│ └── LocaleTextImpl.java
│ ├── font
│ ├── FontException.java
│ ├── FontRegistry.java
│ ├── config
│ │ └── FontConfiguration.java
│ ├── FontRegistryImpl.java
│ └── controls
│ │ ├── AbstractIcon.java
│ │ ├── IconRegular.java
│ │ └── Icon.java
│ ├── ui
│ ├── scale
│ │ ├── MissingScaleAwarePropertyException.java
│ │ ├── ScaleAware.java
│ │ └── ScaleAwareImpl.java
│ ├── stage
│ │ └── StageAware.java
│ └── size
│ │ └── SizeAware.java
│ ├── stage
│ ├── InvalidStageException.java
│ ├── BorderlessStage.java
│ └── BorderlessStageWrapper.java
│ ├── stereotype
│ └── ViewController.java
│ ├── JavaFxAutoConfiguration.java
│ └── SpringJavaFXApplication.java
├── .github
└── workflows
│ └── build.yml
├── README.md
├── pom.xml
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | target/
3 |
4 | **/*.iml
--------------------------------------------------------------------------------
/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker:
--------------------------------------------------------------------------------
1 | mock-maker-inline
--------------------------------------------------------------------------------
/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:
--------------------------------------------------------------------------------
1 | com.github.spring.boot.javafx.JavaFxAutoConfiguration
--------------------------------------------------------------------------------
/src/main/resources/fonts/fontawesome-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yoep/spring-boot-starter-javafx/HEAD/src/main/resources/fonts/fontawesome-regular.ttf
--------------------------------------------------------------------------------
/src/main/resources/fonts/fontawesome-solid.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yoep/spring-boot-starter-javafx/HEAD/src/main/resources/fonts/fontawesome-solid.ttf
--------------------------------------------------------------------------------
/src/main/resources/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yoep/spring-boot-starter-javafx/HEAD/src/main/resources/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/view/ViewManagerPolicy.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.view;
2 |
3 | public enum ViewManagerPolicy {
4 | CLOSEABLE,
5 | BLOCKED
6 | }
7 |
--------------------------------------------------------------------------------
/src/test/resources/views/load_view_without_controller.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/text/Message.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.text;
2 |
3 | /**
4 | * Defines a message resource for {@link LocaleText}.
5 | */
6 | public interface Message {
7 | /**
8 | * Get the key of the message.
9 | *
10 | * @return Returns the message key.
11 | */
12 | String getKey();
13 | }
14 |
--------------------------------------------------------------------------------
/src/test/resources/views/load_view_with_controller.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/font/FontException.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.font;
2 |
3 | import lombok.Getter;
4 |
5 | @Getter
6 | public class FontException extends RuntimeException {
7 | private String filename;
8 |
9 | public FontException(String filename) {
10 | super("An error occurred while loading font file " + filename);
11 | this.filename = filename;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/ui/scale/MissingScaleAwarePropertyException.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.ui.scale;
2 |
3 | /**
4 | * Defines the exception that the scale aware scene is missing from the controller at initialization.
5 | */
6 | public class MissingScaleAwarePropertyException extends RuntimeException {
7 | public MissingScaleAwarePropertyException() {
8 | super("Missing scene to execute scale aware logic");
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/test/java/com/github/spring/boot/javafx/controllers/MyTestController.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.controllers;
2 |
3 | import com.github.spring.boot.javafx.stereotype.ViewController;
4 | import javafx.fxml.FXML;
5 | import javafx.scene.layout.Pane;
6 | import lombok.Data;
7 | import lombok.EqualsAndHashCode;
8 | import lombok.ToString;
9 |
10 | @Data
11 | @ToString
12 | @EqualsAndHashCode
13 | @ViewController
14 | public class MyTestController {
15 | @FXML
16 | Pane root;
17 | }
18 |
--------------------------------------------------------------------------------
/src/test/java/com/github/spring/boot/javafx/stage/BorderlessStageWrapperTest.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.stage;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.junit.jupiter.api.Assertions.assertThrows;
6 |
7 | class BorderlessStageWrapperTest {
8 | @Test
9 | void testConstructor_whenStageArgumentIsNull_shouldThrowIllegalArgumentException() {
10 | assertThrows(NullPointerException.class, () -> new BorderlessStageWrapper(null), "stage cannot be null");
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/view/ViewNotFoundException.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.view;
2 |
3 | /**
4 | * Exception indicating that the view doesn't exist or couldn't be found with the given name.
5 | */
6 | public class ViewNotFoundException extends ViewException {
7 | public ViewNotFoundException(String view) {
8 | super(view, "View '" + view + "' not found");
9 | }
10 |
11 | public ViewNotFoundException(String view, Exception ex) {
12 | super(view, "View '" + view + "' not found", ex);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/stage/InvalidStageException.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.stage;
2 |
3 | import javafx.stage.Stage;
4 | import lombok.Getter;
5 |
6 | @Getter
7 | public class InvalidStageException extends RuntimeException {
8 | private final Stage stage;
9 |
10 | public InvalidStageException(Stage stage, String message) {
11 | super(message);
12 | this.stage = stage;
13 | }
14 |
15 | public InvalidStageException(Stage stage, String message, Throwable cause) {
16 | super(message, cause);
17 | this.stage = stage;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/test/java/com/github/spring/boot/javafx/TestConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.ComponentScan;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.context.support.ResourceBundleMessageSource;
7 |
8 | @Configuration
9 | @ComponentScan({
10 | "com.github.spring.boot.javafx.controllers"
11 | })
12 | public class TestConfiguration {
13 | @Bean
14 | public ResourceBundleMessageSource resourceBundleMessageSource() {
15 | return new ResourceBundleMessageSource();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/ui/stage/StageAware.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.ui.stage;
2 |
3 | import javafx.stage.Stage;
4 |
5 | /**
6 | * Defines that a view controller is aware of the stage events, such as the stage being shown/closed.
7 | */
8 | public interface StageAware {
9 | /**
10 | * Is triggered when the stage is shown.
11 | *
12 | * @param stage The stage that triggered the event.
13 | */
14 | void onShown(Stage stage);
15 |
16 | /**
17 | * Is triggered when the stage is closed.
18 | *
19 | * @param stage The stage that triggered the event.
20 | */
21 | void onClosed(Stage stage);
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/view/StageNotFoundException.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.view;
2 |
3 | import lombok.Getter;
4 |
5 | @Getter
6 | public class StageNotFoundException extends RuntimeException {
7 | private final String stageName;
8 | private final boolean primaryStage;
9 |
10 | public StageNotFoundException() {
11 | super("Primary stage couldn't be found");
12 | this.stageName = "primary";
13 | this.primaryStage = false;
14 | }
15 |
16 | public StageNotFoundException(String stageName) {
17 | super("Window '" + stageName + "' couldn't be found");
18 | this.stageName = stageName;
19 | this.primaryStage = false;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/test/java/com/github/spring/boot/javafx/font/FontRegistryImplTest.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.font;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.junit.jupiter.api.Assertions.assertNotNull;
6 |
7 | class FontRegistryImplTest {
8 | @Test
9 | void testGetInstance() {
10 | var result = FontRegistryImpl.getInstance();
11 |
12 | assertNotNull(result, "expected a font registry instance to have been returned");
13 | }
14 |
15 | @Test
16 | void testLoadFont() {
17 | var registry = FontRegistryImpl.getInstance();
18 |
19 | var font = registry.loadFont("fontawesome-regular.ttf");
20 |
21 | assertNotNull(font, "expected a font to have been returned");
22 | }
23 | }
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Maven
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
3 |
4 | name: Build
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | branches: [ master ]
11 | workflow_dispatch:
12 | inputs: {}
13 |
14 | jobs:
15 | test:
16 | name: Test
17 | runs-on: ubuntu-latest
18 |
19 | steps:
20 | - uses: actions/checkout@v2
21 | - name: Set up JDK 17
22 | uses: actions/setup-java@v3
23 | with:
24 | distribution: 'adopt'
25 | java-version: 17
26 | cache: 'maven'
27 | - name: Maven test
28 | run: |
29 | xvfb-run -a mvn -B test
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/view/ViewException.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.view;
2 |
3 | import lombok.Getter;
4 |
5 | /**
6 | * Exception which occurred during the loading of a FXML view.
7 | */
8 | @Getter
9 | public class ViewException extends RuntimeException {
10 | private String view;
11 |
12 | public ViewException(String message) {
13 | super(message);
14 | }
15 |
16 | public ViewException(String view, String message) {
17 | super(message);
18 | this.view = view;
19 | }
20 |
21 | public ViewException(String message, Throwable cause) {
22 | super(message, cause);
23 | }
24 |
25 | public ViewException(String view, String message, Throwable cause) {
26 | super(message, cause);
27 | this.view = view;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/stereotype/ViewController.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.stereotype;
2 |
3 | import org.springframework.core.annotation.AliasFor;
4 | import org.springframework.stereotype.Component;
5 |
6 | import java.lang.annotation.*;
7 |
8 | /**
9 | * Indicates that the annotated class is a "View Controller".
10 | */
11 | @Target({ElementType.TYPE})
12 | @Retention(RetentionPolicy.RUNTIME)
13 | @Documented
14 | @Component
15 | public @interface ViewController {
16 | /**
17 | * The value may indicate a suggestion for a logical component name,
18 | * to be turned into a Spring bean in case of an autodetected component.
19 | * @return the suggested component name, if any (or empty String otherwise)
20 | */
21 | @AliasFor(annotation = Component.class)
22 | String value() default "";
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/ui/size/SizeAware.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.ui.size;
2 |
3 | import javafx.stage.Stage;
4 |
5 | /**
6 | * Defines that the view controller is aware of the size of it's window and can handle size changes within the window.
7 | */
8 | public interface SizeAware {
9 | /**
10 | * Set the initial size of the window.
11 | *
12 | * @param window Set the window to set the size on.
13 | */
14 | void setInitialSize(Stage window);
15 |
16 | /**
17 | * Is triggered when the size of the window is changed.
18 | *
19 | * @param width The new width of the window.
20 | * @param height The new height of the window.
21 | * @param isMaximized The maximized state of the window.
22 | */
23 | void onSizeChange(Number width, Number height, boolean isMaximized);
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/JavaFxAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx;
2 |
3 | import com.github.spring.boot.javafx.font.config.FontConfiguration;
4 | import com.github.spring.boot.javafx.text.config.LocaleTextConfiguration;
5 | import com.github.spring.boot.javafx.view.config.ViewConfiguration;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.context.annotation.Import;
8 |
9 | /**
10 | * Configuration class for auto-configuring JavaFX related beans.
11 | * This class imports other configuration classes responsible for configuring
12 | * fonts, locale text, and views in a JavaFX application.
13 | */
14 | @Configuration
15 | @Import({
16 | FontConfiguration.class,
17 | LocaleTextConfiguration.class,
18 | ViewConfiguration.class
19 | })
20 | public class JavaFxAutoConfiguration {
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/font/FontRegistry.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.font;
2 |
3 | import javafx.scene.text.Font;
4 |
5 | public interface FontRegistry {
6 | /**
7 | * The font directory location.
8 | */
9 | String FONT_DIRECTORY = "/fonts/";
10 |
11 | /**
12 | * Load the given font file and use the size of the system default font.
13 | *
14 | * @param filename The font filename to load from the {@link #FONT_DIRECTORY}.
15 | * @return Returns the loaded font.
16 | */
17 | Font loadFont(String filename);
18 |
19 | /**
20 | * Load the given font file.
21 | *
22 | * @param filename The font filename to load from the {@link #FONT_DIRECTORY}.
23 | * @param size The size of the font.
24 | * @return Returns the loaded font.
25 | */
26 | Font loadFont(String filename, double size);
27 | }
28 |
--------------------------------------------------------------------------------
/src/test/java/com/github/spring/boot/javafx/font/controls/IconSolidTest.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.font.controls;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.junit.jupiter.api.extension.ExtendWith;
5 | import org.testfx.framework.junit5.ApplicationExtension;
6 |
7 | import static org.junit.jupiter.api.Assertions.assertEquals;
8 | import static org.junit.jupiter.api.Assertions.assertTrue;
9 |
10 | @ExtendWith(ApplicationExtension.class)
11 | class IconSolidTest {
12 |
13 | @Test
14 | void testNewInstance() {
15 | var result = new IconSolid();
16 |
17 | assertTrue(result.getStyleClass().contains(AbstractIcon.STYLE_CLASS));
18 | }
19 |
20 | @Test
21 | void testNewInstanceWithUnicode() {
22 | var unicode = IconSolid.AD_UNICODE;
23 |
24 | var result = new IconSolid(unicode);
25 |
26 | assertTrue(result.getStyleClass().contains(AbstractIcon.STYLE_CLASS));
27 | assertEquals(unicode, result.getText());
28 | }
29 | }
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/ui/scale/ScaleAware.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.ui.scale;
2 |
3 | import javafx.scene.Scene;
4 | import javafx.scene.layout.Region;
5 |
6 | /**
7 | * Defines that a view controller is aware of the scale factor and the view is able to be scaled accordingly.
8 | */
9 | public interface ScaleAware {
10 | /**
11 | * Scale the given scene according to the scale factor.
12 | * This method is automatically invoked by the {@link com.github.spring.boot.javafx.view.ViewLoader} when the view is being loaded.
13 | *
14 | * @param scene The current scene to use for scaling.
15 | * @param root The root region of the FXML file.
16 | * @param scale Set the scale of the UI.
17 | */
18 | void scale(Scene scene, Region root, float scale);
19 |
20 | /**
21 | * Invoked when the scene scale is being changed to a new scale factor.
22 | *
23 | * @param newValue The new scale factor.
24 | */
25 | void onScaleChanged(float newValue);
26 | }
27 |
--------------------------------------------------------------------------------
/src/test/java/com/github/spring/boot/javafx/JavaFxAutoConfigurationTest.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx;
2 |
3 | import com.github.spring.boot.javafx.view.ViewLoader;
4 | import com.github.spring.boot.javafx.view.ViewManager;
5 | import org.junit.jupiter.api.Test;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.boot.test.context.SpringBootTest;
8 |
9 | import static org.junit.jupiter.api.Assertions.assertNotNull;
10 |
11 | @SpringBootTest(
12 | classes = {
13 | JavaFxAutoConfiguration.class,
14 | TestConfiguration.class
15 | }
16 | )
17 | class JavaFxAutoConfigurationTest {
18 | @Autowired
19 | private ViewManager viewManager;
20 | @Autowired
21 | private ViewLoader viewLoader;
22 |
23 | @Test
24 | void testAutoConfiguration() {
25 | assertNotNull(viewManager, "expected a view manager to have been created");
26 | assertNotNull(viewLoader, "expected a view loader to have been created");
27 | }
28 | }
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/font/config/FontConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.font.config;
2 |
3 | import com.github.spring.boot.javafx.font.FontRegistry;
4 | import com.github.spring.boot.javafx.font.FontRegistryImpl;
5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 |
9 | /**
10 | * Configuration class for configuring fonts in the application.
11 | * This class provides a bean definition for FontRegistry if one is not already present.
12 | */
13 | @Configuration
14 | public class FontConfiguration {
15 |
16 | /**
17 | * Defines a bean for FontRegistry if no other bean of type FontRegistry is present.
18 | *
19 | * @return the FontRegistry bean instance
20 | */
21 | @Bean
22 | @ConditionalOnMissingBean(FontRegistry.class)
23 | public FontRegistry fontRegistry() {
24 | return FontRegistryImpl.getInstance();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/view/ViewProperties.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.view;
2 |
3 | import javafx.scene.paint.Paint;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Builder;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 |
9 | @Data
10 | @Builder
11 | @NoArgsConstructor
12 | @AllArgsConstructor
13 | public class ViewProperties {
14 | /**
15 | * The title of the window.
16 | */
17 | private String title;
18 | /**
19 | * The icon of the window to show in the title bar or taskbar.
20 | */
21 | private String icon;
22 | /**
23 | * The new window will be set as a dialog on top of the current window.
24 | */
25 | private boolean dialog;
26 | /**
27 | * The indication if the new window should be resizable.
28 | */
29 | @Builder.Default
30 | private boolean resizable = true;
31 | /**
32 | * The indication if the new window will be maximized by default.
33 | */
34 | private boolean maximized;
35 | /**
36 | * The new window will be automatically centered on the primary screen.
37 | */
38 | @Builder.Default
39 | private boolean centerOnScreen = true;
40 | /**
41 | * The default background fill color of the scene.
42 | */
43 | private Paint background;
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/text/config/LocaleTextConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.text.config;
2 |
3 | import com.github.spring.boot.javafx.text.LocaleText;
4 | import com.github.spring.boot.javafx.text.LocaleTextImpl;
5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.context.support.ResourceBundleMessageSource;
9 |
10 | /**
11 | * Configuration class for managing locale-specific text resources.
12 | * This class provides a bean definition for LocaleText if one is not already present,
13 | * using a ResourceBundleMessageSource as the underlying message source.
14 | */
15 | @Configuration
16 | public class LocaleTextConfiguration {
17 |
18 | /**
19 | * Defines a bean for LocaleText if no other bean of type LocaleText is present,
20 | * using the provided ResourceBundleMessageSource as the message source.
21 | *
22 | * @param messageSource the ResourceBundleMessageSource instance to use for managing message sources
23 | * @return the LocaleText bean instance
24 | */
25 | @Bean
26 | @ConditionalOnMissingBean(LocaleText.class)
27 | public LocaleText localeText(ResourceBundleMessageSource messageSource) {
28 | return new LocaleTextImpl(messageSource);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/test/java/com/github/spring/boot/javafx/font/controls/IconRegularTest.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.font.controls;
2 |
3 | import javafx.geometry.Insets;
4 | import org.junit.jupiter.api.Test;
5 | import org.junit.jupiter.api.extension.ExtendWith;
6 | import org.testfx.framework.junit5.ApplicationExtension;
7 |
8 | import static java.util.Arrays.asList;
9 | import static org.junit.jupiter.api.Assertions.*;
10 |
11 | @ExtendWith(ApplicationExtension.class)
12 | class IconRegularTest {
13 |
14 | @Test
15 | void testNewInstance() {
16 | var result = new IconRegular();
17 |
18 | assertTrue(result.getStyleClass().contains(AbstractIcon.STYLE_CLASS));
19 | }
20 |
21 | @Test
22 | void testNewInstanceWithUnicode() {
23 | var unicode = IconRegular.ANGRY_UNICODE;
24 |
25 | var result = new IconRegular(unicode);
26 |
27 | assertTrue(result.getStyleClass().contains(AbstractIcon.STYLE_CLASS));
28 | assertEquals(unicode, result.getText());
29 | }
30 |
31 | @Test
32 | void testNewInstanceWithBuilder() {
33 | var unicode = IconRegular.ANGRY_UNICODE;
34 | var padding = new Insets(12, 20, 30, 40);
35 |
36 | var result = IconRegular.builder()
37 | .unicode(unicode)
38 | .padding(padding)
39 | .visible(false)
40 | .styleClasses(asList("foo", "bar"))
41 | .build();
42 |
43 | assertTrue(result.getStyleClass().contains(AbstractIcon.STYLE_CLASS));
44 | assertEquals(unicode, result.getText());
45 | assertEquals(padding, result.getPadding());
46 | assertFalse(result.isVisible());
47 | assertTrue(result.getStyleClass().contains("foo"));
48 | assertTrue(result.getStyleClass().contains("bar"));
49 | }
50 | }
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/font/FontRegistryImpl.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.font;
2 |
3 | import javafx.scene.text.Font;
4 |
5 | import java.util.HashMap;
6 | import java.util.Map;
7 | import java.util.Objects;
8 | import java.util.Optional;
9 |
10 | /**
11 | * Registry for loading additional fonts into JavaFX.
12 | */
13 | public class FontRegistryImpl implements FontRegistry {
14 | private static final FontRegistryImpl INSTANCE = new FontRegistryImpl();
15 | private final Map loadedFonts = new HashMap<>();
16 |
17 | private FontRegistryImpl() {
18 | }
19 |
20 | /**
21 | * Get the instance of the {@link FontRegistryImpl}.
22 | *
23 | * @return Returns the instance.
24 | */
25 | public static FontRegistryImpl getInstance() {
26 | return INSTANCE;
27 | }
28 |
29 | @Override
30 | public Font loadFont(String filename) {
31 | Objects.requireNonNull(filename, "filename cannot be null");
32 | var defaultFont = Font.getDefault();
33 |
34 | return loadFont(filename, defaultFont.getSize());
35 | }
36 |
37 | @Override
38 | public Font loadFont(String filename, double size) {
39 | Objects.requireNonNull(filename, "filename cannot be null");
40 |
41 | if (loadedFonts.containsKey(filename))
42 | return createFontFromAlreadyLoadedFont(loadedFonts.get(filename), size);
43 |
44 | return loadFontResource(filename, size);
45 | }
46 |
47 | private Font loadFontResource(String filename, double size) {
48 | var resource = getClass().getResource(FONT_DIRECTORY + filename);
49 | var font = Optional.ofNullable(Font.loadFont(resource.toExternalForm(), size))
50 | .orElseThrow(() -> new FontException(filename));
51 |
52 | loadedFonts.put(filename, font);
53 |
54 | return font;
55 | }
56 |
57 | private Font createFontFromAlreadyLoadedFont(Font font, double size) {
58 | return Font.font(font.getFamily(), size);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/test/java/com/github/spring/boot/javafx/stage/BorderlessStageTest.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.stage;
2 |
3 | import javafx.application.Platform;
4 | import org.junit.jupiter.api.Test;
5 | import org.junit.jupiter.api.extension.ExtendWith;
6 | import org.testfx.framework.junit5.ApplicationExtension;
7 | import org.testfx.util.WaitForAsyncUtils;
8 |
9 | import java.util.concurrent.atomic.AtomicReference;
10 |
11 | import static org.junit.jupiter.api.Assertions.assertEquals;
12 |
13 | @ExtendWith(ApplicationExtension.class)
14 | class BorderlessStageTest {
15 | @Test
16 | void testSetHeader() {
17 | var expectedResult = 10.0;
18 | var stage = new AtomicReference();
19 | Platform.runLater(() -> stage.set(new BorderlessStage()));
20 | WaitForAsyncUtils.waitForFxEvents();
21 |
22 | stage.get().setHeader(expectedResult);
23 |
24 | assertEquals(expectedResult, stage.get().getHeader());
25 | }
26 |
27 | @Test
28 | void testHeaderProperty() {
29 | var expectedResult = 15.0;
30 | var stage = new AtomicReference();
31 | var headerHolder = new AtomicReference();
32 | Platform.runLater(() -> stage.set(new BorderlessStage()));
33 | WaitForAsyncUtils.waitForFxEvents();
34 |
35 | stage.get().headerProperty().addListener((observable, oldValue, newValue) -> {
36 | headerHolder.set(newValue.doubleValue());
37 | });
38 | stage.get().setHeader(expectedResult);
39 | WaitForAsyncUtils.waitForFxEvents();
40 |
41 | assertEquals(expectedResult, headerHolder.get());
42 | }
43 |
44 | @Test
45 | void testSetResizeBorder() {
46 | var expectedResult = 5.0;
47 | var stage = new AtomicReference();
48 | Platform.runLater(() -> stage.set(new BorderlessStage()));
49 | WaitForAsyncUtils.waitForFxEvents();
50 |
51 | stage.get().setResizeBorder(expectedResult);
52 |
53 | assertEquals(expectedResult, stage.get().getResizeBorder());
54 | }
55 | }
--------------------------------------------------------------------------------
/src/test/java/com/github/spring/boot/javafx/view/ViewLoaderImplTest.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.view;
2 |
3 | import com.github.spring.boot.javafx.JavaFxAutoConfiguration;
4 | import com.github.spring.boot.javafx.TestConfiguration;
5 | import com.github.spring.boot.javafx.controllers.MyTestController;
6 | import javafx.fxml.FXML;
7 | import javafx.scene.layout.Pane;
8 | import org.junit.jupiter.api.AfterEach;
9 | import org.junit.jupiter.api.Test;
10 | import org.junit.jupiter.api.extension.ExtendWith;
11 | import org.mockito.junit.jupiter.MockitoExtension;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.boot.test.context.SpringBootTest;
14 | import org.testfx.framework.junit5.ApplicationExtension;
15 |
16 | import static org.junit.jupiter.api.Assertions.assertNotNull;
17 |
18 | @SpringBootTest(
19 | classes = {
20 | JavaFxAutoConfiguration.class,
21 | TestConfiguration.class
22 | },
23 | webEnvironment = SpringBootTest.WebEnvironment.NONE
24 | )
25 | @ExtendWith({MockitoExtension.class, ApplicationExtension.class})
26 | public class ViewLoaderImplTest {
27 | @Autowired
28 | ViewLoader viewLoader;
29 | @Autowired
30 | MyTestController controller;
31 |
32 | @AfterEach
33 | void tearDown() {
34 | controller.setRoot(null);
35 | }
36 |
37 | @Test
38 | void testLoadWithoutController() {
39 | var result = viewLoader.load("load_view_with_controller.fxml");
40 |
41 | assertNotNull(result);
42 | assertNotNull(controller.getRoot(), "expected a root node to have been wired");
43 | }
44 |
45 | @Test
46 | void testLoadWithController() {
47 | var controller = new MyController();
48 |
49 | var result = viewLoader.load("load_view_without_controller.fxml", controller);
50 |
51 | assertNotNull(result);
52 | assertNotNull(controller.root, "expected a root node to have been wired");
53 | }
54 |
55 | public static class MyController {
56 | @FXML
57 | Pane root;
58 | }
59 | }
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/view/config/ViewConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.view.config;
2 |
3 | import com.github.spring.boot.javafx.text.LocaleText;
4 | import com.github.spring.boot.javafx.view.ViewLoader;
5 | import com.github.spring.boot.javafx.view.ViewLoaderImpl;
6 | import com.github.spring.boot.javafx.view.ViewManager;
7 | import com.github.spring.boot.javafx.view.ViewManagerImpl;
8 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
9 | import org.springframework.context.ApplicationContext;
10 | import org.springframework.context.ConfigurableApplicationContext;
11 | import org.springframework.context.annotation.Bean;
12 | import org.springframework.context.annotation.Configuration;
13 |
14 | /**
15 | * Configuration class for managing views in the application.
16 | * This class provides bean definitions for ViewLoader and ViewManager
17 | * if no beans of these types are already present.
18 | */
19 | @Configuration
20 | public class ViewConfiguration {
21 |
22 | /**
23 | * Defines a bean for ViewLoader if no other bean of type ViewLoader is present.
24 | *
25 | * @param applicationContext the application context
26 | * @param viewManager the ViewManager instance
27 | * @param localeText the LocaleText instance
28 | * @return the ViewLoader bean instance
29 | */
30 | @Bean
31 | @ConditionalOnMissingBean(ViewLoader.class)
32 | public ViewLoader viewLoader(ApplicationContext applicationContext, ViewManager viewManager, LocaleText localeText) {
33 | return new ViewLoaderImpl(applicationContext, viewManager, localeText);
34 | }
35 |
36 | /**
37 | * Defines a bean for ViewManager if no other bean of type ViewManager is present.
38 | *
39 | * @param applicationContext the configurable application context
40 | * @return the ViewManager bean instance
41 | */
42 | @Bean
43 | @ConditionalOnMissingBean(ViewManager.class)
44 | public ViewManager viewManager(ConfigurableApplicationContext applicationContext) {
45 | return new ViewManagerImpl(applicationContext);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/view/ViewManager.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.view;
2 |
3 | import javafx.beans.property.Property;
4 | import javafx.beans.property.ReadOnlyProperty;
5 | import javafx.scene.Scene;
6 | import javafx.stage.Stage;
7 |
8 | import java.util.Optional;
9 |
10 | public interface ViewManager {
11 | /**
12 | * Get the current policy for the view manager.
13 | *
14 | * @return Returns the current policy.
15 | */
16 | ViewManagerPolicy getPolicy();
17 |
18 | /**
19 | * Get the policy property of the view manager.
20 | *
21 | * @return Returns the policy property.
22 | */
23 | Property policyProperty();
24 |
25 | /**
26 | * Set the policy for the view manager which it follows when all windows are closed.
27 | *
28 | * @param policy Set the policy that needs to be applied.
29 | */
30 | void setPolicy(ViewManagerPolicy policy);
31 |
32 | /**
33 | * Get the primary window of the JavaFX application.
34 | *
35 | * @return Returns the primary window if present, else {@link Optional#empty()}.
36 | */
37 | Optional getPrimaryStage();
38 |
39 | /**
40 | * Get the primary stage property of the view manager.
41 | *
42 | * @return Returns the primary stage property.
43 | */
44 | ReadOnlyProperty primaryStageProperty();
45 |
46 | /**
47 | * Get the total amount of windows which are currently being shown.
48 | *
49 | * @return Returns the total amount of shown windows.
50 | */
51 | int getTotalWindows();
52 |
53 | /**
54 | * Get the JavaFX window by the given name.
55 | *
56 | * @param name Set the name of the window.
57 | * @return Returns the window if found, else {@link Optional#empty()}.
58 | */
59 | Optional getStage(String name);
60 |
61 | /**
62 | * Register the primary stage of the JavaFX application.
63 | *
64 | * @param primaryStage The primary stage to register in this manager.
65 | */
66 | void registerPrimaryStage(Stage primaryStage);
67 |
68 | /**
69 | * Add a new opened window to the manager.
70 | *
71 | * @param window Set the new window.
72 | * @param view Set the corresponding loaded view of the window.
73 | */
74 | void addWindowView(Stage window, Scene view);
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/stage/BorderlessStage.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.stage;
2 |
3 | import javafx.beans.property.DoubleProperty;
4 | import javafx.stage.Stage;
5 | import javafx.stage.StageStyle;
6 |
7 | /**
8 | * The {@link BorderlessStage} uses the {@link StageStyle#UNDECORATED} style but allows the functionality of
9 | * moving- and resizing the stage by the user.
10 | */
11 | public class BorderlessStage extends Stage {
12 | private final BorderlessStageWrapper stageWrapper;
13 |
14 | //region Constructors
15 |
16 | /**
17 | * Initialize a new instance of the borderless stage.
18 | */
19 | public BorderlessStage() {
20 | this.stageWrapper = new BorderlessStageWrapper(this);
21 | }
22 |
23 | //endregion
24 |
25 | //region Properties
26 |
27 | /**
28 | * Get the header height of the pane which allows the stage to be dragged around.
29 | *
30 | * @return Returns the header height of this pane.
31 | */
32 | public double getHeader() {
33 | return stageWrapper.getHeader();
34 | }
35 |
36 | /**
37 | * Get the header height property.
38 | *
39 | * @return Return the property of the header height.
40 | */
41 | public DoubleProperty headerProperty() {
42 | return stageWrapper.headerProperty();
43 | }
44 |
45 | /**
46 | * Set the header height of the pane which allows the stage to be dragged around.
47 | *
48 | * @param header The height of the header.
49 | */
50 | public void setHeader(double header) {
51 | stageWrapper.setHeader(header);
52 | }
53 |
54 | /**
55 | * Get the width of the resize border.
56 | *
57 | * @return Returns the width of the resize border.
58 | */
59 | public double getResizeBorder() {
60 | return stageWrapper.getResizeBorder();
61 | }
62 |
63 | /**
64 | * Get the resize border property.
65 | *
66 | * @return Returns the resize border property.
67 | */
68 | public DoubleProperty resizeBorderProperty() {
69 | return stageWrapper.resizeBorderProperty();
70 | }
71 |
72 | /**
73 | * Set the new width of the resize border.
74 | *
75 | * @param resizeBorder The new border resize width.
76 | */
77 | public void setResizeBorder(double resizeBorder) {
78 | stageWrapper.setResizeBorder(resizeBorder);
79 | }
80 |
81 | //endregion
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/ui/scale/ScaleAwareImpl.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.ui.scale;
2 |
3 | import javafx.scene.Scene;
4 | import javafx.scene.layout.Region;
5 | import javafx.scene.transform.Scale;
6 | import javafx.stage.Window;
7 |
8 | /**
9 | * Abstract implementation of {@link ScaleAware} for scaling the scene during initialization.
10 | */
11 | public abstract class ScaleAwareImpl implements ScaleAware {
12 | protected float scaleFactor;
13 |
14 | private Scene scene;
15 | private Region root;
16 | private Scale scale;
17 |
18 | @Override
19 | public void scale(Scene scene, Region root, float scale) {
20 | if (scene == null)
21 | throw new MissingScaleAwarePropertyException();
22 |
23 | this.scene = scene;
24 | this.root = root;
25 | this.scaleFactor = scale;
26 |
27 | initializeScaling();
28 | }
29 |
30 | @Override
31 | public void onScaleChanged(float newValue) {
32 | // check if the initial scaling has already been applied before trying to rescale the scene
33 | if (scene == null)
34 | return;
35 |
36 | this.scaleFactor = newValue;
37 | scale();
38 | }
39 |
40 | private void initializeScaling() {
41 | Window window = scene.getWindow();
42 |
43 | // set initial window size
44 | window.setWidth(root.getPrefWidth() * scaleFactor);
45 | window.setHeight(root.getPrefHeight() * scaleFactor);
46 |
47 | // scale the scene by the given scale factor
48 | scene.widthProperty().addListener((observable, oldValue, newValue) -> scaleWidth(newValue.doubleValue()));
49 | scene.heightProperty().addListener((observable, oldValue, newValue) -> scaleHeight(newValue.doubleValue()));
50 |
51 | // apply a scale transformer to the root region
52 | scale = new Scale(scaleFactor, scaleFactor);
53 | scale.setPivotX(0);
54 | scale.setPivotY(0);
55 | root.getTransforms().setAll(scale);
56 | }
57 |
58 | private void scale() {
59 | scale.setX(this.scaleFactor);
60 | scale.setY(this.scaleFactor);
61 |
62 | scaleWidth(scene.getWidth());
63 | scaleHeight(scene.getHeight());
64 | }
65 |
66 | private void scaleWidth(Double newValue) {
67 | root.setPrefWidth(newValue * 1 / scaleFactor);
68 | }
69 |
70 | private void scaleHeight(Double newValue) {
71 | root.setPrefHeight(newValue * 1 / scaleFactor);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/text/LocaleText.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.text;
2 |
3 | import javafx.beans.property.ReadOnlyObjectProperty;
4 | import org.springframework.context.support.MessageSourceAccessor;
5 |
6 | import java.util.Locale;
7 | import java.util.ResourceBundle;
8 |
9 | /**
10 | * Defines a easy way of loading localized text messages.
11 | * This interface uses {@link Message} for easy localized text definitions.
12 | */
13 | public interface LocaleText {
14 | /**
15 | * The property name of the locale text message source accessor.
16 | */
17 | String MESSAGE_SOURCE_ACCESSOR_PROPERTY = "messageSourceAccessor";
18 |
19 | /**
20 | * The property name of the locale text resource bundle.
21 | */
22 | String RESOURCE_BUNDLE_PROPERTY = "resourceBundle";
23 |
24 | /**
25 | * Get the message source that is used by this {@link LocaleText}.
26 | *
27 | * @return Returns the message source.
28 | */
29 | MessageSourceAccessor getMessageSource();
30 |
31 | /**
32 | * Get the message source accessor property of this locale text.
33 | *
34 | * @return Returns the read-only message source accessor property.
35 | */
36 | ReadOnlyObjectProperty messageSourceProperty();
37 |
38 | /**
39 | * Get the resource bundle that is used by this {@link LocaleText}.
40 | *
41 | * @return Returns the resource bundle.
42 | */
43 | ResourceBundle getResourceBundle();
44 |
45 | /**
46 | * Get the resource bundle property of this locale text.
47 | *
48 | * @return Returns the read-only instance of the resource bundle property.
49 | */
50 | ReadOnlyObjectProperty resourceBundleProperty();
51 |
52 | /**
53 | * Get the text for the given message key.
54 | *
55 | * @param message Set the message key.
56 | * @return Returns the formatted text.
57 | */
58 | String get(Message message);
59 |
60 | /**
61 | * Get the text for the given message key.
62 | *
63 | * @param message Set the message key.
64 | * @param args Set the arguments to pass to the message.
65 | * @return Returns the formatted text.
66 | */
67 | String get(Message message, Object... args);
68 |
69 | /**
70 | * Get the text for the given message.
71 | *
72 | * @param message Set the message.
73 | * @param args Set the arguments to pass to the message.
74 | * @return Returns the formatted text.
75 | */
76 | String get(String message, Object... args);
77 |
78 | /**
79 | * Update the locale that needs to be used for the localized texts.
80 | *
81 | * @param locale The new locale to use.
82 | */
83 | void updateLocale(Locale locale);
84 | }
85 |
--------------------------------------------------------------------------------
/src/test/java/com/github/spring/boot/javafx/font/controls/IconTest.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.font.controls;
2 |
3 | import javafx.geometry.Insets;
4 | import javafx.scene.paint.Color;
5 | import org.junit.jupiter.api.Test;
6 | import org.junit.jupiter.api.extension.ExtendWith;
7 | import org.testfx.framework.junit5.ApplicationExtension;
8 |
9 | import static org.junit.jupiter.api.Assertions.assertEquals;
10 | import static org.junit.jupiter.api.Assertions.assertTrue;
11 |
12 | @ExtendWith(ApplicationExtension.class)
13 | class IconTest {
14 | public static final String FONT_FAMILY = "FontAwesome";
15 |
16 | @Test
17 | void testNewInstance() {
18 | var result = new Icon();
19 |
20 | assertTrue(result.getStyleClass().contains(AbstractIcon.STYLE_CLASS));
21 | assertEquals(FONT_FAMILY, result.getFont().getFamily());
22 | }
23 |
24 | @Test
25 | void testNewInstanceWithUnicode() {
26 | var unicode = Icon.ADJUST_UNICODE;
27 |
28 | var result = new Icon(unicode);
29 |
30 | assertTrue(result.getStyleClass().contains(AbstractIcon.STYLE_CLASS));
31 | assertEquals(unicode, result.getText());
32 | }
33 |
34 | @Test
35 | void testNewInstanceWithBuilder() {
36 | var padding = new Insets(10, 20, 30, 40);
37 |
38 | var result = Icon.builder()
39 | .unicode(Icon.AMAZON_UNICODE)
40 | .padding(padding)
41 | .visible(true)
42 | .build();
43 |
44 | assertTrue(result.getStyleClass().contains(AbstractIcon.STYLE_CLASS));
45 | assertEquals(Icon.AMAZON_UNICODE, result.getText());
46 | assertEquals(padding, result.getPadding());
47 | assertTrue(result.isVisible());
48 | assertEquals(FONT_FAMILY, result.getFont().getFamily(), "expected the font family to not have been changed");
49 | }
50 |
51 | @Test
52 | void testSizeFactor() {
53 | var icon = new Icon();
54 | assertEquals(0.0, icon.getSizeFactor(), "expected the initial size factor to be 0.0");
55 |
56 | var newSizeFactor = 2.3;
57 | icon.setSizeFactor(newSizeFactor);
58 | assertEquals(newSizeFactor, icon.getSizeFactor(), "expected the size factor to be 2.3");
59 | assertEquals(FONT_FAMILY, icon.getFont().getFamily(), "expected the font family to not have been changed");
60 | }
61 |
62 | @Test
63 | void testTextColor() {
64 | var icon = new Icon();
65 | assertEquals(Color.BLACK, icon.getTextFill(), "expected the initial text color to be black");
66 |
67 | icon.setColor(Color.RED);
68 | assertEquals(Color.RED, icon.getTextFill(), "expected the text color to be red");
69 | assertEquals(FONT_FAMILY, icon.getFont().getFamily(), "expected the font family to not have been changed");
70 | }
71 | }
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/SpringJavaFXApplication.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx;
2 |
3 | import com.github.spring.boot.javafx.view.ViewManager;
4 | import javafx.application.Application;
5 | import javafx.application.Preloader;
6 | import javafx.stage.Stage;
7 | import org.springframework.boot.Banner;
8 | import org.springframework.boot.SpringApplication;
9 | import org.springframework.context.ConfigurableApplicationContext;
10 |
11 | /**
12 | * Abstract Spring Boot extension of {@link Application}.
13 | */
14 | public abstract class SpringJavaFXApplication extends Application {
15 | /**
16 | * The application context created by the JavaFX starter.
17 | * This context will only be available once the {@link #init()} has been invoked by JavaFX.
18 | */
19 | protected ConfigurableApplicationContext applicationContext;
20 |
21 | /**
22 | * Launch a JavaFX application with for the given class and program arguments.
23 | *
24 | * @param appClass The class to launch the JavaFX application for.
25 | * @param args The program arguments.
26 | */
27 | @SuppressWarnings("unused")
28 | public static void launch(Class extends Application> appClass, String... args) {
29 | Application.launch(appClass, args);
30 | }
31 |
32 | /**
33 | * Launch a JavaFX application with for the given class and program arguments.
34 | *
35 | * @param appClass The class to launch the JavaFX application for.
36 | * @param preloaderClass The class to use as the preloader of the JavaFX application.
37 | * @param args The program arguments.
38 | */
39 | @SuppressWarnings("unused")
40 | public static void launch(Class extends Application> appClass, Class extends Preloader> preloaderClass, String... args) {
41 | System.setProperty("javafx.preloader", preloaderClass.getName());
42 | Application.launch(appClass, args);
43 | }
44 |
45 | /**
46 | * Launch a JavaFX application with the given program arguments.
47 | *
48 | * @param args The program arguments.
49 | */
50 | @SuppressWarnings("unused")
51 | public static void launch(String... args) {
52 | Application.launch(args);
53 | }
54 |
55 | @Override
56 | public void init() {
57 | Parameters parameters = getParameters();
58 | SpringApplication application = new SpringApplication(this.getClass());
59 |
60 | application.setBannerMode(Banner.Mode.OFF);
61 | application.setHeadless(false);
62 |
63 | applicationContext = application.run(parameters.getRaw().toArray(new String[0]));
64 | }
65 |
66 | @Override
67 | public void start(Stage primaryStage) throws Exception {
68 | ViewManager viewManager = applicationContext.getBean(ViewManager.class);
69 | viewManager.registerPrimaryStage(primaryStage);
70 | }
71 |
72 | @Override
73 | public void stop() throws Exception {
74 | applicationContext.close();
75 | System.exit(0);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/view/ViewLoader.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.view;
2 |
3 | import javafx.scene.Node;
4 | import javafx.scene.layout.Pane;
5 | import javafx.stage.Stage;
6 |
7 | public interface ViewLoader {
8 | /**
9 | * The directory containing the FXML files.
10 | */
11 | String VIEW_DIRECTORY = "/views";
12 | /**
13 | * The directory contain
14 | */
15 | String IMAGE_DIRECTORY = "/images";
16 |
17 | /**
18 | * Set the UI scale of the views.
19 | *
20 | * @param scale The scale value of the ui.
21 | */
22 | void setScale(float scale);
23 |
24 | /**
25 | * Load and show the given view.
26 | *
27 | * @param view Set the view to load and show.
28 | * @param properties The view properties.
29 | */
30 | void show(String view, ViewProperties properties);
31 |
32 | /**
33 | * Show the primary scene on the given primary window.
34 | *
35 | * @param window The window.
36 | * @param view The view scene to load.
37 | * @param properties The view properties.
38 | */
39 | void show(Stage window, String view, ViewProperties properties);
40 |
41 | /**
42 | * Show the given view in a new window.
43 | *
44 | * @param view The FXML file to load and show.
45 | * @param properties The properties of the window.
46 | */
47 | void showWindow(String view, ViewProperties properties);
48 |
49 | /**
50 | * Show the given pane in a new window.
51 | *
52 | * @param pane The root pane to show in the window.
53 | * @param controller The controller of the root pane.µ
54 | * @param properties The properties of the window.
55 | */
56 | void showWindow(Pane pane, Object controller, ViewProperties properties);
57 |
58 | /**
59 | * Load the given FXML view file from the classpath.
60 | * Spring will inject the correct controller based on the {@code fx:controller} attribute in the view.
61 | *
62 | * @param view The FXML file to load.
63 | * @param The root node of the view file.
64 | * @return Returns the root node of the loaded FXML view if successfully loaded, else null.
65 | */
66 | T load(String view);
67 |
68 | /**
69 | * Load the given FXML view from the classpath and use the given controller within the loaded view. (discouraged)
70 | * Use Spring's {@link org.springframework.context.annotation.Scope} annotation on the {@link com.github.spring.boot.javafx.stereotype.ViewController}
71 | * instead.
72 | * This will create a new controller instance each time the view is loaded (and use {@link #load(String)} instead).
73 | *
74 | * @param view The FXML file to load.
75 | * @param controller The controller to wire into the view.
76 | * @param The root node of the view file.
77 | * @return Returns the root node of the loaded FXML view if successfully loaded, else null.
78 | */
79 | T load(String view, Object controller);
80 | }
81 |
--------------------------------------------------------------------------------
/src/test/java/com/github/spring/boot/javafx/ui/scale/ScaleAwareImplTest.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.ui.scale;
2 |
3 | import javafx.beans.property.SimpleDoubleProperty;
4 | import javafx.collections.ObservableList;
5 | import javafx.scene.Scene;
6 | import javafx.scene.layout.Region;
7 | import javafx.scene.transform.Scale;
8 | import javafx.scene.transform.Transform;
9 | import javafx.stage.Window;
10 | import org.junit.jupiter.api.BeforeEach;
11 | import org.junit.jupiter.api.Test;
12 | import org.junit.jupiter.api.extension.ExtendWith;
13 | import org.mockito.Mock;
14 | import org.mockito.junit.jupiter.MockitoExtension;
15 |
16 | import java.util.concurrent.atomic.AtomicReference;
17 |
18 | import static org.junit.jupiter.api.Assertions.*;
19 | import static org.mockito.ArgumentMatchers.isA;
20 | import static org.mockito.Mockito.lenient;
21 | import static org.mockito.Mockito.when;
22 |
23 | @ExtendWith(MockitoExtension.class)
24 | class ScaleAwareImplTest {
25 | @Mock
26 | private Scene scene;
27 | @Mock
28 | private Region root;
29 | @Mock
30 | private Window window;
31 | @Mock
32 | private ObservableList transforms;
33 | private MyController controller;
34 |
35 | @BeforeEach
36 | void setUp() {
37 | lenient().when(root.getTransforms()).thenReturn(transforms);
38 | lenient().when(scene.getWindow()).thenReturn(window);
39 |
40 | controller = new MyController();
41 | }
42 |
43 | @Test
44 | void testScale_whenSceneIsMissing_shouldThrowMissingScaleAwarePropertyException() {
45 | assertThrows(MissingScaleAwarePropertyException.class, () -> controller.scale(null, root, 1.0f), "Missing scene to execute scale aware logic");
46 | }
47 |
48 | @Test
49 | void testScale_whenInitialScaleIsGiven_shouldInitializeSceneWithTheGivenScale() {
50 | float scale = 1.5f;
51 | AtomicReference scaleHolder = new AtomicReference<>();
52 | when(transforms.setAll(isA(Scale.class))).thenAnswer(invocation -> {
53 | scaleHolder.set(invocation.getArgument(0, Scale.class));
54 | return true;
55 | });
56 | when(scene.widthProperty()).thenReturn(new SimpleDoubleProperty());
57 | when(scene.heightProperty()).thenReturn(new SimpleDoubleProperty());
58 |
59 | controller.scale(scene, root, scale);
60 | Scale result = scaleHolder.get();
61 |
62 | assertNotNull(result, "Expected a scale to have been set on the region");
63 | assertEquals(scale, result.getX());
64 | assertEquals(scale, result.getY());
65 | assertEquals(0, result.getPivotX());
66 | assertEquals(0, result.getPivotY());
67 | }
68 |
69 | @Test
70 | void testOnScaleChanged_whenNewValueIsGiven_shouldUpdateTheScaleWithTheNewValue() {
71 | float initialScale = 1.0f;
72 | float expectedScale = 1.8f;
73 | AtomicReference scaleHolder = new AtomicReference<>();
74 | when(transforms.setAll(isA(Scale.class))).thenAnswer(invocation -> {
75 | scaleHolder.set(invocation.getArgument(0, Scale.class));
76 | return true;
77 | });
78 | when(scene.widthProperty()).thenReturn(new SimpleDoubleProperty());
79 | when(scene.heightProperty()).thenReturn(new SimpleDoubleProperty());
80 |
81 | controller.scale(scene, root, initialScale);
82 | controller.onScaleChanged(expectedScale);
83 | Scale scale = scaleHolder.get();
84 |
85 | assertNotNull(scale, "Expected the scale to have been set on the region");
86 | assertEquals(expectedScale, scale.getX());
87 | assertEquals(expectedScale, scale.getY());
88 | }
89 |
90 | static class MyController extends ScaleAwareImpl {
91 | }
92 | }
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/font/controls/AbstractIcon.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.font.controls;
2 |
3 | import com.github.spring.boot.javafx.font.FontRegistryImpl;
4 | import javafx.beans.property.DoubleProperty;
5 | import javafx.beans.property.SimpleDoubleProperty;
6 | import javafx.scene.control.Label;
7 | import javafx.scene.paint.Color;
8 | import javafx.scene.text.Font;
9 | import javafx.scene.text.FontWeight;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.springframework.util.Assert;
12 |
13 | import java.util.Optional;
14 | import java.util.function.Consumer;
15 |
16 | /**
17 | * Abstract implementation of a Font Awesome icon that extends the {@link Label}.
18 | * This class loads the font file and prevents any changes to the initial loaded font family.
19 | */
20 | @Slf4j
21 | @SuppressWarnings("unused")
22 | abstract class AbstractIcon extends Label {
23 | public static final String STYLE_CLASS ="icon";
24 |
25 | private final DoubleProperty sizeFactorProperty = new SimpleDoubleProperty();
26 | private String fontFamily;
27 | private boolean updating;
28 |
29 | AbstractIcon(String filename) {
30 | Assert.hasText(filename, "filename cannot be empty");
31 | init(filename);
32 | }
33 |
34 | AbstractIcon(String filename, String text) {
35 | super(text);
36 | Assert.hasText(filename, "filename cannot be empty");
37 | init(filename);
38 | }
39 |
40 | public double getSizeFactor() {
41 | return sizeFactorProperty.get();
42 | }
43 |
44 | public void setSizeFactor(double factor) {
45 | sizeFactorProperty.set(factor);
46 | }
47 |
48 | public void setColor(Color color) {
49 | setTextFill(color);
50 | }
51 |
52 | void setProperty(T property, Consumer mapping) {
53 | Optional.ofNullable(property)
54 | .ifPresent(mapping);
55 | }
56 |
57 | @Override
58 | public String toString() {
59 | return getText();
60 | }
61 |
62 | private void init(String filename) {
63 | initializeFont(filename);
64 | initializeSizeFactor();
65 | initializeFontFamilyListener();
66 | initializeStyleClass();
67 | }
68 |
69 | private void initializeFont(String filename) {
70 | var font = FontRegistryImpl.getInstance().loadFont(filename);
71 |
72 | fontFamily = font.getFamily();
73 | setFont(font);
74 | }
75 |
76 | private void initializeSizeFactor() {
77 | sizeFactorProperty.addListener((observable, oldValue, newValue) -> {
78 | updating = true;
79 | var oldFont = getFont();
80 | var fontSize = getActualSize(newValue.doubleValue(), oldFont.getSize());
81 |
82 | setFont(Font.font(fontFamily, FontWeight.findByName(oldFont.getStyle()), fontSize));
83 | updating = false;
84 | });
85 | }
86 |
87 | private void initializeFontFamilyListener() {
88 | // this listener prevents any changes to the font family
89 | fontProperty().addListener((observable, oldValue, newValue) -> {
90 | if (newValue.getFamily().equals(fontFamily) || updating)
91 | return;
92 |
93 | updating = true;
94 | double fontSize = getActualSize(sizeFactorProperty.get(), newValue.getSize());
95 |
96 | setFont(Font.font(fontFamily, FontWeight.findByName(newValue.getStyle()), fontSize));
97 | updating = false;
98 | });
99 | }
100 |
101 | private void initializeStyleClass() {
102 | this.getStyleClass().add(STYLE_CLASS);
103 | }
104 |
105 | private double getActualSize(double sizeFactor, double fontSize) {
106 | return sizeFactor <= 0 ? fontSize : sizeFactor * fontSize;
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/text/LocaleTextImpl.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.text;
2 |
3 | import javafx.beans.property.ObjectProperty;
4 | import javafx.beans.property.ReadOnlyObjectProperty;
5 | import javafx.beans.property.SimpleObjectProperty;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.apache.commons.lang3.ArrayUtils;
8 | import org.springframework.context.NoSuchMessageException;
9 | import org.springframework.context.support.MessageSourceAccessor;
10 | import org.springframework.context.support.MessageSourceResourceBundle;
11 | import org.springframework.context.support.ResourceBundleMessageSource;
12 |
13 | import java.util.Locale;
14 | import java.util.Objects;
15 | import java.util.ResourceBundle;
16 |
17 | /**
18 | * Get the localized text for the given message key.
19 | * This class uses Spring's {@link MessageSourceResourceBundle} for retrieving the locale strings.
20 | */
21 | @Slf4j
22 | public class LocaleTextImpl implements LocaleText {
23 | private final ResourceBundleMessageSource messageSource;
24 | private final ObjectProperty messageSourceAccessor = new SimpleObjectProperty<>(this, MESSAGE_SOURCE_ACCESSOR_PROPERTY);
25 | private final ObjectProperty resourceBundle = new SimpleObjectProperty<>(this, RESOURCE_BUNDLE_PROPERTY);
26 |
27 | /**
28 | * Initialize a new instance of {@link LocaleTextImpl}.
29 | *
30 | * @param messageSource set the message source to use.
31 | */
32 | public LocaleTextImpl(ResourceBundleMessageSource messageSource) {
33 | Objects.requireNonNull(messageSource, "messageSource cannot be null");
34 | this.messageSource = messageSource;
35 |
36 | init();
37 | }
38 |
39 | //region Properties
40 |
41 | @Override
42 | public MessageSourceAccessor getMessageSource() {
43 | return messageSourceAccessor.get();
44 | }
45 |
46 | @Override
47 | public ObjectProperty messageSourceProperty() {
48 | return messageSourceAccessor;
49 | }
50 |
51 | private void setMessageSource(MessageSourceAccessor messageSourceAccessor) {
52 | this.messageSourceAccessor.set(messageSourceAccessor);
53 | }
54 |
55 | @Override
56 | public ResourceBundle getResourceBundle() {
57 | return resourceBundle.get();
58 | }
59 |
60 | @Override
61 | public ReadOnlyObjectProperty resourceBundleProperty() {
62 | return resourceBundle;
63 | }
64 |
65 | private void setResourceBundle(ResourceBundle resourceBundle) {
66 | this.resourceBundle.set(resourceBundle);
67 | }
68 |
69 | //endregion
70 |
71 | //region Getters
72 |
73 | @Override
74 | public String get(Message message) {
75 | return get(message, ArrayUtils.EMPTY_OBJECT_ARRAY);
76 | }
77 |
78 | @Override
79 | public String get(Message message, Object... args) {
80 | return get(message.getKey(), args);
81 | }
82 |
83 | @Override
84 | public String get(String message, Object... args) {
85 | try {
86 | return getMessageSource().getMessage(message, args);
87 | } catch (NoSuchMessageException ex) {
88 | log.warn("Message key '" + message + "' not found", ex);
89 | return message;
90 | }
91 | }
92 |
93 | //endregion
94 |
95 | //region Methods
96 |
97 | @Override
98 | public void updateLocale(Locale locale) {
99 | setMessageSource(createMessageSourceAccessor(locale));
100 | setResourceBundle(createResourceBundle(locale));
101 | }
102 |
103 | //endregion
104 |
105 | //region Functions
106 |
107 | private void init() {
108 | setMessageSource(createMessageSourceAccessor(Locale.getDefault()));
109 | setResourceBundle(createResourceBundle(Locale.getDefault()));
110 | }
111 |
112 | private MessageSourceAccessor createMessageSourceAccessor(Locale locale) {
113 | return new MessageSourceAccessor(messageSource, locale);
114 | }
115 |
116 | private MessageSourceResourceBundle createResourceBundle(Locale locale) {
117 | return new MessageSourceResourceBundle(messageSource, locale);
118 | }
119 |
120 | //endregion
121 | }
122 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/view/ViewManagerImpl.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.view;
2 |
3 | import javafx.application.Platform;
4 | import javafx.beans.property.Property;
5 | import javafx.beans.property.ReadOnlyProperty;
6 | import javafx.beans.property.SimpleObjectProperty;
7 | import javafx.event.EventHandler;
8 | import javafx.scene.Scene;
9 | import javafx.stage.Stage;
10 | import javafx.stage.WindowEvent;
11 | import lombok.AllArgsConstructor;
12 | import lombok.EqualsAndHashCode;
13 | import lombok.Value;
14 | import lombok.extern.slf4j.Slf4j;
15 | import org.springframework.context.ConfigurableApplicationContext;
16 |
17 | import java.util.ArrayList;
18 | import java.util.List;
19 | import java.util.Objects;
20 | import java.util.Optional;
21 |
22 | @Slf4j
23 | @EqualsAndHashCode
24 | public class ViewManagerImpl implements ViewManager {
25 | public static final String PRIMARY_STAGE_PROPERTY = "primaryStage";
26 | public static final String POLICY_PROPERTY = "policy";
27 |
28 | private final ConfigurableApplicationContext applicationContext;
29 | private final List windows = new ArrayList<>();
30 | private final Property primaryStage = new SimpleObjectProperty<>(this, PRIMARY_STAGE_PROPERTY);
31 | private final Property policy = new SimpleObjectProperty<>(this, POLICY_PROPERTY, ViewManagerPolicy.CLOSEABLE);
32 |
33 | //region Constructors
34 |
35 | public ViewManagerImpl(ConfigurableApplicationContext applicationContext) {
36 | this.applicationContext = applicationContext;
37 | }
38 |
39 | //endregion
40 |
41 | //region Properties
42 |
43 | @Override
44 | public Optional getPrimaryStage() {
45 | return Optional.ofNullable(primaryStage.getValue());
46 | }
47 |
48 | @Override
49 | public ReadOnlyProperty primaryStageProperty() {
50 | return primaryStage;
51 | }
52 |
53 | @Override
54 | public Optional getStage(String name) {
55 | return windows.stream()
56 | .filter(e -> e.getStage().getTitle().equalsIgnoreCase(name))
57 | .findFirst()
58 | .map(Window::getStage);
59 | }
60 |
61 | @Override
62 | public ViewManagerPolicy getPolicy() {
63 | return policy.getValue();
64 | }
65 |
66 | @Override
67 | public Property policyProperty() {
68 | return policy;
69 | }
70 |
71 | @Override
72 | public void setPolicy(ViewManagerPolicy policy) {
73 | this.policy.setValue(policy);
74 | }
75 |
76 | @Override
77 | public int getTotalWindows() {
78 | return windows.size();
79 | }
80 |
81 | //endregion
82 |
83 | //region Methods
84 |
85 | @Override
86 | public void registerPrimaryStage(Stage primaryStage) {
87 | Objects.requireNonNull(primaryStage, "primaryStage cannot be null");
88 | if (getPrimaryStage().isPresent()) {
89 | log.warn("Ignoring primary stage register as one has already been registered");
90 | return;
91 | }
92 |
93 | this.primaryStage.setValue(primaryStage);
94 | addWindowView(primaryStage, primaryStage.getScene(), true);
95 | }
96 |
97 | @Override
98 | public void addWindowView(Stage window, Scene view) {
99 | Objects.requireNonNull(window, "window cannot be null");
100 | Objects.requireNonNull(view, "view cannot be null");
101 | addWindowView(window, view, false);
102 | }
103 |
104 | //endregion
105 |
106 | //region Functions
107 |
108 | private void addWindowView(Stage window, Scene view, boolean isPrimaryStage) {
109 | window.setOnHiding(onWindowClosingEventHandler());
110 | windows.add(new Window(window, view, isPrimaryStage));
111 | log.debug("Currently showing " + getTotalWindows() + " window(s)");
112 | }
113 |
114 | private EventHandler onWindowClosingEventHandler() {
115 | return event -> {
116 | Stage stage = (Stage) event.getSource();
117 | Window window = this.windows.stream()
118 | .filter(e -> e.getStage() == stage)
119 | .findFirst()
120 | .orElseThrow(() -> new StageNotFoundException(stage.getTitle()));
121 |
122 | this.windows.remove(window);
123 | log.debug("Currently showing " + getTotalWindows() + " window(s)");
124 |
125 | if (policy.getValue() == ViewManagerPolicy.CLOSEABLE) {
126 | if (window.isPrimaryWindow()) {
127 | log.debug("Application closing, primary window is closed");
128 | exitApplication();
129 | } else if (this.windows.size() == 0) {
130 | log.debug("All windows closed, exiting application");
131 | exitApplication();
132 | }
133 | }
134 | };
135 | }
136 |
137 | private void exitApplication() {
138 | try {
139 | Platform.exit();
140 | } catch (Exception ex) {
141 | log.error("Failed to stop application gracefully, " + ex.getMessage(), ex);
142 | System.exit(1);
143 | }
144 | }
145 |
146 | //endregion
147 |
148 | @Value
149 | @AllArgsConstructor
150 | private static class Window {
151 | private final Stage stage;
152 | private Scene scene;
153 | private final boolean primaryWindow;
154 | }
155 | }
156 |
157 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Spring Boot JavaFX starter
2 |
3 | Spring Boot starter for easy integration with JavaFX.
4 | This library provides easy integration with JavaFX as well as additional helpers for
5 | loading & managing JavaFX views in Spring.
6 |
7 | ## Maven
8 |
9 | The library is available in the maven central repository and can be used by adding:
10 |
11 | _Spring Boot 3.X_
12 | ```xml
13 |
14 | com.github.yoep
15 | spring-boot-starter-javafx
16 | 2.0.0
17 |
18 | ```
19 |
20 | _Spring Boot 2.X_
21 | ```xml
22 |
23 | com.github.yoep
24 | spring-boot-starter-javafx
25 | 1.0.12
26 |
27 | ```
28 |
29 | ## Requirements
30 |
31 | ### Version 1.0.0+
32 |
33 | This is the legacy version of the library which requires Spring Boot 2+ and Java 8+.
34 |
35 | - Spring Boot 2+
36 | - Java 8+
37 |
38 | ### Version 2.0.0+
39 |
40 | This is the new major version of the library which requires Spring Boot 3+ and Java 17+.
41 |
42 | - Spring Boot 3+
43 | - Java 17+
44 |
45 | ## Usage
46 |
47 | Create a class which extends `SpringJavaFXApplication` and launch the JavaFX application from this class.
48 |
49 | _main entry example_
50 | ```java
51 | @SpringBootApplication
52 | public class MySpringApplication extends SpringJavaFXApplication {
53 |
54 | public static void main(String[] args) {
55 | launch(MySpringApplication.class, args);
56 | }
57 |
58 | @Override
59 | public void start(Stage primaryStage) throws Exception {
60 | super.start(primaryStage);
61 |
62 | // YOUR CODE ON STARTUP HERE
63 | }
64 | }
65 | ```
66 |
67 | Create a `ResourceBundle` bean which can be used by JavaFX within `.fxml` files.
68 |
69 | _resource bundle example_
70 | ```java
71 | @Configuration
72 | public class LanguageConfig {
73 | @Bean
74 | public ResourceBundleMessageSource messageSource() {
75 | ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
76 | messageSource.setBasenames("lang/example");
77 | return messageSource;
78 | }
79 | }
80 | ```
81 |
82 | ### Borderless stage
83 |
84 | You can create a borderless (undecorated) stage which is still resizable
85 | and draggable by using the `BorderlessStage` class.
86 |
87 | This functionality can also be achieved on the primary stage by using
88 | the `BorderlessStageWrapper` as follows:
89 |
90 | ```java
91 |
92 | @SpringBootApplication
93 | public class MySpringApplication extends SpringJavaFXApplication {
94 | @Override
95 | public void start(Stage stage) throws Exception {
96 | var myBorderlessStage = new BorderlessStageWrapper(stage);
97 | super.start(stage);
98 |
99 | // set the height of the header
100 | // this height is used within the BorderlessStage
101 | // to drag the window around
102 | myBorderlessStage.setHeader(20);
103 | // set the virtual border of the BorderlessStage
104 | // this width is used to determine when the user can grab
105 | // the non-existing border to resize the borderless stage
106 | myBorderlessStage.setResizeBorder(2);
107 | }
108 | }
109 | ```
110 |
111 | ### View controllers
112 |
113 | Use the following stereotype to define a view controller.
114 | This is not required as the library will use any bean that is known within the
115 | `ApplicationContext` to bind them to views.
116 |
117 | ```java
118 | @ViewController
119 | public class MyViewController {
120 | }
121 | ```
122 |
123 | ### Loading views
124 |
125 | There are 2 options when loading views, automatic controller selection through beans
126 | or manually defining the controller that needs to be used by JavaFX.
127 |
128 | - Automatically use a controller from the `ApplicationContext`.
129 |
130 | ```java
131 | private class Example {
132 | private ViewLoader viewLoader;
133 |
134 | private void loadView() {
135 | viewLoader.load("my-view-file.fxml");
136 | }
137 | }
138 | ```
139 |
140 | - Define a controller which needs to be used in the view.
141 |
142 | ```java
143 | private class Example {
144 | private ViewLoader viewLoader;
145 |
146 | private void loadView() {
147 | ViewController controller = new ViewController();
148 |
149 | viewLoader.load("my-view-file.fxml", controller);
150 | }
151 | }
152 | ```
153 |
154 | ## FAT jar packaging
155 |
156 | It is **recommended to not use** the `spring-boot-maven-plugin` if you want to package the JavaFX application into a fat jar.
157 | The reason behind this, is that the plugin will break JavaFX due to the JAR layout that is used by the plugin.
158 |
159 | For creating fat jar packages, use the `maven-shade-plugin` instead.
160 |
161 | ```xml
162 |
163 | org.apache.maven.plugins
164 | maven-shade-plugin
165 |
166 | false
167 |
168 |
169 |
170 | package
171 |
172 | shade
173 |
174 |
175 |
176 |
177 | META-INF/spring.handlers
178 |
179 |
180 | META-INF/spring.factories
181 |
182 |
183 | META-INF/spring.schemas
184 |
185 |
186 |
187 | ${start-class}
188 |
189 |
190 |
191 |
192 |
193 |
194 | ```
195 |
196 | ## IntelliJ IDEA
197 |
198 | IntelliJ adds by default the `javafx.base` and `javafx.graphics` to the modules of Java 9+.
199 | This might be causing issues in Java 9 and above, as the `javafx.controls` and `javafx.fxml` are
200 | missing from the modules causing an `IllegalAccessException` when trying to run the application.
201 |
202 | Add the following options to the `VM Options` in the run configuration of IntelliJ to fix this issue.
203 |
204 | -p "\lib" --add-modules javafx.controls,javafx.fxml,javafx.swing
205 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.2.5
9 |
10 |
11 | com.github.yoep
12 | spring-boot-starter-javafx
13 | 2.0.1-SNAPSHOT
14 | jar
15 |
16 | Spring Boot starter JavaFX
17 | Spring Boot starter for JavaFX applications
18 | https://github.com/yoep/spring-boot-starter-javafx
19 |
20 |
21 |
22 | Apache License, Version 2.0
23 | http://www.apache.org/licenses/LICENSE-2.0.txt
24 | repo
25 |
26 |
27 |
28 |
29 | https://github.com/yoep/spring-boot-starter-javafx
30 | scm:git:git@github.com:yoep/spring-boot-starter-javafx.git
31 | 1.0.12
32 |
33 |
34 |
35 |
36 | ossrh
37 | https://oss.sonatype.org/content/repositories/snapshots
38 |
39 |
40 | ossrh
41 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
42 |
43 |
44 |
45 |
46 | 17
47 | 17
48 | 17
49 |
50 |
51 | 22.0.1
52 |
53 |
54 | 5.10.2
55 | 5.2.0
56 | 5.11.0
57 | 4.0.17
58 |
59 |
60 | 3.1.0
61 | 3.2.0
62 | 3.3.0
63 | 3.0.1
64 |
65 |
66 |
67 |
68 |
69 | org.apache.commons
70 | commons-lang3
71 | provided
72 |
73 |
74 |
75 |
76 | org.springframework.boot
77 | spring-boot
78 | provided
79 |
80 |
81 | org.springframework.boot
82 | spring-boot-autoconfigure
83 | provided
84 |
85 |
86 | org.springframework.boot
87 | spring-boot-starter-logging
88 | provided
89 |
90 |
91 |
92 |
93 | org.openjfx
94 | javafx-fxml
95 | ${javafx.version}
96 | provided
97 |
98 |
99 |
100 |
101 | org.projectlombok
102 | lombok
103 | provided
104 |
105 |
106 |
107 |
108 | org.junit.jupiter
109 | junit-jupiter-engine
110 | ${junit.jupiter.engine.version}
111 | test
112 |
113 |
114 | org.mockito
115 | mockito-inline
116 | ${mockito.inline.version}
117 | test
118 |
119 |
120 | org.mockito
121 | mockito-junit-jupiter
122 | ${mockito.junit.jupiter.version}
123 | test
124 |
125 |
126 | org.testfx
127 | testfx-junit5
128 | ${testfx.junit.version}
129 | test
130 |
131 |
132 | org.springframework.boot
133 | spring-boot-starter-test
134 | test
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 | org.apache.maven.plugins
143 | maven-gpg-plugin
144 | ${maven.gpg.plugin.version}
145 |
146 |
147 | sign-artifacts
148 | verify
149 |
150 | sign
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 | org.apache.maven.plugins
161 | maven-source-plugin
162 | ${maven.source.plugin.version}
163 |
164 |
165 | attach-sources
166 | verify
167 |
168 | jar-no-fork
169 |
170 |
171 |
172 |
173 |
174 | org.apache.maven.plugins
175 | maven-javadoc-plugin
176 | ${maven.javadoc.plugin.version}
177 |
178 |
179 | attach-javadocs
180 |
181 | jar
182 |
183 |
184 |
185 |
186 |
187 | org.apache.maven.plugins
188 | maven-release-plugin
189 | ${maven.release.plugin.version}
190 |
191 | @{project.version}
192 | clean deploy -Possrh
193 |
194 |
195 |
196 |
197 |
198 |
199 | maven_central
200 | Maven Central
201 | https://repo.maven.apache.org/maven2/
202 |
203 |
204 |
205 |
206 |
207 | ossrh
208 |
209 |
210 |
211 | org.apache.maven.plugins
212 | maven-gpg-plugin
213 |
214 |
215 |
216 |
217 |
218 |
219 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/stage/BorderlessStageWrapper.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.stage;
2 |
3 | import javafx.beans.property.DoubleProperty;
4 | import javafx.beans.property.SimpleDoubleProperty;
5 | import javafx.event.EventHandler;
6 | import javafx.scene.Cursor;
7 | import javafx.scene.Scene;
8 | import javafx.scene.input.MouseEvent;
9 | import javafx.stage.Stage;
10 | import javafx.stage.StageStyle;
11 | import lombok.Getter;
12 | import org.springframework.lang.Nullable;
13 |
14 | import java.util.Objects;
15 |
16 | /**
17 | * The {@link BorderlessStageWrapper} wraps around an existing stage and converts it into a borderless stage.
18 | * The precondition of the stage is that {@link Stage#isShowing()} needs to be false so the style can be initialized for the stage.
19 | * If the stage is however already being show, a {@link InvalidStageException} will be thrown.
20 | */
21 | public class BorderlessStageWrapper {
22 | public static final String HEADER_PROPERTY = "header";
23 | public static final String RESIZE_BORDER_PROPERTY = "resizeBorder";
24 |
25 | private final EventHandler mouseMovedEventHandler = this::onMouseMoved;
26 | private final EventHandler mousePressedEventHandler = this::onMousePressed;
27 | private final EventHandler mouseDraggedEventHandler = this::onMouseDragged;
28 |
29 | private final DoubleProperty header = new SimpleDoubleProperty(this, HEADER_PROPERTY, 0);
30 | private final DoubleProperty resizeBorder = new SimpleDoubleProperty(this, RESIZE_BORDER_PROPERTY, 4);
31 | @Getter
32 | private final Stage stage;
33 |
34 | private double xOffset;
35 | private double yOffset;
36 | private double xStart;
37 | private double yStart;
38 | private boolean windowDrag;
39 | private boolean windowResize;
40 | private Cursor cursor = Cursor.DEFAULT;
41 |
42 | //region Constructors
43 |
44 | public BorderlessStageWrapper(Stage stage) {
45 | Objects.requireNonNull(stage, "stage cannot be null");
46 | this.stage = stage;
47 | init();
48 | }
49 |
50 | //endregion
51 |
52 | //region Properties
53 |
54 | /**
55 | * Get the header height of the pane which allows the stage to be dragged around.
56 | *
57 | * @return Returns the header height of this pane.
58 | */
59 | public double getHeader() {
60 | return header.get();
61 | }
62 |
63 | /**
64 | * Get the header height property.
65 | *
66 | * @return Return the property of the header height.
67 | */
68 | public DoubleProperty headerProperty() {
69 | return header;
70 | }
71 |
72 | /**
73 | * Set the header height of the pane which allows the stage to be dragged around.
74 | *
75 | * @param header The height of the header.
76 | */
77 | public void setHeader(double header) {
78 | this.header.set(header);
79 | }
80 |
81 | /**
82 | * Get the width of the resize border.
83 | *
84 | * @return Returns the width of the resize border.
85 | */
86 | public double getResizeBorder() {
87 | return resizeBorder.get();
88 | }
89 |
90 | /**
91 | * Get the resize border property.
92 | *
93 | * @return Returns the resize border property.
94 | */
95 | public DoubleProperty resizeBorderProperty() {
96 | return resizeBorder;
97 | }
98 |
99 | /**
100 | * Set the new width of the resize border.
101 | *
102 | * @param resizeBorder The new border resize width.
103 | */
104 | public void setResizeBorder(double resizeBorder) {
105 | this.resizeBorder.set(resizeBorder);
106 | }
107 |
108 | //endregion
109 |
110 | //region Functions
111 |
112 | /**
113 | * Invoked when the scene of this {@link BorderlessStage} is being changed.
114 | *
115 | * @param oldValue The old scene of the {@link BorderlessStage}.
116 | * @param newValue The new scene of the {@link BorderlessStage}.
117 | */
118 | protected void onSceneChanged(@Nullable Scene oldValue, @Nullable Scene newValue) {
119 | if (oldValue != null)
120 | removeSceneListeners(oldValue);
121 |
122 | if (newValue != null)
123 | addSceneListeners(newValue);
124 | }
125 |
126 | private void init() {
127 | initializeStage();
128 | initializeListeners();
129 | }
130 |
131 | private void initializeStage() {
132 | if (stage.isShowing()) {
133 | throw new InvalidStageException(stage, "Stage is in an invalid state, stage is already being showed");
134 | }
135 |
136 | stage.initStyle(StageStyle.UNDECORATED);
137 | }
138 |
139 | private void initializeListeners() {
140 | stage.sceneProperty().addListener((observable, oldValue, newValue) -> onSceneChanged(oldValue, newValue));
141 | }
142 |
143 | private void removeSceneListeners(Scene scene) {
144 | Objects.requireNonNull(scene, "scene cannot be null");
145 | scene.removeEventHandler(MouseEvent.MOUSE_MOVED, mouseMovedEventHandler);
146 | scene.removeEventHandler(MouseEvent.MOUSE_PRESSED, mousePressedEventHandler);
147 | scene.removeEventHandler(MouseEvent.MOUSE_DRAGGED, mouseDraggedEventHandler);
148 | }
149 |
150 | private void addSceneListeners(Scene scene) {
151 | Objects.requireNonNull(scene, "scene cannot be null");
152 | scene.addEventHandler(MouseEvent.MOUSE_MOVED, mouseMovedEventHandler);
153 | scene.addEventHandler(MouseEvent.MOUSE_PRESSED, mousePressedEventHandler);
154 | scene.addEventHandler(MouseEvent.MOUSE_DRAGGED, mouseDraggedEventHandler);
155 | }
156 |
157 | private void onMouseMoved(MouseEvent event) {
158 | // check if the stage is allowed to be resized
159 | // if not, ignore this event
160 | if (!isResizeAllowed())
161 | return;
162 |
163 | double x = event.getSceneX();
164 | double y = event.getSceneY();
165 | double width = stage.getWidth();
166 | double height = stage.getHeight();
167 | double border = getResizeBorder();
168 |
169 | if (x < border && y < border) {
170 | cursor = Cursor.NW_RESIZE;
171 | } else if (x > width - border && y < border) {
172 | cursor = Cursor.NE_RESIZE;
173 | } else if (x > width - border && y > height - border) {
174 | cursor = Cursor.SE_RESIZE;
175 | } else if (x < border && y > height - border) {
176 | cursor = Cursor.SW_RESIZE;
177 | } else if (y < border) {
178 | cursor = Cursor.N_RESIZE;
179 | } else if (x > width - border) {
180 | cursor = Cursor.E_RESIZE;
181 | } else if (y > height - border) {
182 | cursor = Cursor.S_RESIZE;
183 | } else if (x < border) {
184 | cursor = Cursor.W_RESIZE;
185 | } else {
186 | cursor = Cursor.DEFAULT;
187 | }
188 |
189 | windowResize = cursor != Cursor.DEFAULT;
190 | stage.getScene().setCursor(cursor);
191 | }
192 |
193 | private void onMousePressed(MouseEvent event) {
194 | // check if the stage is in fullscreen
195 | // if so, ignore this event
196 | if (stage.isFullScreen()) {
197 | return;
198 | }
199 |
200 | xOffset = stage.getX() - event.getScreenX();
201 | yOffset = stage.getY() - event.getScreenY();
202 | xStart = stage.getWidth() - event.getSceneX();
203 | yStart = stage.getHeight() - event.getSceneY();
204 | windowDrag = isValidWindowDragEvent(event);
205 | }
206 |
207 | private void onMouseDragged(MouseEvent event) {
208 | if (windowDrag)
209 | onWindowDrag(event);
210 | if (windowResize && isResizeAllowed())
211 | onWindowResize(event);
212 | }
213 |
214 | private void onWindowDrag(MouseEvent event) {
215 | event.consume();
216 |
217 | stage.setX(event.getScreenX() + xOffset);
218 | stage.setY(event.getScreenY() + yOffset);
219 | }
220 |
221 | private void onWindowResize(MouseEvent event) {
222 | event.consume();
223 |
224 | if (cursor == Cursor.E_RESIZE || cursor == Cursor.NE_RESIZE || cursor == Cursor.SE_RESIZE) {
225 | double newWidth = event.getSceneX() + xStart;
226 |
227 | if (newWidth >= stage.getMinWidth())
228 | stage.setWidth(newWidth);
229 | }
230 |
231 | if (cursor == Cursor.S_RESIZE || cursor == Cursor.SE_RESIZE || cursor == Cursor.SW_RESIZE) {
232 | double newHeight = event.getSceneY() + yStart;
233 |
234 | if (newHeight >= stage.getMinHeight())
235 | stage.setHeight(newHeight);
236 | }
237 |
238 | if (cursor == Cursor.W_RESIZE || cursor == Cursor.SW_RESIZE || cursor == Cursor.NW_RESIZE) {
239 | double width = stage.getX() - event.getScreenX() + stage.getWidth();
240 |
241 | if (width >= stage.getMinWidth()) {
242 | stage.setX(event.getScreenX());
243 | stage.setWidth(width);
244 | }
245 | }
246 |
247 | if (cursor == Cursor.N_RESIZE || cursor == Cursor.NW_RESIZE || cursor == Cursor.NE_RESIZE) {
248 | double height = stage.getY() - event.getScreenY() + stage.getHeight();
249 |
250 | if (height >= stage.getMinHeight()) {
251 | stage.setY(event.getScreenY());
252 | stage.setHeight(height);
253 | }
254 | }
255 | }
256 |
257 | private boolean isResizeAllowed() {
258 | return stage.isResizable() && !stage.isFullScreen();
259 | }
260 |
261 | private boolean isValidWindowDragEvent(MouseEvent event) {
262 | // check if the mouse event is a valid window drag event
263 | // the event should be within the header height and not a window resize event
264 | return !windowResize && event.getSceneY() <= getHeader();
265 | }
266 |
267 | //endregion
268 | }
269 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/font/controls/IconRegular.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.font.controls;
2 |
3 | import javafx.event.EventHandler;
4 | import javafx.geometry.Insets;
5 | import javafx.scene.input.MouseEvent;
6 | import lombok.Builder;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Fontawesome v5 regular icon.
12 | */
13 | public class IconRegular extends AbstractIcon {
14 | //region Unicode
15 |
16 | public static final String ADDRESS_BOOK_UNICODE = "\uf2b9";
17 | public static final String ADDRESS_CARD_UNICODE = "\uf2bb";
18 | public static final String ANGRY_UNICODE = "\uf556";
19 | public static final String ARROW_ALT_CIRCLE_DOWN_UNICODE = "\uf358";
20 | public static final String ARROW_ALT_CIRCLE_LEFT_UNICODE = "\uf359";
21 | public static final String ARROW_ALT_CIRCLE_RIGHT_UNICODE = "\uf35a";
22 | public static final String ARROW_ALT_CIRCLE_UP_UNICODE = "\uf35b";
23 | public static final String BELL_UNICODE = "\uf0f3";
24 | public static final String BELL_SLASH_UNICODE = "\uf1f6";
25 | public static final String BOOKMARK_UNICODE = "\uf02e";
26 | public static final String BUILDING_UNICODE = "\uf1ad";
27 | public static final String CALENDAR_UNICODE = "\uf133";
28 | public static final String CALENDAR_ALT_UNICODE = "\uf073";
29 | public static final String CALENDAR_CHECK_UNICODE = "\uf274";
30 | public static final String CALENDAR_MINUS_UNICODE = "\uf272";
31 | public static final String CALENDAR_PLUS_UNICODE = "\uf271";
32 | public static final String CALENDAR_TIMES_UNICODE = "\uf273";
33 | public static final String CARET_SQUARE_DOWN_UNICODE = "\uf150";
34 | public static final String CARET_SQUARE_LEFT_UNICODE = "\uf191";
35 | public static final String CARET_SQUARE_RIGHT_UNICODE = "\uf152";
36 | public static final String CARET_SQUARE_UP_UNICODE = "\uf151";
37 | public static final String CHART_BAR_UNICODE = "\uf080";
38 | public static final String CHECK_CIRCLE_UNICODE = "\uf058";
39 | public static final String CHECK_SQUARE_UNICODE = "\uf14a";
40 | public static final String CIRCLE_UNICODE = "\uf111";
41 | public static final String CLIPBOARD_UNICODE = "\uf328";
42 | public static final String CLOCK_UNICODE = "\uf017";
43 | public static final String CLONE_UNICODE = "\uf24d";
44 | public static final String CLOSED_CAPTIONING_UNICODE = "\uf20a";
45 | public static final String COMMENT_UNICODE = "\uf075";
46 | public static final String COMMENT_ALT_UNICODE = "\uf27a";
47 | public static final String COMMENT_DOTS_UNICODE = "\uf4ad";
48 | public static final String COMMENTS_UNICODE = "\uf086";
49 | public static final String COMPASS_UNICODE = "\uf14e";
50 | public static final String COPY_UNICODE = "\uf0c5";
51 | public static final String COPYRIGHT_UNICODE = "\uf1f9";
52 | public static final String CREDIT_CARD_UNICODE = "\uf09d";
53 | public static final String DIZZY_UNICODE = "\uf567";
54 | public static final String DOT_CIRCLE_UNICODE = "\uf192";
55 | public static final String EDIT_UNICODE = "\uf044";
56 | public static final String ENVELOPE_UNICODE = "\uf0e0";
57 | public static final String ENVELOPE_OPEN_UNICODE = "\uf2b6";
58 | public static final String EYE_UNICODE = "\uf06e";
59 | public static final String EYE_SLASH_UNICODE = "\uf070";
60 | public static final String FILE_UNICODE = "\uf15b";
61 | public static final String FILE_ALT_UNICODE = "\uf15c";
62 | public static final String FILE_ARCHIVE_UNICODE = "\uf1c6";
63 | public static final String FILE_AUDIO_UNICODE = "\uf1c7";
64 | public static final String FILE_CODE_UNICODE = "\uf1c9";
65 | public static final String FILE_EXCEL_UNICODE = "\uf1c3";
66 | public static final String FILE_IMAGE_UNICODE = "\uf1c5";
67 | public static final String FILE_PDF_UNICODE = "\uf1c1";
68 | public static final String FILE_POWERPOINT_UNICODE = "\uf1c4";
69 | public static final String FILE_VIDEO_UNICODE = "\uf1c8";
70 | public static final String FILE_WORD_UNICODE = "\uf1c2";
71 | public static final String FLAG_UNICODE = "\uf024";
72 | public static final String FLUSHED_UNICODE = "\uf579";
73 | public static final String FOLDER_UNICODE = "\uf07b";
74 | public static final String FOLDER_OPEN_UNICODE = "\uf07c";
75 | public static final String FROWN_UNICODE = "\uf119";
76 | public static final String FROWN_OPEN_UNICODE = "\uf57a";
77 | public static final String FUTBOL_UNICODE = "\uf1e3";
78 | public static final String GEM_UNICODE = "\uf3a5";
79 | public static final String GRIMACE_UNICODE = "\uf57f";
80 | public static final String GRIN_UNICODE = "\uf580";
81 | public static final String GRIN_ALT_UNICODE = "\uf581";
82 | public static final String GRIN_BEAM_UNICODE = "\uf582";
83 | public static final String GRIN_BEAM_SWEAT_UNICODE = "\uf583";
84 | public static final String GRIN_HEARTS_UNICODE = "\uf584";
85 | public static final String GRIN_SQUINT_UNICODE = "\uf585";
86 | public static final String GRIN_SQUINT_TEARS_UNICODE = "\uf586";
87 | public static final String GRIN_STARS_UNICODE = "\uf587";
88 | public static final String GRIN_TEARS_UNICODE = "\uf588";
89 | public static final String GRIN_TONGUE_UNICODE = "\uf589";
90 | public static final String GRIN_TONGUE_SQUINT_UNICODE = "\uf58a";
91 | public static final String GRIN_TONGUE_WINK_UNICODE = "\uf58b";
92 | public static final String GRIN_WINK_UNICODE = "\uf58c";
93 | public static final String HAND_LIZARD_UNICODE = "\uf258";
94 | public static final String HAND_PAPER_UNICODE = "\uf256";
95 | public static final String HAND_PEACE_UNICODE = "\uf25b";
96 | public static final String HAND_POINT_DOWN_UNICODE = "\uf0a7";
97 | public static final String HAND_POINT_LEFT_UNICODE = "\uf0a5";
98 | public static final String HAND_POINT_RIGHT_UNICODE = "\uf0a4";
99 | public static final String HAND_POINT_UP_UNICODE = "\uf0a6";
100 | public static final String HAND_POINTER_UNICODE = "\uf25a";
101 | public static final String HAND_ROCK_UNICODE = "\uf255";
102 | public static final String HAND_SCISSORS_UNICODE = "\uf257";
103 | public static final String HAND_SPOCK_UNICODE = "\uf259";
104 | public static final String HANDSHAKE_UNICODE = "\uf2b5";
105 | public static final String HDD_UNICODE = "\uf0a0";
106 | public static final String HEART_UNICODE = "\uf004";
107 | public static final String HOSPITAL_UNICODE = "\uf0f8";
108 | public static final String HOURGLASS_UNICODE = "\uf254";
109 | public static final String ID_BADGE_UNICODE = "\uf2c1";
110 | public static final String ID_CARD_UNICODE = "\uf2c2";
111 | public static final String IMAGE_UNICODE = "\uf03e";
112 | public static final String IMAGES_UNICODE = "\uf302";
113 | public static final String KEYBOARD_UNICODE = "\uf11c";
114 | public static final String KISS_UNICODE = "\uf596";
115 | public static final String KISS_BEAM_UNICODE = "\uf597";
116 | public static final String KISS_WINK_HEART_UNICODE = "\uf598";
117 | public static final String LAUGH_UNICODE = "\uf599";
118 | public static final String LAUGH_BEAM_UNICODE = "\uf59a";
119 | public static final String LAUGH_SQUINT_UNICODE = "\uf59b";
120 | public static final String LAUGH_WINK_UNICODE = "\uf59c";
121 | public static final String LEMON_UNICODE = "\uf094";
122 | public static final String LIFE_RING_UNICODE = "\uf1cd";
123 | public static final String LIGHTBULB_UNICODE = "\uf0eb";
124 | public static final String LIST_ALT_UNICODE = "\uf022";
125 | public static final String MAP_UNICODE = "\uf279";
126 | public static final String MEH_UNICODE = "\uf11a";
127 | public static final String MEH_BLANK_UNICODE = "\uf5a4";
128 | public static final String MEH_ROLLING_EYES_UNICODE = "\uf5a5";
129 | public static final String MINUS_SQUARE_UNICODE = "\uf146";
130 | public static final String MONEY_BILL_ALT_UNICODE = "\uf3d1";
131 | public static final String MOON_UNICODE = "\uf186";
132 | public static final String NEWSPAPER_UNICODE = "\uf1ea";
133 | public static final String OBJECT_GROUP_UNICODE = "\uf247";
134 | public static final String OBJECT_UNGROUP_UNICODE = "\uf248";
135 | public static final String PAPER_PLANE_UNICODE = "\uf1d8";
136 | public static final String PAUSE_CIRCLE_UNICODE = "\uf28b";
137 | public static final String PLAY_CIRCLE_UNICODE = "\uf144";
138 | public static final String PLUS_SQUARE_UNICODE = "\uf0fe";
139 | public static final String QUESTION_CIRCLE_UNICODE = "\uf059";
140 | public static final String REGISTERED_UNICODE = "\uf25d";
141 | public static final String SAD_CRY_UNICODE = "\uf5b3";
142 | public static final String SAD_TEAR_UNICODE = "\uf5b4";
143 | public static final String SAVE_UNICODE = "\uf0c7";
144 | public static final String SHARE_SQUARE_UNICODE = "\uf14d";
145 | public static final String SMILE_UNICODE = "\uf118";
146 | public static final String SMILE_BEAM_UNICODE = "\uf5b8";
147 | public static final String SMILE_WINK_UNICODE = "\uf4da";
148 | public static final String SNOWFLAKE_UNICODE = "\uf2dc";
149 | public static final String SQUARE_UNICODE = "\uf0c8";
150 | public static final String STAR_UNICODE = "\uf005";
151 | public static final String STAR_HALF_UNICODE = "\uf089";
152 | public static final String STICKY_NOTE_UNICODE = "\uf249";
153 | public static final String STOP_CIRCLE_UNICODE = "\uf28d";
154 | public static final String SUN_UNICODE = "\uf185";
155 | public static final String SURPRISE_UNICODE = "\uf5c2";
156 | public static final String THUMBS_DOWN_UNICODE = "\uf165";
157 | public static final String THUMBS_UP_UNICODE = "\uf164";
158 | public static final String TIMES_CIRCLE_UNICODE = "\uf057";
159 | public static final String TIRED_UNICODE = "\uf5c8";
160 | public static final String TRASH_ALT_UNICODE = "\uf2ed";
161 | public static final String USER_UNICODE = "\uf007";
162 | public static final String USER_CIRCLE_UNICODE = "\uf2bd";
163 | public static final String WINDOW_CLOSE_UNICODE = "\uf410";
164 | public static final String WINDOW_MAXIMIZE_UNICODE = "\uf2d0";
165 | public static final String WINDOW_MINIMIZE_UNICODE = "\uf2d1";
166 | public static final String WINDOW_RESTORE_UNICODE = "\uf2d2";
167 |
168 | //endregion
169 |
170 | private static final String FILENAME = "fontawesome-regular.ttf";
171 |
172 | public IconRegular() {
173 | super(FILENAME);
174 | }
175 |
176 | public IconRegular(String unicode) {
177 | super(FILENAME, unicode);
178 | }
179 |
180 | @Builder
181 | public IconRegular(String unicode, Insets padding, Boolean visible, EventHandler super MouseEvent> onMouseClicked, List styleClasses) {
182 | super(FILENAME);
183 | setProperty(unicode, this::setText);
184 | setProperty(padding, this::setPadding);
185 | setProperty(visible, this::setVisible);
186 | setProperty(onMouseClicked, this::setOnMouseClicked);
187 | setProperty(styleClasses, e -> this.getStyleClass().addAll(e));
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/view/ViewLoaderImpl.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.view;
2 |
3 | import com.github.spring.boot.javafx.text.LocaleText;
4 | import com.github.spring.boot.javafx.ui.scale.ScaleAware;
5 | import com.github.spring.boot.javafx.ui.size.SizeAware;
6 | import com.github.spring.boot.javafx.ui.stage.StageAware;
7 | import javafx.application.Platform;
8 | import javafx.fxml.FXMLLoader;
9 | import javafx.scene.Group;
10 | import javafx.scene.Node;
11 | import javafx.scene.Scene;
12 | import javafx.scene.image.Image;
13 | import javafx.scene.layout.Pane;
14 | import javafx.scene.layout.Region;
15 | import javafx.stage.Modality;
16 | import javafx.stage.Screen;
17 | import javafx.stage.Stage;
18 | import lombok.extern.slf4j.Slf4j;
19 | import org.apache.commons.lang3.StringUtils;
20 | import org.springframework.context.ApplicationContext;
21 | import org.springframework.core.io.ClassPathResource;
22 | import org.springframework.util.Assert;
23 |
24 | import java.io.File;
25 | import java.io.IOException;
26 | import java.util.Objects;
27 | import java.util.Optional;
28 |
29 | @Slf4j
30 | public class ViewLoaderImpl implements ViewLoader {
31 | protected final ApplicationContext applicationContext;
32 | protected final ViewManager viewManager;
33 | protected final LocaleText localeText;
34 |
35 | protected float scale = 1f;
36 |
37 | //region Constructors
38 |
39 | /**
40 | * Initialize a new instance of {@link ViewLoaderImpl}.
41 | *
42 | * @param applicationContext Set the current application context.
43 | * @param viewManager Set the view manager to store the views in.
44 | * @param localeText Set the UI text manager.
45 | */
46 | public ViewLoaderImpl(ApplicationContext applicationContext, ViewManager viewManager, LocaleText localeText) {
47 | Objects.requireNonNull(applicationContext, "applicationContext cannot be null");
48 | Objects.requireNonNull(viewManager, "viewManager cannot be null");
49 | Objects.requireNonNull(localeText, "localeText cannot be null");
50 | this.applicationContext = applicationContext;
51 | this.viewManager = viewManager;
52 | this.localeText = localeText;
53 | }
54 |
55 | //endregion
56 |
57 | //region ViewLoader
58 |
59 | @Override
60 | public void setScale(float scale) {
61 | if (this.scale == scale)
62 | return;
63 |
64 | this.scale = scale;
65 | onScaleChanged(scale);
66 | }
67 |
68 | @Override
69 | public void show(String view, ViewProperties properties) {
70 | Assert.hasText(view, "view cannot be empty");
71 | Objects.requireNonNull(properties, "properties cannot be null");
72 |
73 | Stage stage = viewManager.getPrimaryStage()
74 | .orElseThrow(StageNotFoundException::new);
75 | showScene(stage, view, properties);
76 | }
77 |
78 | @Override
79 | public void show(Stage window, String view, ViewProperties properties) {
80 | Objects.requireNonNull(window, "window cannot be empty");
81 | Assert.hasText(view, "view cannot be empty");
82 | Objects.requireNonNull(properties, "properties cannot be null");
83 | showScene(window, view, properties);
84 | }
85 |
86 | @Override
87 | public void showWindow(String view, ViewProperties properties) {
88 | Assert.hasText(view, "view cannot be empty");
89 | Objects.requireNonNull(properties, "properties cannot be null");
90 | Platform.runLater(() -> showScene(new Stage(), view, properties));
91 | }
92 |
93 | @Override
94 | public void showWindow(Pane pane, Object controller, ViewProperties properties) {
95 | Objects.requireNonNull(pane, "pane cannot be null");
96 | Objects.requireNonNull(controller, "controller cannot be null");
97 | Objects.requireNonNull(properties, "properties cannot be null");
98 |
99 | Platform.runLater(() -> showScene(new Stage(), new SceneInfo(new Scene(pane), pane, controller), properties));
100 | }
101 |
102 | @Override
103 | public T load(String view) {
104 | Assert.hasText(view, "view cannot be empty");
105 | var loader = loadResource(view);
106 |
107 | loader.setControllerFactory(applicationContext::getBean);
108 | return loadComponent(loader);
109 | }
110 |
111 | @Override
112 | public T load(String view, Object controller) {
113 | Assert.hasText(view, "view cannot be empty");
114 | Objects.requireNonNull(controller, "controller cannot be null");
115 | var loader = loadResource(view);
116 |
117 | loader.setController(controller);
118 | return loadComponent(loader);
119 | }
120 |
121 | //endregion
122 |
123 | //region Functions
124 |
125 | /**
126 | * Load the view component from the {@link FXMLLoader}.
127 | * This method attaches the available resources of the application to the loader before loading the actual component.
128 | *
129 | * @param loader The loader to load the component from.
130 | * @param The root node of the view.
131 | * @return Returns the loaded view component on success, else null when the loading failed.
132 | */
133 | protected T loadComponent(FXMLLoader loader) {
134 | Objects.requireNonNull(loader, "loader cannot be null");
135 | loader.setResources(localeText.getResourceBundle());
136 |
137 | try {
138 | return loader.load();
139 | } catch (IOException e) {
140 | log.error(e.getMessage(), e);
141 | return null;
142 | }
143 | }
144 |
145 | /**
146 | * Prepare the resource view to be loaded.
147 | * This method will load the resource file from the classpath and prepare the {@link FXMLLoader}.
148 | *
149 | * @param view The view file that needs to be loaded.
150 | * @return Returns the loader for the given view file.
151 | */
152 | protected FXMLLoader loadResource(String view) {
153 | Objects.requireNonNull(view, "view cannot be null");
154 | var componentResource = new ClassPathResource(ViewLoader.VIEW_DIRECTORY + File.separator + view);
155 |
156 | if (!componentResource.exists())
157 | throw new ViewNotFoundException(view);
158 |
159 | try {
160 | return new FXMLLoader(componentResource.getURL());
161 | } catch (IOException ex) {
162 | throw new ViewException(ex.getMessage(), ex);
163 | }
164 | }
165 |
166 | private SceneInfo loadView(String view, ViewProperties properties) throws ViewNotFoundException {
167 | Assert.hasText(view, "view cannot be empty");
168 | var fxmlResourceFile = new ClassPathResource(ViewLoader.VIEW_DIRECTORY + File.separator + view);
169 |
170 | if (fxmlResourceFile.exists()) {
171 | FXMLLoader loader;
172 |
173 | try {
174 | loader = new FXMLLoader(fxmlResourceFile.getURL(), localeText.getResourceBundle());
175 | } catch (IOException ex) {
176 | throw new ViewException(view, ex.getMessage(), ex);
177 | }
178 |
179 | loader.setControllerFactory(applicationContext::getBean);
180 |
181 | try {
182 | Region root = loader.load();
183 | Object controller = loader.getController();
184 | Scene scene;
185 |
186 | if (controller instanceof ScaleAware) {
187 | scene = new Scene(new Group(root));
188 | } else {
189 | scene = new Scene(root);
190 | }
191 |
192 | // check if a background fill color has been defined
193 | // if so, set the fill color for the scene
194 | if (properties != null && properties.getBackground() != null)
195 | scene.setFill(properties.getBackground());
196 |
197 | return new SceneInfo(scene, root, controller);
198 | } catch (IllegalStateException ex) {
199 | throw new ViewNotFoundException(view, ex);
200 | } catch (IOException ex) {
201 | log.error("View '" + view + "' is invalid", ex);
202 | throw new ViewException(view, ex.getMessage(), ex);
203 | }
204 | }
205 |
206 | return null;
207 | }
208 |
209 | private void showScene(Stage window, String view, ViewProperties properties) {
210 | var sceneInfo = loadView(view, properties);
211 |
212 | if (sceneInfo != null) {
213 | showScene(window, sceneInfo, properties);
214 | } else {
215 | log.warn("Unable to show view " + view + " in window " + window);
216 | }
217 | }
218 |
219 | private void showScene(Stage window, SceneInfo sceneInfo, ViewProperties properties) {
220 | var scene = sceneInfo.scene();
221 | var controller = sceneInfo.controller();
222 |
223 | window.setScene(scene);
224 | viewManager.addWindowView(window, scene);
225 |
226 | if (controller instanceof ScaleAware) {
227 | initWindowScale(sceneInfo);
228 | }
229 | if (controller instanceof SizeAware) {
230 | initWindowSize(scene, (SizeAware) controller);
231 | }
232 | if (controller instanceof StageAware) {
233 | initWindowEvents(scene, (StageAware) controller);
234 | }
235 |
236 | setWindowViewProperties(window, properties);
237 |
238 | if (properties.isDialog()) {
239 | window.initModality(Modality.APPLICATION_MODAL);
240 | window.showAndWait();
241 | } else {
242 | window.show();
243 | }
244 | }
245 |
246 | private void setWindowViewProperties(Stage window, ViewProperties properties) {
247 | window.setTitle(properties.getTitle());
248 | // prevent JavaFX from making unnecessary changes to the window
249 | if (!Objects.equals(window.isMaximized(), properties.isMaximized()))
250 | window.setMaximized(properties.isMaximized());
251 | if (!Objects.equals(window.isResizable(), properties.isResizable()))
252 | window.setResizable(properties.isResizable());
253 |
254 | Optional.ofNullable(properties.getIcon())
255 | .filter(StringUtils::isNotBlank)
256 | .ifPresent(icon -> window.getIcons().add(loadWindowIcon(icon)));
257 |
258 | if (properties.isCenterOnScreen()) {
259 | centerOnScreen(window);
260 | }
261 | }
262 |
263 | /**
264 | * Center the given window on the screen.
265 | *
266 | * @param window Set the window to center.
267 | */
268 | private void centerOnScreen(Stage window) {
269 | var screenBounds = Screen.getPrimary().getVisualBounds();
270 |
271 | window.setX((screenBounds.getWidth() - window.getWidth()) / 2);
272 | window.setY((screenBounds.getHeight() - window.getHeight()) / 2);
273 | }
274 |
275 | private Image loadWindowIcon(String iconName) {
276 | try {
277 | var iconResource = new ClassPathResource(ViewLoader.IMAGE_DIRECTORY + File.separator + iconName);
278 |
279 | if (iconResource.exists()) {
280 | return new Image(iconResource.getInputStream());
281 | } else {
282 | throw new ViewException("Icon '" + iconName + "' not found");
283 | }
284 | } catch (IOException ex) {
285 | throw new ViewException(ex.getMessage(), ex);
286 | }
287 | }
288 |
289 | private void initWindowScale(SceneInfo sceneInfo) {
290 | var controller = (ScaleAware) sceneInfo.controller();
291 |
292 | controller.scale(sceneInfo.scene(), sceneInfo.root(), scale);
293 | }
294 |
295 | private void initWindowSize(Scene scene, SizeAware controller) {
296 | var window = (Stage) scene.getWindow();
297 | controller.setInitialSize(window);
298 | window.widthProperty().addListener((observable, oldValue, newValue) -> {
299 | if (window.isShowing()) {
300 | controller.onSizeChange(newValue, window.getHeight(), window.isMaximized());
301 | }
302 | });
303 | window.heightProperty().addListener((observable, oldValue, newValue) -> {
304 | if (window.isShowing()) {
305 | controller.onSizeChange(window.getWidth(), newValue, window.isMaximized());
306 | }
307 | });
308 | window.maximizedProperty().addListener(((observable, oldValue, newValue) -> {
309 | if (window.isShowing()) {
310 | controller.onSizeChange(window.getWidth(), window.getHeight(), newValue);
311 | }
312 | }));
313 | }
314 |
315 | private void initWindowEvents(Scene scene, StageAware controller) {
316 | final var window = (Stage) scene.getWindow();
317 |
318 | window.setOnShown(event -> controller.onShown(window));
319 | window.setOnCloseRequest(event -> controller.onClosed(window));
320 | }
321 |
322 | private void onScaleChanged(final float newValue) {
323 | for (var scaleAware : applicationContext.getBeansOfType(ScaleAware.class).values()) {
324 | try {
325 | scaleAware.onScaleChanged(newValue);
326 | } catch (Exception ex) {
327 | log.error("Failed to invoke scale awareness with error " + ex.getMessage(), ex);
328 | }
329 | }
330 | }
331 |
332 | //endregion
333 |
334 | /**
335 | * Contains the general information about a certain scene which might actively be rendered within JavaFX.
336 | *
337 | * @param scene The scene to be rendered.
338 | * @param root The root region of the scene.
339 | * @param controller The controller of the scene.
340 | */
341 | record SceneInfo(Scene scene, Region root, Object controller) {
342 | }
343 | }
344 |
--------------------------------------------------------------------------------
/src/main/java/com/github/spring/boot/javafx/font/controls/Icon.java:
--------------------------------------------------------------------------------
1 | package com.github.spring.boot.javafx.font.controls;
2 |
3 | import javafx.event.EventHandler;
4 | import javafx.geometry.Insets;
5 | import javafx.scene.input.MouseEvent;
6 | import lombok.Builder;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * JavaFX node containing a Fontawesome v4.7 icon.
12 | */
13 | public class Icon extends AbstractIcon {
14 | //region Unicodes
15 |
16 | public static final String ADDRESS_BOOK_O_UNICODE = "\uf2ba";
17 | public static final String ADDRESS_BOOK_UNICODE = "\uf2b9";
18 | public static final String ADDRESS_CARD_O_UNICODE = "\uf2bc";
19 | public static final String ADDRESS_CARD_UNICODE = "\uf2bb";
20 | public static final String ADJUST_UNICODE = "\uf042";
21 | public static final String ADN_UNICODE = "\uf170";
22 | public static final String ALIGN_CENTER_UNICODE = "\uf037";
23 | public static final String ALIGN_JUSTIFY_UNICODE = "\uf039";
24 | public static final String ALIGN_LEFT_UNICODE = "\uf036";
25 | public static final String ALIGN_RIGHT_UNICODE = "\uf038";
26 | public static final String AMAZON_UNICODE = "\uf270";
27 | public static final String AMBULANCE_UNICODE = "\uf0f9";
28 | public static final String AMERICAN_SIGN_LANGUAGE_INTERPRETING_UNICODE = "\uf2a3";
29 | public static final String ANCHOR_UNICODE = "\uf13d";
30 | public static final String ANDROID_UNICODE = "\uf17b";
31 | public static final String ANGELLIST_UNICODE = "\uf209";
32 | public static final String ANGLE_DOUBLE_DOWN_UNICODE = "\uf103";
33 | public static final String ANGLE_DOUBLE_LEFT_UNICODE = "\uf100";
34 | public static final String ANGLE_DOUBLE_RIGHT_UNICODE = "\uf101";
35 | public static final String ANGLE_DOUBLE_UP_UNICODE = "\uf102";
36 | public static final String ANGLE_DOWN_UNICODE = "\uf107";
37 | public static final String ANGLE_LEFT_UNICODE = "\uf104";
38 | public static final String ANGLE_RIGHT_UNICODE = "\uf105";
39 | public static final String ANGLE_UP_UNICODE = "\uf106";
40 | public static final String APPLE_UNICODE = "\uf179";
41 | public static final String ARCHIVE_UNICODE = "\uf187";
42 | public static final String AREA_CHART_UNICODE = "\uf1fe";
43 | public static final String ARROWS_ALT_UNICODE = "\uf0b2";
44 | public static final String ARROWS_H_UNICODE = "\uf07e";
45 | public static final String ARROWS_UNICODE = "\uf047";
46 | public static final String ARROWS_V_UNICODE = "\uf07d";
47 | public static final String ARROW_CIRCLE_DOWN_UNICODE = "\uf0ab";
48 | public static final String ARROW_CIRCLE_LEFT_UNICODE = "\uf0a8";
49 | public static final String ARROW_CIRCLE_O_DOWN_UNICODE = "\uf01a";
50 | public static final String ARROW_CIRCLE_O_LEFT_UNICODE = "\uf190";
51 | public static final String ARROW_CIRCLE_O_RIGHT_UNICODE = "\uf18e";
52 | public static final String ARROW_CIRCLE_O_UP_UNICODE = "\uf01b";
53 | public static final String ARROW_CIRCLE_RIGHT_UNICODE = "\uf0a9";
54 | public static final String ARROW_CIRCLE_UP_UNICODE = "\uf0aa";
55 | public static final String ARROW_DOWN_UNICODE = "\uf063";
56 | public static final String ARROW_LEFT_UNICODE = "\uf060";
57 | public static final String ARROW_RIGHT_UNICODE = "\uf061";
58 | public static final String ARROW_UP_UNICODE = "\uf062";
59 | public static final String ASL_INTERPRETING_UNICODE = "\uf2a3";
60 | public static final String ASSISTIVE_LISTENING_SYSTEMS_UNICODE = "\uf2a2";
61 | public static final String ASTERISK_UNICODE = "\uf069";
62 | public static final String AT_UNICODE = "\uf1fa";
63 | public static final String AUDIO_DESCRIPTION_UNICODE = "\uf29e";
64 | public static final String AUTOMOBILE_UNICODE = "\uf1b9";
65 | public static final String BACKWARD_UNICODE = "\uf04a";
66 | public static final String BALANCE_SCALE_UNICODE = "\uf24e";
67 | public static final String BANDCAMP_UNICODE = "\uf2d5";
68 | public static final String BANK_UNICODE = "\uf19c";
69 | public static final String BAN_UNICODE = "\uf05e";
70 | public static final String BARCODE_UNICODE = "\uf02a";
71 | public static final String BARS_UNICODE = "\uf0c9";
72 | public static final String BAR_CHART_O_UNICODE = "\uf080";
73 | public static final String BAR_CHART_UNICODE = "\uf080";
74 | public static final String BATHTUB_UNICODE = "\uf2cd";
75 | public static final String BATH_UNICODE = "\uf2cd";
76 | public static final String BATTERY_0_UNICODE = "\uf244";
77 | public static final String BATTERY_1_UNICODE = "\uf243";
78 | public static final String BATTERY_2_UNICODE = "\uf242";
79 | public static final String BATTERY_3_UNICODE = "\uf241";
80 | public static final String BATTERY_4_UNICODE = "\uf240";
81 | public static final String BATTERY_EMPTY_UNICODE = "\uf244";
82 | public static final String BATTERY_FULL_UNICODE = "\uf240";
83 | public static final String BATTERY_HALF_UNICODE = "\uf242";
84 | public static final String BATTERY_QUARTER_UNICODE = "\uf243";
85 | public static final String BATTERY_THREE_QUARTERS_UNICODE = "\uf241";
86 | public static final String BATTERY_UNICODE = "\uf240";
87 | public static final String BED_UNICODE = "\uf236";
88 | public static final String BEER_UNICODE = "\uf0fc";
89 | public static final String BEHANCE_SQUARE_UNICODE = "\uf1b5";
90 | public static final String BEHANCE_UNICODE = "\uf1b4";
91 | public static final String BELL_O_UNICODE = "\uf0a2";
92 | public static final String BELL_SLASH_O_UNICODE = "\uf1f7";
93 | public static final String BELL_SLASH_UNICODE = "\uf1f6";
94 | public static final String BELL_UNICODE = "\uf0f3";
95 | public static final String BICYCLE_UNICODE = "\uf206";
96 | public static final String BINOCULARS_UNICODE = "\uf1e5";
97 | public static final String BIRTHDAY_CAKE_UNICODE = "\uf1fd";
98 | public static final String BITBUCKET_SQUARE_UNICODE = "\uf172";
99 | public static final String BITBUCKET_UNICODE = "\uf171";
100 | public static final String BITCOIN_UNICODE = "\uf15a";
101 | public static final String BLACK_TIE_UNICODE = "\uf27e";
102 | public static final String BLIND_UNICODE = "\uf29d";
103 | public static final String BLUETOOTH_B_UNICODE = "\uf294";
104 | public static final String BLUETOOTH_UNICODE = "\uf293";
105 | public static final String BOLD_UNICODE = "\uf032";
106 | public static final String BOLT_UNICODE = "\uf0e7";
107 | public static final String BOMB_UNICODE = "\uf1e2";
108 | public static final String BOOKMARK_O_UNICODE = "\uf097";
109 | public static final String BOOKMARK_UNICODE = "\uf02e";
110 | public static final String BOOK_UNICODE = "\uf02d";
111 | public static final String BRAILLE_UNICODE = "\uf2a1";
112 | public static final String BRIEFCASE_UNICODE = "\uf0b1";
113 | public static final String BTC_UNICODE = "\uf15a";
114 | public static final String BUG_UNICODE = "\uf188";
115 | public static final String BUILDING_O_UNICODE = "\uf0f7";
116 | public static final String BUILDING_UNICODE = "\uf1ad";
117 | public static final String BULLHORN_UNICODE = "\uf0a1";
118 | public static final String BULLSEYE_UNICODE = "\uf140";
119 | public static final String BUS_UNICODE = "\uf207";
120 | public static final String BUYSELLADS_UNICODE = "\uf20d";
121 | public static final String CAB_UNICODE = "\uf1ba";
122 | public static final String CALCULATOR_UNICODE = "\uf1ec";
123 | public static final String CALENDAR_CHECK_O_UNICODE = "\uf274";
124 | public static final String CALENDAR_MINUS_O_UNICODE = "\uf272";
125 | public static final String CALENDAR_O_UNICODE = "\uf133";
126 | public static final String CALENDAR_PLUS_O_UNICODE = "\uf271";
127 | public static final String CALENDAR_TIMES_O_UNICODE = "\uf273";
128 | public static final String CALENDAR_UNICODE = "\uf073";
129 | public static final String CAMERA_RETRO_UNICODE = "\uf083";
130 | public static final String CAMERA_UNICODE = "\uf030";
131 | public static final String CARET_DOWN_UNICODE = "\uf0d7";
132 | public static final String CARET_LEFT_UNICODE = "\uf0d9";
133 | public static final String CARET_RIGHT_UNICODE = "\uf0da";
134 | public static final String CARET_SQUARE_O_DOWN_UNICODE = "\uf150";
135 | public static final String CARET_SQUARE_O_LEFT_UNICODE = "\uf191";
136 | public static final String CARET_SQUARE_O_RIGHT_UNICODE = "\uf152";
137 | public static final String CARET_SQUARE_O_UP_UNICODE = "\uf151";
138 | public static final String CARET_UP_UNICODE = "\uf0d8";
139 | public static final String CART_ARROW_DOWN_UNICODE = "\uf218";
140 | public static final String CART_PLUS_UNICODE = "\uf217";
141 | public static final String CAR_UNICODE = "\uf1b9";
142 | public static final String CC_AMEX_UNICODE = "\uf1f3";
143 | public static final String CC_DINERS_CLUB_UNICODE = "\uf24c";
144 | public static final String CC_DISCOVER_UNICODE = "\uf1f2";
145 | public static final String CC_JCB_UNICODE = "\uf24b";
146 | public static final String CC_MASTERCARD_UNICODE = "\uf1f1";
147 | public static final String CC_PAYPAL_UNICODE = "\uf1f4";
148 | public static final String CC_STRIPE_UNICODE = "\uf1f5";
149 | public static final String CC_UNICODE = "\uf20a";
150 | public static final String CC_VISA_UNICODE = "\uf1f0";
151 | public static final String CERTIFICATE_UNICODE = "\uf0a3";
152 | public static final String CHAIN_BROKEN_UNICODE = "\uf127";
153 | public static final String CHAIN_UNICODE = "\uf0c1";
154 | public static final String CHECK_CIRCLE_O_UNICODE = "\uf05d";
155 | public static final String CHECK_CIRCLE_UNICODE = "\uf058";
156 | public static final String CHECK_SQUARE_O_UNICODE = "\uf046";
157 | public static final String CHECK_SQUARE_UNICODE = "\uf14a";
158 | public static final String CHECK_UNICODE = "\uf00c";
159 | public static final String CHEVRON_CIRCLE_DOWN_UNICODE = "\uf13a";
160 | public static final String CHEVRON_CIRCLE_LEFT_UNICODE = "\uf137";
161 | public static final String CHEVRON_CIRCLE_RIGHT_UNICODE = "\uf138";
162 | public static final String CHEVRON_CIRCLE_UP_UNICODE = "\uf139";
163 | public static final String CHEVRON_DOWN_UNICODE = "\uf078";
164 | public static final String CHEVRON_LEFT_UNICODE = "\uf053";
165 | public static final String CHEVRON_RIGHT_UNICODE = "\uf054";
166 | public static final String CHEVRON_UP_UNICODE = "\uf077";
167 | public static final String CHILD_UNICODE = "\uf1ae";
168 | public static final String CHROME_UNICODE = "\uf268";
169 | public static final String CIRCLE_O_NOTCH_UNICODE = "\uf1ce";
170 | public static final String CIRCLE_O_UNICODE = "\uf10c";
171 | public static final String CIRCLE_THIN_UNICODE = "\uf1db";
172 | public static final String CIRCLE_UNICODE = "\uf111";
173 | public static final String CLIPBOARD_UNICODE = "\uf0ea";
174 | public static final String CLOCK_O_UNICODE = "\uf017";
175 | public static final String CLONE_UNICODE = "\uf24d";
176 | public static final String CLOSE_UNICODE = "\uf00d";
177 | public static final String CLOUD_DOWNLOAD_UNICODE = "\uf0ed";
178 | public static final String CLOUD_UNICODE = "\uf0c2";
179 | public static final String CLOUD_UPLOAD_UNICODE = "\uf0ee";
180 | public static final String CNY_UNICODE = "\uf157";
181 | public static final String CODEPEN_UNICODE = "\uf1cb";
182 | public static final String CODE_FORK_UNICODE = "\uf126";
183 | public static final String CODE_UNICODE = "\uf121";
184 | public static final String CODIEPIE_UNICODE = "\uf284";
185 | public static final String COFFEE_UNICODE = "\uf0f4";
186 | public static final String COGS_UNICODE = "\uf085";
187 | public static final String COG_UNICODE = "\uf013";
188 | public static final String COLUMNS_UNICODE = "\uf0db";
189 | public static final String COMMENTING_O_UNICODE = "\uf27b";
190 | public static final String COMMENTING_UNICODE = "\uf27a";
191 | public static final String COMMENTS_O_UNICODE = "\uf0e6";
192 | public static final String COMMENTS_UNICODE = "\uf086";
193 | public static final String COMMENT_O_UNICODE = "\uf0e5";
194 | public static final String COMMENT_UNICODE = "\uf075";
195 | public static final String COMPASS_UNICODE = "\uf14e";
196 | public static final String COMPRESS_UNICODE = "\uf066";
197 | public static final String CONNECTDEVELOP_UNICODE = "\uf20e";
198 | public static final String CONTAO_UNICODE = "\uf26d";
199 | public static final String COPYRIGHT_UNICODE = "\uf1f9";
200 | public static final String COPY_UNICODE = "\uf0c5";
201 | public static final String CREATIVE_COMMONS_UNICODE = "\uf25e";
202 | public static final String CREDIT_CARD_ALT_UNICODE = "\uf283";
203 | public static final String CREDIT_CARD_UNICODE = "\uf09d";
204 | public static final String CROP_UNICODE = "\uf125";
205 | public static final String CROSSHAIRS_UNICODE = "\uf05b";
206 | public static final String CSS3_UNICODE = "\uf13c";
207 | public static final String CUBES_UNICODE = "\uf1b3";
208 | public static final String CUBE_UNICODE = "\uf1b2";
209 | public static final String CUTLERY_UNICODE = "\uf0f5";
210 | public static final String CUT_UNICODE = "\uf0c4";
211 | public static final String DASHBOARD_UNICODE = "\uf0e4";
212 | public static final String DASHCUBE_UNICODE = "\uf210";
213 | public static final String DATABASE_UNICODE = "\uf1c0";
214 | public static final String DEAFNESS_UNICODE = "\uf2a4";
215 | public static final String DEAF_UNICODE = "\uf2a4";
216 | public static final String DEDENT_UNICODE = "\uf03b";
217 | public static final String DELICIOUS_UNICODE = "\uf1a5";
218 | public static final String DESKTOP_UNICODE = "\uf108";
219 | public static final String DEVIANTART_UNICODE = "\uf1bd";
220 | public static final String DIAMOND_UNICODE = "\uf219";
221 | public static final String DIGG_UNICODE = "\uf1a6";
222 | public static final String DOLLAR_UNICODE = "\uf155";
223 | public static final String DOT_CIRCLE_O_UNICODE = "\uf192";
224 | public static final String DOWNLOAD_UNICODE = "\uf019";
225 | public static final String DRIBBBLE_UNICODE = "\uf17d";
226 | public static final String DRIVERS_LICENSE_O_UNICODE = "\uf2c3";
227 | public static final String DRIVERS_LICENSE_UNICODE = "\uf2c2";
228 | public static final String DROPBOX_UNICODE = "\uf16b";
229 | public static final String DRUPAL_UNICODE = "\uf1a9";
230 | public static final String EDGE_UNICODE = "\uf282";
231 | public static final String EDIT_UNICODE = "\uf044";
232 | public static final String EERCAST_UNICODE = "\uf2da";
233 | public static final String EJECT_UNICODE = "\uf052";
234 | public static final String ELLIPSIS_H_UNICODE = "\uf141";
235 | public static final String ELLIPSIS_V_UNICODE = "\uf142";
236 | public static final String EMPIRE_UNICODE = "\uf1d1";
237 | public static final String ENVELOPE_OPEN_O_UNICODE = "\uf2b7";
238 | public static final String ENVELOPE_OPEN_UNICODE = "\uf2b6";
239 | public static final String ENVELOPE_O_UNICODE = "\uf003";
240 | public static final String ENVELOPE_SQUARE_UNICODE = "\uf199";
241 | public static final String ENVELOPE_UNICODE = "\uf0e0";
242 | public static final String ENVIRA_UNICODE = "\uf299";
243 | public static final String ERASER_UNICODE = "\uf12d";
244 | public static final String ETSY_UNICODE = "\uf2d7";
245 | public static final String EURO_UNICODE = "\uf153";
246 | public static final String EUR_UNICODE = "\uf153";
247 | public static final String EXCHANGE_UNICODE = "\uf0ec";
248 | public static final String EXCLAMATION_CIRCLE_UNICODE = "\uf06a";
249 | public static final String EXCLAMATION_TRIANGLE_UNICODE = "\uf071";
250 | public static final String EXCLAMATION_UNICODE = "\uf12a";
251 | public static final String EXPAND_UNICODE = "\uf065";
252 | public static final String EXPEDITEDSSL_UNICODE = "\uf23e";
253 | public static final String EXTERNAL_LINK_SQUARE_UNICODE = "\uf14c";
254 | public static final String EXTERNAL_LINK_UNICODE = "\uf08e";
255 | public static final String EYEDROPPER_UNICODE = "\uf1fb";
256 | public static final String EYE_SLASH_UNICODE = "\uf070";
257 | public static final String EYE_UNICODE = "\uf06e";
258 | public static final String FACEBOOK_F_UNICODE = "\uf09a";
259 | public static final String FACEBOOK_OFFICIAL_UNICODE = "\uf230";
260 | public static final String FACEBOOK_SQUARE_UNICODE = "\uf082";
261 | public static final String FACEBOOK_UNICODE = "\uf09a";
262 | public static final String FAST_BACKWARD_UNICODE = "\uf049";
263 | public static final String FAST_FORWARD_UNICODE = "\uf050";
264 | public static final String FAX_UNICODE = "\uf1ac";
265 | public static final String FA_UNICODE = "\uf2b4";
266 | public static final String FEED_UNICODE = "\uf09e";
267 | public static final String FEMALE_UNICODE = "\uf182";
268 | public static final String FIGHTER_JET_UNICODE = "\uf0fb";
269 | public static final String FILES_O_UNICODE = "\uf0c5";
270 | public static final String FILE_ARCHIVE_O_UNICODE = "\uf1c6";
271 | public static final String FILE_AUDIO_O_UNICODE = "\uf1c7";
272 | public static final String FILE_CODE_O_UNICODE = "\uf1c9";
273 | public static final String FILE_EXCEL_O_UNICODE = "\uf1c3";
274 | public static final String FILE_IMAGE_O_UNICODE = "\uf1c5";
275 | public static final String FILE_MOVIE_O_UNICODE = "\uf1c8";
276 | public static final String FILE_O_UNICODE = "\uf016";
277 | public static final String FILE_PDF_O_UNICODE = "\uf1c1";
278 | public static final String FILE_PHOTO_O_UNICODE = "\uf1c5";
279 | public static final String FILE_PICTURE_O_UNICODE = "\uf1c5";
280 | public static final String FILE_POWERPOINT_O_UNICODE = "\uf1c4";
281 | public static final String FILE_SOUND_O_UNICODE = "\uf1c7";
282 | public static final String FILE_TEXT_O_UNICODE = "\uf0f6";
283 | public static final String FILE_TEXT_UNICODE = "\uf15c";
284 | public static final String FILE_UNICODE = "\uf15b";
285 | public static final String FILE_VIDEO_O_UNICODE = "\uf1c8";
286 | public static final String FILE_WORD_O_UNICODE = "\uf1c2";
287 | public static final String FILE_ZIP_O_UNICODE = "\uf1c6";
288 | public static final String FILM_UNICODE = "\uf008";
289 | public static final String FILTER_UNICODE = "\uf0b0";
290 | public static final String FIREFOX_UNICODE = "\uf269";
291 | public static final String FIRE_EXTINGUISHER_UNICODE = "\uf134";
292 | public static final String FIRE_UNICODE = "\uf06d";
293 | public static final String FIRST_ORDER_UNICODE = "\uf2b0";
294 | public static final String FLAG_CHECKERED_UNICODE = "\uf11e";
295 | public static final String FLAG_O_UNICODE = "\uf11d";
296 | public static final String FLAG_UNICODE = "\uf024";
297 | public static final String FLASH_UNICODE = "\uf0e7";
298 | public static final String FLASK_UNICODE = "\uf0c3";
299 | public static final String FLICKR_UNICODE = "\uf16e";
300 | public static final String FLOPPY_O_UNICODE = "\uf0c7";
301 | public static final String FOLDER_OPEN_O_UNICODE = "\uf115";
302 | public static final String FOLDER_OPEN_UNICODE = "\uf07c";
303 | public static final String FOLDER_O_UNICODE = "\uf114";
304 | public static final String FOLDER_UNICODE = "\uf07b";
305 | public static final String FONTICONS_UNICODE = "\uf280";
306 | public static final String FONT_AWESOME_UNICODE = "\uf2b4";
307 | public static final String FONT_UNICODE = "\uf031";
308 | public static final String FORT_AWESOME_UNICODE = "\uf286";
309 | public static final String FORUMBEE_UNICODE = "\uf211";
310 | public static final String FORWARD_UNICODE = "\uf04e";
311 | public static final String FOURSQUARE_UNICODE = "\uf180";
312 | public static final String FREE_CODE_CAMP_UNICODE = "\uf2c5";
313 | public static final String FROWN_O_UNICODE = "\uf119";
314 | public static final String FUTBOL_O_UNICODE = "\uf1e3";
315 | public static final String GAMEPAD_UNICODE = "\uf11b";
316 | public static final String GAVEL_UNICODE = "\uf0e3";
317 | public static final String GBP_UNICODE = "\uf154";
318 | public static final String GEARS_UNICODE = "\uf085";
319 | public static final String GEAR_UNICODE = "\uf013";
320 | public static final String GENDERLESS_UNICODE = "\uf22d";
321 | public static final String GET_POCKET_UNICODE = "\uf265";
322 | public static final String GE_UNICODE = "\uf1d1";
323 | public static final String GG_CIRCLE_UNICODE = "\uf261";
324 | public static final String GG_UNICODE = "\uf260";
325 | public static final String GIFT_UNICODE = "\uf06b";
326 | public static final String GITHUB_ALT_UNICODE = "\uf113";
327 | public static final String GITHUB_SQUARE_UNICODE = "\uf092";
328 | public static final String GITHUB_UNICODE = "\uf09b";
329 | public static final String GITLAB_UNICODE = "\uf296";
330 | public static final String GITTIP_UNICODE = "\uf184";
331 | public static final String GIT_SQUARE_UNICODE = "\uf1d2";
332 | public static final String GIT_UNICODE = "\uf1d3";
333 | public static final String GLASS_UNICODE = "\uf000";
334 | public static final String GLIDE_G_UNICODE = "\uf2a6";
335 | public static final String GLIDE_UNICODE = "\uf2a5";
336 | public static final String GLOBE_UNICODE = "\uf0ac";
337 | public static final String GOOGLE_PLUS_CIRCLE_UNICODE = "\uf2b3";
338 | public static final String GOOGLE_PLUS_OFFICIAL_UNICODE = "\uf2b3";
339 | public static final String GOOGLE_PLUS_SQUARE_UNICODE = "\uf0d4";
340 | public static final String GOOGLE_PLUS_UNICODE = "\uf0d5";
341 | public static final String GOOGLE_UNICODE = "\uf1a0";
342 | public static final String GOOGLE_WALLET_UNICODE = "\uf1ee";
343 | public static final String GRADUATION_CAP_UNICODE = "\uf19d";
344 | public static final String GRATIPAY_UNICODE = "\uf184";
345 | public static final String GRAV_UNICODE = "\uf2d6";
346 | public static final String GROUP_UNICODE = "\uf0c0";
347 | public static final String HACKER_NEWS_UNICODE = "\uf1d4";
348 | public static final String HANDSHAKE_O_UNICODE = "\uf2b5";
349 | public static final String HAND_GRAB_O_UNICODE = "\uf255";
350 | public static final String HAND_LIZARD_O_UNICODE = "\uf258";
351 | public static final String HAND_O_DOWN_UNICODE = "\uf0a7";
352 | public static final String HAND_O_LEFT_UNICODE = "\uf0a5";
353 | public static final String HAND_O_RIGHT_UNICODE = "\uf0a4";
354 | public static final String HAND_O_UP_UNICODE = "\uf0a6";
355 | public static final String HAND_PAPER_O_UNICODE = "\uf256";
356 | public static final String HAND_PEACE_O_UNICODE = "\uf25b";
357 | public static final String HAND_POINTER_O_UNICODE = "\uf25a";
358 | public static final String HAND_ROCK_O_UNICODE = "\uf255";
359 | public static final String HAND_SCISSORS_O_UNICODE = "\uf257";
360 | public static final String HAND_SPOCK_O_UNICODE = "\uf259";
361 | public static final String HAND_STOP_O_UNICODE = "\uf256";
362 | public static final String HARD_OF_HEARING_UNICODE = "\uf2a4";
363 | public static final String HASHTAG_UNICODE = "\uf292";
364 | public static final String HDD_O_UNICODE = "\uf0a0";
365 | public static final String HEADER_UNICODE = "\uf1dc";
366 | public static final String HEADPHONES_UNICODE = "\uf025";
367 | public static final String HEARTBEAT_UNICODE = "\uf21e";
368 | public static final String HEART_O_UNICODE = "\uf08a";
369 | public static final String HEART_UNICODE = "\uf004";
370 | public static final String HISTORY_UNICODE = "\uf1da";
371 | public static final String HOME_UNICODE = "\uf015";
372 | public static final String HOSPITAL_O_UNICODE = "\uf0f8";
373 | public static final String HOTEL_UNICODE = "\uf236";
374 | public static final String HOURGLASS_1_UNICODE = "\uf251";
375 | public static final String HOURGLASS_2_UNICODE = "\uf252";
376 | public static final String HOURGLASS_3_UNICODE = "\uf253";
377 | public static final String HOURGLASS_END_UNICODE = "\uf253";
378 | public static final String HOURGLASS_HALF_UNICODE = "\uf252";
379 | public static final String HOURGLASS_O_UNICODE = "\uf250";
380 | public static final String HOURGLASS_START_UNICODE = "\uf251";
381 | public static final String HOURGLASS_UNICODE = "\uf254";
382 | public static final String HOUZZ_UNICODE = "\uf27c";
383 | public static final String HTML5_UNICODE = "\uf13b";
384 | public static final String H_SQUARE_UNICODE = "\uf0fd";
385 | public static final String ID_BADGE_UNICODE = "\uf2c1";
386 | public static final String ID_CARD_O_UNICODE = "\uf2c3";
387 | public static final String ID_CARD_UNICODE = "\uf2c2";
388 | public static final String ILS_UNICODE = "\uf20b";
389 | public static final String IMAGE_UNICODE = "\uf03e";
390 | public static final String IMDB_UNICODE = "\uf2d8";
391 | public static final String INBOX_UNICODE = "\uf01c";
392 | public static final String INDENT_UNICODE = "\uf03c";
393 | public static final String INDUSTRY_UNICODE = "\uf275";
394 | public static final String INFO_CIRCLE_UNICODE = "\uf05a";
395 | public static final String INFO_UNICODE = "\uf129";
396 | public static final String INR_UNICODE = "\uf156";
397 | public static final String INSTAGRAM_UNICODE = "\uf16d";
398 | public static final String INSTITUTION_UNICODE = "\uf19c";
399 | public static final String INTERNET_EXPLORER_UNICODE = "\uf26b";
400 | public static final String INTERSEX_UNICODE = "\uf224";
401 | public static final String IOXHOST_UNICODE = "\uf208";
402 | public static final String ITALIC_UNICODE = "\uf033";
403 | public static final String I_CURSOR_UNICODE = "\uf246";
404 | public static final String JOOMLA_UNICODE = "\uf1aa";
405 | public static final String JPY_UNICODE = "\uf157";
406 | public static final String JSFIDDLE_UNICODE = "\uf1cc";
407 | public static final String KEYBOARD_O_UNICODE = "\uf11c";
408 | public static final String KEY_UNICODE = "\uf084";
409 | public static final String KRW_UNICODE = "\uf159";
410 | public static final String LANGUAGE_UNICODE = "\uf1ab";
411 | public static final String LAPTOP_UNICODE = "\uf109";
412 | public static final String LASTFM_SQUARE_UNICODE = "\uf203";
413 | public static final String LASTFM_UNICODE = "\uf202";
414 | public static final String LEAF_UNICODE = "\uf06c";
415 | public static final String LEANPUB_UNICODE = "\uf212";
416 | public static final String LEGAL_UNICODE = "\uf0e3";
417 | public static final String LEMON_O_UNICODE = "\uf094";
418 | public static final String LEVEL_DOWN_UNICODE = "\uf149";
419 | public static final String LEVEL_UP_UNICODE = "\uf148";
420 | public static final String LIFE_BOUY_UNICODE = "\uf1cd";
421 | public static final String LIFE_BUOY_UNICODE = "\uf1cd";
422 | public static final String LIFE_RING_UNICODE = "\uf1cd";
423 | public static final String LIFE_SAVER_UNICODE = "\uf1cd";
424 | public static final String LIGHTBULB_O_UNICODE = "\uf0eb";
425 | public static final String LINE_CHART_UNICODE = "\uf201";
426 | public static final String LINKEDIN_SQUARE_UNICODE = "\uf08c";
427 | public static final String LINKEDIN_UNICODE = "\uf0e1";
428 | public static final String LINK_UNICODE = "\uf0c1";
429 | public static final String LINODE_UNICODE = "\uf2b8";
430 | public static final String LINUX_UNICODE = "\uf17c";
431 | public static final String LIST_ALT_UNICODE = "\uf022";
432 | public static final String LIST_OL_UNICODE = "\uf0cb";
433 | public static final String LIST_UL_UNICODE = "\uf0ca";
434 | public static final String LIST_UNICODE = "\uf03a";
435 | public static final String LOCATION_ARROW_UNICODE = "\uf124";
436 | public static final String LOCK_UNICODE = "\uf023";
437 | public static final String LONG_ARROW_DOWN_UNICODE = "\uf175";
438 | public static final String LONG_ARROW_LEFT_UNICODE = "\uf177";
439 | public static final String LONG_ARROW_RIGHT_UNICODE = "\uf178";
440 | public static final String LONG_ARROW_UP_UNICODE = "\uf176";
441 | public static final String LOW_VISION_UNICODE = "\uf2a8";
442 | public static final String MAGIC_UNICODE = "\uf0d0";
443 | public static final String MAGNET_UNICODE = "\uf076";
444 | public static final String MAIL_FORWARD_UNICODE = "\uf064";
445 | public static final String MAIL_REPLY_ALL_UNICODE = "\uf122";
446 | public static final String MAIL_REPLY_UNICODE = "\uf112";
447 | public static final String MALE_UNICODE = "\uf183";
448 | public static final String MAP_MARKER_UNICODE = "\uf041";
449 | public static final String MAP_O_UNICODE = "\uf278";
450 | public static final String MAP_PIN_UNICODE = "\uf276";
451 | public static final String MAP_SIGNS_UNICODE = "\uf277";
452 | public static final String MAP_UNICODE = "\uf279";
453 | public static final String MARS_DOUBLE_UNICODE = "\uf227";
454 | public static final String MARS_STROKE_H_UNICODE = "\uf22b";
455 | public static final String MARS_STROKE_UNICODE = "\uf229";
456 | public static final String MARS_STROKE_V_UNICODE = "\uf22a";
457 | public static final String MARS_UNICODE = "\uf222";
458 | public static final String MAXCDN_UNICODE = "\uf136";
459 | public static final String MEANPATH_UNICODE = "\uf20c";
460 | public static final String MEDIUM_UNICODE = "\uf23a";
461 | public static final String MEDKIT_UNICODE = "\uf0fa";
462 | public static final String MEETUP_UNICODE = "\uf2e0";
463 | public static final String MEH_O_UNICODE = "\uf11a";
464 | public static final String MERCURY_UNICODE = "\uf223";
465 | public static final String MICROCHIP_UNICODE = "\uf2db";
466 | public static final String MICROPHONE_SLASH_UNICODE = "\uf131";
467 | public static final String MICROPHONE_UNICODE = "\uf130";
468 | public static final String MINUS_CIRCLE_UNICODE = "\uf056";
469 | public static final String MINUS_SQUARE_O_UNICODE = "\uf147";
470 | public static final String MINUS_SQUARE_UNICODE = "\uf146";
471 | public static final String MINUS_UNICODE = "\uf068";
472 | public static final String MIXCLOUD_UNICODE = "\uf289";
473 | public static final String MOBILE_PHONE_UNICODE = "\uf10b";
474 | public static final String MOBILE_UNICODE = "\uf10b";
475 | public static final String MODX_UNICODE = "\uf285";
476 | public static final String MONEY_UNICODE = "\uf0d6";
477 | public static final String MOON_O_UNICODE = "\uf186";
478 | public static final String MORTAR_BOARD_UNICODE = "\uf19d";
479 | public static final String MOTORCYCLE_UNICODE = "\uf21c";
480 | public static final String MOUSE_POINTER_UNICODE = "\uf245";
481 | public static final String MUSIC_UNICODE = "\uf001";
482 | public static final String NAVICON_UNICODE = "\uf0c9";
483 | public static final String NEUTER_UNICODE = "\uf22c";
484 | public static final String NEWSPAPER_O_UNICODE = "\uf1ea";
485 | public static final String OBJECT_GROUP_UNICODE = "\uf247";
486 | public static final String OBJECT_UNGROUP_UNICODE = "\uf248";
487 | public static final String ODNOKLASSNIKI_SQUARE_UNICODE = "\uf264";
488 | public static final String ODNOKLASSNIKI_UNICODE = "\uf263";
489 | public static final String OPENCART_UNICODE = "\uf23d";
490 | public static final String OPENID_UNICODE = "\uf19b";
491 | public static final String OPERA_UNICODE = "\uf26a";
492 | public static final String OPTIN_MONSTER_UNICODE = "\uf23c";
493 | public static final String OUTDENT_UNICODE = "\uf03b";
494 | public static final String PAGELINES_UNICODE = "\uf18c";
495 | public static final String PAINT_BRUSH_UNICODE = "\uf1fc";
496 | public static final String PAPERCLIP_UNICODE = "\uf0c6";
497 | public static final String PAPER_PLANE_O_UNICODE = "\uf1d9";
498 | public static final String PAPER_PLANE_UNICODE = "\uf1d8";
499 | public static final String PARAGRAPH_UNICODE = "\uf1dd";
500 | public static final String PASTE_UNICODE = "\uf0ea";
501 | public static final String PAUSE_CIRCLE_O_UNICODE = "\uf28c";
502 | public static final String PAUSE_CIRCLE_UNICODE = "\uf28b";
503 | public static final String PAUSE_UNICODE = "\uf04c";
504 | public static final String PAW_UNICODE = "\uf1b0";
505 | public static final String PAYPAL_UNICODE = "\uf1ed";
506 | public static final String PENCIL_SQUARE_O_UNICODE = "\uf044";
507 | public static final String PENCIL_SQUARE_UNICODE = "\uf14b";
508 | public static final String PENCIL_UNICODE = "\uf040";
509 | public static final String PERCENT_UNICODE = "\uf295";
510 | public static final String PHONE_SQUARE_UNICODE = "\uf098";
511 | public static final String PHONE_UNICODE = "\uf095";
512 | public static final String PHOTO_UNICODE = "\uf03e";
513 | public static final String PICTURE_O_UNICODE = "\uf03e";
514 | public static final String PIED_PIPER_ALT_UNICODE = "\uf1a8";
515 | public static final String PIED_PIPER_PP_UNICODE = "\uf1a7";
516 | public static final String PIED_PIPER_UNICODE = "\uf2ae";
517 | public static final String PIE_CHART_UNICODE = "\uf200";
518 | public static final String PINTEREST_P_UNICODE = "\uf231";
519 | public static final String PINTEREST_SQUARE_UNICODE = "\uf0d3";
520 | public static final String PINTEREST_UNICODE = "\uf0d2";
521 | public static final String PLANE_UNICODE = "\uf072";
522 | public static final String PLAY_CIRCLE_O_UNICODE = "\uf01d";
523 | public static final String PLAY_CIRCLE_UNICODE = "\uf144";
524 | public static final String PLAY_UNICODE = "\uf04b";
525 | public static final String PLUG_UNICODE = "\uf1e6";
526 | public static final String PLUS_CIRCLE_UNICODE = "\uf055";
527 | public static final String PLUS_SQUARE_O_UNICODE = "\uf196";
528 | public static final String PLUS_SQUARE_UNICODE = "\uf0fe";
529 | public static final String PLUS_UNICODE = "\uf067";
530 | public static final String PODCAST_UNICODE = "\uf2ce";
531 | public static final String POWER_OFF_UNICODE = "\uf011";
532 | public static final String PRINT_UNICODE = "\uf02f";
533 | public static final String PRODUCT_HUNT_UNICODE = "\uf288";
534 | public static final String PUZZLE_PIECE_UNICODE = "\uf12e";
535 | public static final String QQ_UNICODE = "\uf1d6";
536 | public static final String QRCODE_UNICODE = "\uf029";
537 | public static final String QUESTION_CIRCLE_O_UNICODE = "\uf29c";
538 | public static final String QUESTION_CIRCLE_UNICODE = "\uf059";
539 | public static final String QUESTION_UNICODE = "\uf128";
540 | public static final String QUORA_UNICODE = "\uf2c4";
541 | public static final String QUOTE_LEFT_UNICODE = "\uf10d";
542 | public static final String QUOTE_RIGHT_UNICODE = "\uf10e";
543 | public static final String RANDOM_UNICODE = "\uf074";
544 | public static final String RAVELRY_UNICODE = "\uf2d9";
545 | public static final String RA_UNICODE = "\uf1d0";
546 | public static final String REBEL_UNICODE = "\uf1d0";
547 | public static final String RECYCLE_UNICODE = "\uf1b8";
548 | public static final String REDDIT_ALIEN_UNICODE = "\uf281";
549 | public static final String REDDIT_SQUARE_UNICODE = "\uf1a2";
550 | public static final String REDDIT_UNICODE = "\uf1a1";
551 | public static final String REFRESH_UNICODE = "\uf021";
552 | public static final String REGISTERED_UNICODE = "\uf25d";
553 | public static final String REMOVE_UNICODE = "\uf00d";
554 | public static final String RENREN_UNICODE = "\uf18b";
555 | public static final String REORDER_UNICODE = "\uf0c9";
556 | public static final String REPEAT_UNICODE = "\uf01e";
557 | public static final String REPLY_ALL_UNICODE = "\uf122";
558 | public static final String REPLY_UNICODE = "\uf112";
559 | public static final String RESISTANCE_UNICODE = "\uf1d0";
560 | public static final String RETWEET_UNICODE = "\uf079";
561 | public static final String RMB_UNICODE = "\uf157";
562 | public static final String ROAD_UNICODE = "\uf018";
563 | public static final String ROCKET_UNICODE = "\uf135";
564 | public static final String ROTATE_LEFT_UNICODE = "\uf0e2";
565 | public static final String ROTATE_RIGHT_UNICODE = "\uf01e";
566 | public static final String ROUBLE_UNICODE = "\uf158";
567 | public static final String RSS_SQUARE_UNICODE = "\uf143";
568 | public static final String RSS_UNICODE = "\uf09e";
569 | public static final String RUBLE_UNICODE = "\uf158";
570 | public static final String RUB_UNICODE = "\uf158";
571 | public static final String RUPEE_UNICODE = "\uf156";
572 | public static final String S15_UNICODE = "\uf2cd";
573 | public static final String SAFARI_UNICODE = "\uf267";
574 | public static final String SAVE_UNICODE = "\uf0c7";
575 | public static final String SCISSORS_UNICODE = "\uf0c4";
576 | public static final String SCRIBD_UNICODE = "\uf28a";
577 | public static final String SEARCH_MINUS_UNICODE = "\uf010";
578 | public static final String SEARCH_PLUS_UNICODE = "\uf00e";
579 | public static final String SEARCH_UNICODE = "\uf002";
580 | public static final String SELLSY_UNICODE = "\uf213";
581 | public static final String SEND_O_UNICODE = "\uf1d9";
582 | public static final String SEND_UNICODE = "\uf1d8";
583 | public static final String SERVER_UNICODE = "\uf233";
584 | public static final String SHARE_ALT_SQUARE_UNICODE = "\uf1e1";
585 | public static final String SHARE_ALT_UNICODE = "\uf1e0";
586 | public static final String SHARE_SQUARE_O_UNICODE = "\uf045";
587 | public static final String SHARE_SQUARE_UNICODE = "\uf14d";
588 | public static final String SHARE_UNICODE = "\uf064";
589 | public static final String SHEKEL_UNICODE = "\uf20b";
590 | public static final String SHEQEL_UNICODE = "\uf20b";
591 | public static final String SHIELD_UNICODE = "\uf132";
592 | public static final String SHIP_UNICODE = "\uf21a";
593 | public static final String SHIRTSINBULK_UNICODE = "\uf214";
594 | public static final String SHOPPING_BAG_UNICODE = "\uf290";
595 | public static final String SHOPPING_BASKET_UNICODE = "\uf291";
596 | public static final String SHOPPING_CART_UNICODE = "\uf07a";
597 | public static final String SHOWER_UNICODE = "\uf2cc";
598 | public static final String SIGNAL_UNICODE = "\uf012";
599 | public static final String SIGNING_UNICODE = "\uf2a7";
600 | public static final String SIGN_IN_UNICODE = "\uf090";
601 | public static final String SIGN_LANGUAGE_UNICODE = "\uf2a7";
602 | public static final String SIGN_OUT_UNICODE = "\uf08b";
603 | public static final String SIMPLYBUILT_UNICODE = "\uf215";
604 | public static final String SITEMAP_UNICODE = "\uf0e8";
605 | public static final String SKYATLAS_UNICODE = "\uf216";
606 | public static final String SKYPE_UNICODE = "\uf17e";
607 | public static final String SLACK_UNICODE = "\uf198";
608 | public static final String SLIDERS_UNICODE = "\uf1de";
609 | public static final String SLIDESHARE_UNICODE = "\uf1e7";
610 | public static final String SMILE_O_UNICODE = "\uf118";
611 | public static final String SNAPCHAT_GHOST_UNICODE = "\uf2ac";
612 | public static final String SNAPCHAT_SQUARE_UNICODE = "\uf2ad";
613 | public static final String SNAPCHAT_UNICODE = "\uf2ab";
614 | public static final String SNOWFLAKE_O_UNICODE = "\uf2dc";
615 | public static final String SOCCER_BALL_O_UNICODE = "\uf1e3";
616 | public static final String SORT_ALPHA_ASC_UNICODE = "\uf15d";
617 | public static final String SORT_ALPHA_DESC_UNICODE = "\uf15e";
618 | public static final String SORT_AMOUNT_ASC_UNICODE = "\uf160";
619 | public static final String SORT_AMOUNT_DESC_UNICODE = "\uf161";
620 | public static final String SORT_ASC_UNICODE = "\uf0de";
621 | public static final String SORT_DESC_UNICODE = "\uf0dd";
622 | public static final String SORT_DOWN_UNICODE = "\uf0dd";
623 | public static final String SORT_NUMERIC_ASC_UNICODE = "\uf162";
624 | public static final String SORT_NUMERIC_DESC_UNICODE = "\uf163";
625 | public static final String SORT_UNICODE = "\uf0dc";
626 | public static final String SORT_UP_UNICODE = "\uf0de";
627 | public static final String SOUNDCLOUD_UNICODE = "\uf1be";
628 | public static final String SPACE_SHUTTLE_UNICODE = "\uf197";
629 | public static final String SPINNER_UNICODE = "\uf110";
630 | public static final String SPOON_UNICODE = "\uf1b1";
631 | public static final String SPOTIFY_UNICODE = "\uf1bc";
632 | public static final String SQUARE_O_UNICODE = "\uf096";
633 | public static final String SQUARE_UNICODE = "\uf0c8";
634 | public static final String STACK_EXCHANGE_UNICODE = "\uf18d";
635 | public static final String STACK_OVERFLOW_UNICODE = "\uf16c";
636 | public static final String STAR_HALF_EMPTY_UNICODE = "\uf123";
637 | public static final String STAR_HALF_FULL_UNICODE = "\uf123";
638 | public static final String STAR_HALF_O_UNICODE = "\uf123";
639 | public static final String STAR_HALF_UNICODE = "\uf089";
640 | public static final String STAR_O_UNICODE = "\uf006";
641 | public static final String STAR_UNICODE = "\uf005";
642 | public static final String STEAM_SQUARE_UNICODE = "\uf1b7";
643 | public static final String STEAM_UNICODE = "\uf1b6";
644 | public static final String STEP_BACKWARD_UNICODE = "\uf048";
645 | public static final String STEP_FORWARD_UNICODE = "\uf051";
646 | public static final String STETHOSCOPE_UNICODE = "\uf0f1";
647 | public static final String STICKY_NOTE_O_UNICODE = "\uf24a";
648 | public static final String STICKY_NOTE_UNICODE = "\uf249";
649 | public static final String STOP_CIRCLE_O_UNICODE = "\uf28e";
650 | public static final String STOP_CIRCLE_UNICODE = "\uf28d";
651 | public static final String STOP_UNICODE = "\uf04d";
652 | public static final String STREET_VIEW_UNICODE = "\uf21d";
653 | public static final String STRIKETHROUGH_UNICODE = "\uf0cc";
654 | public static final String STUMBLEUPON_CIRCLE_UNICODE = "\uf1a3";
655 | public static final String STUMBLEUPON_UNICODE = "\uf1a4";
656 | public static final String SUBSCRIPT_UNICODE = "\uf12c";
657 | public static final String SUBWAY_UNICODE = "\uf239";
658 | public static final String SUITCASE_UNICODE = "\uf0f2";
659 | public static final String SUN_O_UNICODE = "\uf185";
660 | public static final String SUPERPOWERS_UNICODE = "\uf2dd";
661 | public static final String SUPERSCRIPT_UNICODE = "\uf12b";
662 | public static final String SUPPORT_UNICODE = "\uf1cd";
663 | public static final String TABLET_UNICODE = "\uf10a";
664 | public static final String TABLE_UNICODE = "\uf0ce";
665 | public static final String TACHOMETER_UNICODE = "\uf0e4";
666 | public static final String TAGS_UNICODE = "\uf02c";
667 | public static final String TAG_UNICODE = "\uf02b";
668 | public static final String TASKS_UNICODE = "\uf0ae";
669 | public static final String TAXI_UNICODE = "\uf1ba";
670 | public static final String TELEGRAM_UNICODE = "\uf2c6";
671 | public static final String TELEVISION_UNICODE = "\uf26c";
672 | public static final String TENCENT_WEIBO_UNICODE = "\uf1d5";
673 | public static final String TERMINAL_UNICODE = "\uf120";
674 | public static final String TEXT_HEIGHT_UNICODE = "\uf034";
675 | public static final String TEXT_WIDTH_UNICODE = "\uf035";
676 | public static final String THEMEISLE_UNICODE = "\uf2b2";
677 | public static final String THERMOMETER_0_UNICODE = "\uf2cb";
678 | public static final String THERMOMETER_1_UNICODE = "\uf2ca";
679 | public static final String THERMOMETER_2_UNICODE = "\uf2c9";
680 | public static final String THERMOMETER_3_UNICODE = "\uf2c8";
681 | public static final String THERMOMETER_4_UNICODE = "\uf2c7";
682 | public static final String THERMOMETER_EMPTY_UNICODE = "\uf2cb";
683 | public static final String THERMOMETER_FULL_UNICODE = "\uf2c7";
684 | public static final String THERMOMETER_HALF_UNICODE = "\uf2c9";
685 | public static final String THERMOMETER_QUARTER_UNICODE = "\uf2ca";
686 | public static final String THERMOMETER_THREE_QUARTERS_UNICODE = "\uf2c8";
687 | public static final String THERMOMETER_UNICODE = "\uf2c7";
688 | public static final String THUMBS_DOWN_UNICODE = "\uf165";
689 | public static final String THUMBS_O_DOWN_UNICODE = "\uf088";
690 | public static final String THUMBS_O_UP_UNICODE = "\uf087";
691 | public static final String THUMBS_UP_UNICODE = "\uf164";
692 | public static final String THUMB_TACK_UNICODE = "\uf08d";
693 | public static final String TH_LARGE_UNICODE = "\uf009";
694 | public static final String TH_LIST_UNICODE = "\uf00b";
695 | public static final String TH_UNICODE = "\uf00a";
696 | public static final String TICKET_UNICODE = "\uf145";
697 | public static final String TIMES_CIRCLE_O_UNICODE = "\uf05c";
698 | public static final String TIMES_CIRCLE_UNICODE = "\uf057";
699 | public static final String TIMES_RECTANGLE_O_UNICODE = "\uf2d4";
700 | public static final String TIMES_RECTANGLE_UNICODE = "\uf2d3";
701 | public static final String TIMES_UNICODE = "\uf00d";
702 | public static final String TINT_UNICODE = "\uf043";
703 | public static final String TOGGLE_DOWN_UNICODE = "\uf150";
704 | public static final String TOGGLE_LEFT_UNICODE = "\uf191";
705 | public static final String TOGGLE_OFF_UNICODE = "\uf204";
706 | public static final String TOGGLE_ON_UNICODE = "\uf205";
707 | public static final String TOGGLE_RIGHT_UNICODE = "\uf152";
708 | public static final String TOGGLE_UP_UNICODE = "\uf151";
709 | public static final String TRADEMARK_UNICODE = "\uf25c";
710 | public static final String TRAIN_UNICODE = "\uf238";
711 | public static final String TRANSGENDER_ALT_UNICODE = "\uf225";
712 | public static final String TRANSGENDER_UNICODE = "\uf224";
713 | public static final String TRASH_O_UNICODE = "\uf014";
714 | public static final String TRASH_UNICODE = "\uf1f8";
715 | public static final String TREE_UNICODE = "\uf1bb";
716 | public static final String TRELLO_UNICODE = "\uf181";
717 | public static final String TRIPADVISOR_UNICODE = "\uf262";
718 | public static final String TROPHY_UNICODE = "\uf091";
719 | public static final String TRUCK_UNICODE = "\uf0d1";
720 | public static final String TRY_UNICODE = "\uf195";
721 | public static final String TTY_UNICODE = "\uf1e4";
722 | public static final String TUMBLR_SQUARE_UNICODE = "\uf174";
723 | public static final String TUMBLR_UNICODE = "\uf173";
724 | public static final String TURKISH_LIRA_UNICODE = "\uf195";
725 | public static final String TV_UNICODE = "\uf26c";
726 | public static final String TWITCH_UNICODE = "\uf1e8";
727 | public static final String TWITTER_SQUARE_UNICODE = "\uf081";
728 | public static final String TWITTER_UNICODE = "\uf099";
729 | public static final String UMBRELLA_UNICODE = "\uf0e9";
730 | public static final String UNDERLINE_UNICODE = "\uf0cd";
731 | public static final String UNDO_UNICODE = "\uf0e2";
732 | public static final String UNIVERSAL_ACCESS_UNICODE = "\uf29a";
733 | public static final String UNIVERSITY_UNICODE = "\uf19c";
734 | public static final String UNLINK_UNICODE = "\uf127";
735 | public static final String UNLOCK_ALT_UNICODE = "\uf13e";
736 | public static final String UNLOCK_UNICODE = "\uf09c";
737 | public static final String UNSORTED_UNICODE = "\uf0dc";
738 | public static final String UPLOAD_UNICODE = "\uf093";
739 | public static final String USB_UNICODE = "\uf287";
740 | public static final String USD_UNICODE = "\uf155";
741 | public static final String USERS_UNICODE = "\uf0c0";
742 | public static final String USER_CIRCLE_O_UNICODE = "\uf2be";
743 | public static final String USER_CIRCLE_UNICODE = "\uf2bd";
744 | public static final String USER_MD_UNICODE = "\uf0f0";
745 | public static final String USER_O_UNICODE = "\uf2c0";
746 | public static final String USER_PLUS_UNICODE = "\uf234";
747 | public static final String USER_SECRET_UNICODE = "\uf21b";
748 | public static final String USER_TIMES_UNICODE = "\uf235";
749 | public static final String USER_UNICODE = "\uf007";
750 | public static final String VCARD_O_UNICODE = "\uf2bc";
751 | public static final String VCARD_UNICODE = "\uf2bb";
752 | public static final String VENUS_DOUBLE_UNICODE = "\uf226";
753 | public static final String VENUS_MARS_UNICODE = "\uf228";
754 | public static final String VENUS_UNICODE = "\uf221";
755 | public static final String VIACOIN_UNICODE = "\uf237";
756 | public static final String VIADEO_SQUARE_UNICODE = "\uf2aa";
757 | public static final String VIADEO_UNICODE = "\uf2a9";
758 | public static final String VIDEO_CAMERA_UNICODE = "\uf03d";
759 | public static final String VIMEO_SQUARE_UNICODE = "\uf194";
760 | public static final String VIMEO_UNICODE = "\uf27d";
761 | public static final String VINE_UNICODE = "\uf1ca";
762 | public static final String VK_UNICODE = "\uf189";
763 | public static final String VOLUME_CONTROL_PHONE_UNICODE = "\uf2a0";
764 | public static final String VOLUME_DOWN_UNICODE = "\uf027";
765 | public static final String VOLUME_OFF_UNICODE = "\uf026";
766 | public static final String VOLUME_UP_UNICODE = "\uf028";
767 | public static final String WARNING_UNICODE = "\uf071";
768 | public static final String WECHAT_UNICODE = "\uf1d7";
769 | public static final String WEIBO_UNICODE = "\uf18a";
770 | public static final String WEIXIN_UNICODE = "\uf1d7";
771 | public static final String WHATSAPP_UNICODE = "\uf232";
772 | public static final String WHEELCHAIR_ALT_UNICODE = "\uf29b";
773 | public static final String WHEELCHAIR_UNICODE = "\uf193";
774 | public static final String WIFI_UNICODE = "\uf1eb";
775 | public static final String WIKIPEDIA_W_UNICODE = "\uf266";
776 | public static final String WINDOWS_UNICODE = "\uf17a";
777 | public static final String WINDOW_CLOSE_O_UNICODE = "\uf2d4";
778 | public static final String WINDOW_CLOSE_UNICODE = "\uf2d3";
779 | public static final String WINDOW_MAXIMIZE_UNICODE = "\uf2d0";
780 | public static final String WINDOW_MINIMIZE_UNICODE = "\uf2d1";
781 | public static final String WINDOW_RESTORE_UNICODE = "\uf2d2";
782 | public static final String WON_UNICODE = "\uf159";
783 | public static final String WORDPRESS_UNICODE = "\uf19a";
784 | public static final String WPBEGINNER_UNICODE = "\uf297";
785 | public static final String WPEXPLORER_UNICODE = "\uf2de";
786 | public static final String WPFORMS_UNICODE = "\uf298";
787 | public static final String WRENCH_UNICODE = "\uf0ad";
788 | public static final String XING_SQUARE_UNICODE = "\uf169";
789 | public static final String XING_UNICODE = "\uf168";
790 | public static final String YAHOO_UNICODE = "\uf19e";
791 | public static final String YC_SQUARE_UNICODE = "\uf1d4";
792 | public static final String YC_UNICODE = "\uf23b";
793 | public static final String YELP_UNICODE = "\uf1e9";
794 | public static final String YEN_UNICODE = "\uf157";
795 | public static final String YOAST_UNICODE = "\uf2b1";
796 | public static final String YOUTUBE_PLAY_UNICODE = "\uf16a";
797 | public static final String YOUTUBE_SQUARE_UNICODE = "\uf166";
798 | public static final String YOUTUBE_UNICODE = "\uf167";
799 | public static final String Y_COMBINATOR_SQUARE_UNICODE = "\uf1d4";
800 | public static final String Y_COMBINATOR_UNICODE = "\uf23b";
801 | public static final String _500PX_UNICODE = "\uf26e";
802 |
803 | //endregion
804 |
805 | private static final String FILENAME = "fontawesome-webfont.woff";
806 |
807 | //region Constructors
808 |
809 | /**
810 | * Instantiate a new Font Awesome icon.
811 | */
812 | public Icon() {
813 | super(FILENAME);
814 | }
815 |
816 | /**
817 | * Instantiate a new Font Awesome icon.
818 | *
819 | * @param unicode The unicode of the Font Awesome icon.
820 | */
821 | public Icon(String unicode) {
822 | super(FILENAME, unicode);
823 | }
824 |
825 | //endregion
826 |
827 | @Builder
828 | public Icon(String unicode, Insets padding, Boolean visible, EventHandler super MouseEvent> onMouseClicked, List styleClasses) {
829 | super(FILENAME);
830 | setProperty(unicode, this::setText);
831 | setProperty(padding, this::setPadding);
832 | setProperty(visible, this::setVisible);
833 | setProperty(onMouseClicked, this::setOnMouseClicked);
834 | setProperty(styleClasses, e -> this.getStyleClass().addAll(e));
835 | }
836 | }
837 |
--------------------------------------------------------------------------------