diff --git a/pom.xml b/pom.xml index c738535..3149ddb 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.andrewlalis javafx-scene-router - 1.5.1 + 1.6.0 JavaFX Scene Router A library that provides a router implementation for JavaFX, for browser-like navigation between pages. https://github.com/andrewlalis/javafx-scene-router diff --git a/src/main/java/com/andrewlalis/javafx_scene_router/AnchorPaneRouterView.java b/src/main/java/com/andrewlalis/javafx_scene_router/AnchorPaneRouterView.java index cbff6d1..b2cbe04 100644 --- a/src/main/java/com/andrewlalis/javafx_scene_router/AnchorPaneRouterView.java +++ b/src/main/java/com/andrewlalis/javafx_scene_router/AnchorPaneRouterView.java @@ -7,8 +7,7 @@ import javafx.scene.layout.AnchorPane; * A router view implementation using the JavaFX {@link AnchorPane}, so that * route contents can (optionally) be grown to fill all available space. */ -public class AnchorPaneRouterView implements RouterView { - private final AnchorPane anchorPane = new AnchorPane(); +public class AnchorPaneRouterView extends SimpleRouterView { private final boolean expandContents; /** @@ -18,6 +17,7 @@ public class AnchorPaneRouterView implements RouterView { * fill all available space. */ public AnchorPaneRouterView(boolean expandContents) { + super(new AnchorPane()); this.expandContents = expandContents; } @@ -43,14 +43,6 @@ public class AnchorPaneRouterView implements RouterView { AnchorPane.setBottomAnchor(node, 0.0); AnchorPane.setLeftAnchor(node, 0.0); } - anchorPane.getChildren().setAll(node); - } - - /** - * Gets the underlying pane used for rendering. - * @return The anchor pane this view uses. - */ - public AnchorPane getAnchorPane() { - return anchorPane; + super.showRouteNode(node); } } diff --git a/src/main/java/com/andrewlalis/javafx_scene_router/SceneRouter.java b/src/main/java/com/andrewlalis/javafx_scene_router/SceneRouter.java index 79a54c1..b35cf3d 100644 --- a/src/main/java/com/andrewlalis/javafx_scene_router/SceneRouter.java +++ b/src/main/java/com/andrewlalis/javafx_scene_router/SceneRouter.java @@ -102,6 +102,23 @@ public class SceneRouter { return map(route, fxml, null); } + /** + * "Warms up" the route cache by calling each route's supplier once. This + * will cause FXML resources to be loaded, such that all subsequent loads + * are much faster. + * @return A future that's complete once all routes are loaded. + */ + public CompletableFuture loadAllRoutes() { + CompletableFuture cf = new CompletableFuture<>(); + Thread.ofVirtual().start(() -> { + for (Supplier nodeSupplier : routeMap.values()) { + nodeSupplier.get(); + } + cf.complete(null); + }); + return cf; + } + /** * Navigates to a given route, with a given context object. * @param route The route to navigate to. @@ -188,6 +205,34 @@ public class SceneRouter { return cf; } + /** + * Navigates to the given route, clearing any previous history. + * @param route The route to navigate to. + * @param context The context for the route. + * @return A future that resolves once navigation is complete. + */ + public CompletableFuture replace(String route, Object context) { + String oldRoute = currentRouteProperty.get(); + Object oldContext = history.getCurrentContext(); + CompletableFuture cf = new CompletableFuture<>(); + Platform.runLater(() -> { + history.clear(); + history.push(route, context); + setCurrentNode(route, oldRoute, oldContext); + cf.complete(null); + }); + return cf; + } + + /** + * Navigates to the given route, clearing any previous history. + * @param route The route to navigate to. + * @return A future that resolves once navigation is complete. + */ + public CompletableFuture replace(String route) { + return replace(route, null); + } + /** * Gets the context object for the current route. * @return The context object, or null. @@ -282,6 +327,9 @@ public class SceneRouter { if (controller instanceof RouteSelectionListener rsl) { addRouteSelectionListener(route, rsl); } + if (controller instanceof RouteChangeListener rcl) { + addRouteChangeListener(rcl); + } if (controllerCustomizer != null) { if (controller == null) throw new IllegalStateException("No controller found when loading " + resource.toString()); controllerCustomizer.accept(controller); diff --git a/src/main/java/com/andrewlalis/javafx_scene_router/SimplePaneRouterView.java b/src/main/java/com/andrewlalis/javafx_scene_router/SimplePaneRouterView.java deleted file mode 100644 index 124c8f3..0000000 --- a/src/main/java/com/andrewlalis/javafx_scene_router/SimplePaneRouterView.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.andrewlalis.javafx_scene_router; - -import javafx.scene.Parent; -import javafx.scene.layout.Pane; - -/** - * A simple router view implementation that uses a JavaFX Pane, which shows - * the route contents in their preferred minimal size. - */ -public class SimplePaneRouterView implements RouterView { - private final Pane pane = new Pane(); - - /** - * Shows the node in the pane. - * @param node The node to show. - */ - @Override - public void showRouteNode(Parent node) { - pane.getChildren().setAll(node); - } - - /** - * Gets the pane that's used internally to show the contents. - * @return The pane. - */ - public Pane getPane() { - return pane; - } -} diff --git a/src/main/java/com/andrewlalis/javafx_scene_router/SimpleRouterView.java b/src/main/java/com/andrewlalis/javafx_scene_router/SimpleRouterView.java new file mode 100644 index 0000000..8dbe0f0 --- /dev/null +++ b/src/main/java/com/andrewlalis/javafx_scene_router/SimpleRouterView.java @@ -0,0 +1,39 @@ +package com.andrewlalis.javafx_scene_router; + +import javafx.scene.Parent; +import javafx.scene.layout.Pane; + +/** + * A simple implementation of {@link RouterView} which simply keeps a reference + * to a {@link Pane} and displays any route nodes inside that pane by setting + * its only child to the given route node. + * @param The pane type. + */ +public class SimpleRouterView implements RouterView { + /** + * The pane in which route nodes are displayed. + */ + private final T pane; + + /** + * Constructs this router view to use the given pane. + * @param pane The pane to use. + */ + public SimpleRouterView(T pane) { + this.pane = pane; + } + + @Override + public void showRouteNode(Parent node) { + this.pane.getChildren().clear(); + this.pane.getChildren().add(node); + } + + /** + * Gets the pane used by this router view. + * @return The pane used by this router view. + */ + public T getPane() { + return this.pane; + } +} diff --git a/src/main/java/com/andrewlalis/javafx_scene_router/component/RouterLink.java b/src/main/java/com/andrewlalis/javafx_scene_router/component/RouterLink.java new file mode 100644 index 0000000..6f9bdfc --- /dev/null +++ b/src/main/java/com/andrewlalis/javafx_scene_router/component/RouterLink.java @@ -0,0 +1,60 @@ +package com.andrewlalis.javafx_scene_router.component; + +import com.andrewlalis.javafx_scene_router.SceneRouter; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.fxml.FXML; +import javafx.scene.control.Hyperlink; + +/** + * A hyperlink that, when clicked, navigates the user to a specified route. + */ +public class RouterLink extends Hyperlink { + @FXML + private final StringProperty routeProperty = new SimpleStringProperty(this, "route", null); + @FXML + private final ObjectProperty routerProperty = new SimpleObjectProperty<>(this, "router", null); + + private Object context; + + // Route property. + public StringProperty routeProperty() { + return routeProperty; + } + + public final void setRoute(String route) { + this.context = null; + routeProperty.set(route); + setOnAction(event -> { + SceneRouter router = getRouter(); + String currentRoute = getRoute(); + if (router != null && currentRoute != null) { + router.navigate(currentRoute, context); + } + }); + } + + public final void setRoute(String route, Object context) { + this.context = context; + setRoute(route); + } + + public final String getRoute() { + return routeProperty.get(); + } + + // Router property. + public ObjectProperty routerProperty() { + return routerProperty; + } + + public final void setRouter(SceneRouter router) { + routerProperty.set(router); + } + + public final SceneRouter getRouter() { + return routerProperty.get(); + } +} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 12979d8..53be422 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -4,6 +4,9 @@ module com.andrewlalis.javafx_scene_router { requires javafx.fxml; requires javafx.graphics; + requires javafx.controls; exports com.andrewlalis.javafx_scene_router; + exports com.andrewlalis.javafx_scene_router.component; + opens com.andrewlalis.javafx_scene_router.component to javafx.fxml; }