2020-06-06 18:30:09 +02:00
|
|
|
package envoy.client.ui;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.util.Stack;
|
2020-06-13 22:36:52 +02:00
|
|
|
import java.util.logging.Level;
|
2020-06-06 18:30:09 +02:00
|
|
|
|
2020-07-29 21:59:55 +02:00
|
|
|
import javafx.application.Platform;
|
2020-06-06 18:30:09 +02:00
|
|
|
import javafx.fxml.FXMLLoader;
|
2020-09-08 20:41:01 +02:00
|
|
|
import javafx.scene.*;
|
2020-06-06 18:30:09 +02:00
|
|
|
import javafx.stage.Stage;
|
|
|
|
|
2020-10-18 15:16:46 +02:00
|
|
|
import dev.kske.eventbus.*;
|
|
|
|
|
|
|
|
import envoy.util.EnvoyLog;
|
|
|
|
|
2020-06-06 18:30:09 +02:00
|
|
|
import envoy.client.data.Settings;
|
2020-10-12 16:12:23 +02:00
|
|
|
import envoy.client.data.shortcuts.*;
|
2020-09-24 18:00:59 +02:00
|
|
|
import envoy.client.event.*;
|
2020-09-08 20:41:01 +02:00
|
|
|
|
2020-06-06 18:30:09 +02:00
|
|
|
/**
|
2020-10-18 15:16:46 +02:00
|
|
|
* Manages a stack of scenes. The most recently added scene is displayed inside a stage. When a
|
|
|
|
* scene is removed from the stack, its predecessor is displayed.
|
2020-06-08 09:14:57 +02:00
|
|
|
* <p>
|
2020-10-18 15:16:46 +02:00
|
|
|
* When a scene is loaded, the style sheet for the current theme is applied to it.
|
2020-06-13 22:36:52 +02:00
|
|
|
*
|
2020-06-06 18:30:09 +02:00
|
|
|
* @author Kai S. K. Engelbart
|
|
|
|
* @since Envoy Client v0.1-beta
|
|
|
|
*/
|
2020-09-08 20:41:01 +02:00
|
|
|
public final class SceneContext implements EventListener {
|
2020-06-06 18:30:09 +02:00
|
|
|
|
2020-06-08 11:58:57 +02:00
|
|
|
/**
|
|
|
|
* Contains information about different scenes and their FXML resource files.
|
2020-06-13 22:36:52 +02:00
|
|
|
*
|
2020-06-08 11:58:57 +02:00
|
|
|
* @author Kai S. K. Engelbart
|
|
|
|
* @since Envoy Client v0.1-beta
|
|
|
|
*/
|
2020-06-13 22:36:52 +02:00
|
|
|
public enum SceneInfo {
|
2020-06-06 18:30:09 +02:00
|
|
|
|
2020-06-08 11:58:57 +02:00
|
|
|
/**
|
2020-06-30 21:20:54 +02:00
|
|
|
* The main scene in which the chat screen is displayed.
|
2020-06-13 22:36:52 +02:00
|
|
|
*
|
2020-06-08 11:58:57 +02:00
|
|
|
* @since Envoy Client v0.1-beta
|
|
|
|
*/
|
|
|
|
CHAT_SCENE("/fxml/ChatScene.fxml"),
|
|
|
|
|
|
|
|
/**
|
2020-06-30 21:20:54 +02:00
|
|
|
* The scene in which the settings screen is displayed.
|
2020-06-13 22:36:52 +02:00
|
|
|
*
|
2020-06-08 11:58:57 +02:00
|
|
|
* @since Envoy Client v0.1-beta
|
|
|
|
*/
|
|
|
|
SETTINGS_SCENE("/fxml/SettingsScene.fxml"),
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The scene in which the login screen is displayed.
|
2020-06-13 22:36:52 +02:00
|
|
|
*
|
2020-06-08 11:58:57 +02:00
|
|
|
* @since Envoy Client v0.1-beta
|
|
|
|
*/
|
2020-08-22 21:02:49 +02:00
|
|
|
LOGIN_SCENE("/fxml/LoginScene.fxml");
|
2020-06-08 11:58:57 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The path to the FXML resource.
|
|
|
|
*/
|
2020-06-06 18:30:09 +02:00
|
|
|
public final String path;
|
|
|
|
|
2020-10-18 15:16:46 +02:00
|
|
|
SceneInfo(String path) {
|
|
|
|
this.path = path;
|
|
|
|
}
|
2020-06-06 18:30:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private final Stage stage;
|
2020-07-04 15:26:12 +02:00
|
|
|
private final FXMLLoader loader = new FXMLLoader();
|
|
|
|
private final Stack<Scene> sceneStack = new Stack<>();
|
|
|
|
private final Stack<Object> controllerStack = new Stack<>();
|
2020-06-06 18:30:09 +02:00
|
|
|
|
|
|
|
private static final Settings settings = Settings.getInstance();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes the scene context.
|
2020-06-13 22:36:52 +02:00
|
|
|
*
|
2020-06-06 18:30:09 +02:00
|
|
|
* @param stage the stage in which scenes will be displayed
|
|
|
|
* @since Envoy Client v0.1-beta
|
|
|
|
*/
|
|
|
|
public SceneContext(Stage stage) {
|
|
|
|
this.stage = stage;
|
2020-09-08 20:41:01 +02:00
|
|
|
EventBus.getInstance().registerListener(this);
|
2020-06-06 18:30:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Loads a new scene specified by a scene info.
|
2020-06-13 22:36:52 +02:00
|
|
|
*
|
2020-06-06 18:30:09 +02:00
|
|
|
* @param sceneInfo specifies the scene to load
|
2020-06-08 11:58:57 +02:00
|
|
|
* @throws RuntimeException if the loading process fails
|
2020-06-06 18:30:09 +02:00
|
|
|
* @since Envoy Client v0.1-beta
|
|
|
|
*/
|
2020-06-08 11:58:57 +02:00
|
|
|
public void load(SceneInfo sceneInfo) {
|
2020-09-24 18:00:59 +02:00
|
|
|
EnvoyLog.getLogger(SceneContext.class).log(Level.FINER, "Loading scene " + sceneInfo);
|
2020-06-06 18:30:09 +02:00
|
|
|
loader.setRoot(null);
|
|
|
|
loader.setController(null);
|
|
|
|
|
2020-06-08 11:58:57 +02:00
|
|
|
try {
|
2020-10-18 15:16:46 +02:00
|
|
|
final var rootNode =
|
|
|
|
(Parent) loader.load(getClass().getResourceAsStream(sceneInfo.path));
|
2020-06-08 11:58:57 +02:00
|
|
|
final var scene = new Scene(rootNode);
|
2020-10-12 16:12:23 +02:00
|
|
|
final var controller = loader.getController();
|
|
|
|
controllerStack.push(controller);
|
2020-06-06 18:30:09 +02:00
|
|
|
|
2020-06-08 11:58:57 +02:00
|
|
|
sceneStack.push(scene);
|
|
|
|
stage.setScene(scene);
|
2020-09-20 22:11:15 +02:00
|
|
|
|
2020-10-12 16:12:23 +02:00
|
|
|
// Supply the global custom keyboard shortcuts for that scene
|
2020-10-18 15:16:46 +02:00
|
|
|
scene.getAccelerators()
|
|
|
|
.putAll(GlobalKeyShortcuts.getInstance().getKeyboardShortcuts(sceneInfo));
|
2020-10-12 16:12:23 +02:00
|
|
|
|
|
|
|
// Supply the scene specific keyboard shortcuts
|
2020-10-18 15:16:46 +02:00
|
|
|
if (controller instanceof KeyboardMapping)
|
|
|
|
scene.getAccelerators()
|
|
|
|
.putAll(((KeyboardMapping) controller).getKeyboardShortcuts());
|
2020-09-20 22:11:15 +02:00
|
|
|
|
2020-07-29 21:59:55 +02:00
|
|
|
// The LoginScene is the only scene not intended to be resized
|
|
|
|
// As strange as it seems, this is needed as otherwise the LoginScene won't be
|
|
|
|
// displayed on some OS (...Debian...)
|
2020-08-01 10:04:53 +02:00
|
|
|
stage.sizeToScene();
|
2020-07-29 21:59:55 +02:00
|
|
|
Platform.runLater(() -> stage.setResizable(sceneInfo != SceneInfo.LOGIN_SCENE));
|
2020-06-08 11:58:57 +02:00
|
|
|
applyCSS();
|
|
|
|
stage.show();
|
2020-06-13 22:36:52 +02:00
|
|
|
} catch (final IOException e) {
|
2020-10-18 15:16:46 +02:00
|
|
|
EnvoyLog.getLogger(SceneContext.class)
|
|
|
|
.log(Level.SEVERE, String.format("Could not load scene for %s: ", sceneInfo),
|
|
|
|
e);
|
2020-06-08 11:58:57 +02:00
|
|
|
throw new RuntimeException(e);
|
|
|
|
}
|
2020-06-06 18:30:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes the current scene and displays the previous one.
|
2020-06-13 22:36:52 +02:00
|
|
|
*
|
2020-06-06 18:30:09 +02:00
|
|
|
* @since Envoy Client v0.1-beta
|
|
|
|
*/
|
|
|
|
public void pop() {
|
2020-09-02 10:07:02 +02:00
|
|
|
|
|
|
|
// Pop scene and controller
|
|
|
|
sceneStack.pop();
|
|
|
|
controllerStack.pop();
|
|
|
|
|
|
|
|
// Apply new scene if present
|
2020-06-08 08:45:15 +02:00
|
|
|
if (!sceneStack.isEmpty()) {
|
2020-07-04 15:26:12 +02:00
|
|
|
final var newScene = sceneStack.peek();
|
|
|
|
stage.setScene(newScene);
|
2020-06-08 08:45:15 +02:00
|
|
|
applyCSS();
|
2020-06-10 10:05:25 +02:00
|
|
|
stage.sizeToScene();
|
2020-07-04 15:26:12 +02:00
|
|
|
// If the controller implements the Restorable interface,
|
|
|
|
// the actions to perform on restoration will be executed here
|
2020-07-04 16:07:10 +02:00
|
|
|
final var controller = controllerStack.peek();
|
2020-10-18 15:16:46 +02:00
|
|
|
if (controller instanceof Restorable)
|
|
|
|
((Restorable) controller).onRestore();
|
2020-06-08 08:45:15 +02:00
|
|
|
}
|
2020-06-06 18:30:09 +02:00
|
|
|
stage.show();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void applyCSS() {
|
|
|
|
if (!sceneStack.isEmpty()) {
|
|
|
|
final var styleSheets = stage.getScene().getStylesheets();
|
2020-06-08 10:02:39 +02:00
|
|
|
final var themeCSS = "/css/" + settings.getCurrentTheme() + ".css";
|
2020-06-06 18:30:09 +02:00
|
|
|
styleSheets.clear();
|
2020-10-18 15:16:46 +02:00
|
|
|
styleSheets.addAll(getClass().getResource("/css/base.css").toExternalForm(),
|
|
|
|
getClass().getResource(themeCSS).toExternalForm());
|
2020-06-06 18:30:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-24 18:00:59 +02:00
|
|
|
@Event(eventType = Logout.class, priority = 150)
|
|
|
|
private void onLogout() {
|
|
|
|
sceneStack.clear();
|
|
|
|
controllerStack.clear();
|
|
|
|
}
|
|
|
|
|
2020-09-08 20:41:01 +02:00
|
|
|
@Event(priority = 150, eventType = ThemeChangeEvent.class)
|
2020-10-18 15:16:46 +02:00
|
|
|
private void onThemeChange() {
|
|
|
|
applyCSS();
|
|
|
|
}
|
2020-09-08 20:41:01 +02:00
|
|
|
|
2020-06-06 18:30:09 +02:00
|
|
|
/**
|
|
|
|
* @param <T> the type of the controller
|
|
|
|
* @return the controller used by the current scene
|
|
|
|
* @since Envoy Client v0.1-beta
|
|
|
|
*/
|
2020-07-04 15:26:12 +02:00
|
|
|
public <T> T getController() { return (T) controllerStack.peek(); }
|
2020-06-08 11:58:57 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the stage in which the scenes are displayed
|
|
|
|
* @since Envoy Client v0.1-beta
|
|
|
|
*/
|
|
|
|
public Stage getStage() { return stage; }
|
2020-09-02 10:07:02 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @return whether the scene stack is empty
|
|
|
|
* @since Envoy Client v0.2-beta
|
|
|
|
*/
|
|
|
|
public boolean isEmpty() { return sceneStack.isEmpty(); }
|
2020-06-06 18:30:09 +02:00
|
|
|
}
|