Added initial content
This commit is contained in:
parent
78d0c79b5a
commit
7ff7716971
|
@ -0,0 +1,39 @@
|
||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea/modules.xml
|
||||||
|
.idea/jarRepositories.xml
|
||||||
|
.idea/compiler.xml
|
||||||
|
.idea/libraries/
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
.idea
|
||||||
|
|
||||||
|
### Eclipse ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
### Mac OS ###
|
||||||
|
.DS_Store
|
|
@ -0,0 +1,151 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.andrewlalis</groupId>
|
||||||
|
<artifactId>javafx-scene-router</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>JavaFX Scene Router</name>
|
||||||
|
<description>A library that provides a router implementation for JavaFX, for browser-like navigation between pages.</description>
|
||||||
|
<url>https://github.com/andrewlalis/javafx-scene-router</url>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<javafx.version>21.0.1</javafx.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-controls</artifactId>
|
||||||
|
<version>${javafx.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjfx</groupId>
|
||||||
|
<artifactId>javafx-fxml</artifactId>
|
||||||
|
<version>${javafx.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
<version>3.2.1</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>attach-sources</id>
|
||||||
|
<goals>
|
||||||
|
<goal>jar-no-fork</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
<version>3.3.1</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>attach-javadocs</id>
|
||||||
|
<goals>
|
||||||
|
<goal>jar</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-gpg-plugin</artifactId>
|
||||||
|
<version>3.1.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>sign-artifacts</id>
|
||||||
|
<phase>verify</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>sign</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>net.ju-n.maven.plugins</groupId>
|
||||||
|
<artifactId>checksum-maven-plugin</artifactId>
|
||||||
|
<version>1.4</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>checksum-maven-plugin-files</id>
|
||||||
|
<phase>verify</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>files</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<fileSets>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.build.directory}</directory>
|
||||||
|
<includes>
|
||||||
|
<include>*.pom</include>
|
||||||
|
<include>*.jar</include>
|
||||||
|
</includes>
|
||||||
|
</fileSet>
|
||||||
|
</fileSets>
|
||||||
|
<algorithms>
|
||||||
|
<algorithm>SHA-1</algorithm>
|
||||||
|
<algorithm>MD5</algorithm>
|
||||||
|
<algorithm>SHA-256</algorithm>
|
||||||
|
<algorithm>SHA-512</algorithm>
|
||||||
|
</algorithms>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.sonatype.plugins</groupId>
|
||||||
|
<artifactId>nexus-staging-maven-plugin</artifactId>
|
||||||
|
<version>1.6.13</version>
|
||||||
|
<extensions>true</extensions>
|
||||||
|
<configuration>
|
||||||
|
<serverId>ossrh</serverId>
|
||||||
|
<nexusUrl>https://s01.oss.sonatype.org</nexusUrl>
|
||||||
|
<autoReleaseAfterClose>false</autoReleaseAfterClose>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<scm>
|
||||||
|
<url>https://github.com/andrewlalis/javafx-scene-router</url>
|
||||||
|
<connection>scm:git:git://github.com/andrewlalis/javafx-scene-router.git</connection>
|
||||||
|
<developerConnection>scm:git:ssh://github.com/andrewlalis/javafx-scene-router.git</developerConnection>
|
||||||
|
</scm>
|
||||||
|
|
||||||
|
<licenses>
|
||||||
|
<license>
|
||||||
|
<name>MIT License</name>
|
||||||
|
<url>https://www.opensource.org/licenses/mit-license.php</url>
|
||||||
|
</license>
|
||||||
|
</licenses>
|
||||||
|
|
||||||
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<name>Andrew Lalis</name>
|
||||||
|
<email>andrewlalisofficial@gmail.com</email>
|
||||||
|
</developer>
|
||||||
|
</developers>
|
||||||
|
|
||||||
|
<distributionManagement>
|
||||||
|
<snapshotRepository>
|
||||||
|
<id>ossrh</id>
|
||||||
|
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
|
||||||
|
</snapshotRepository>
|
||||||
|
<repository>
|
||||||
|
<id>ossrh</id>
|
||||||
|
<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
||||||
|
</repository>
|
||||||
|
</distributionManagement>
|
||||||
|
</project>
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.andrewlalis.javafx_scene_router;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A breadcrumb entry that represents one item in a route history.
|
||||||
|
* @param label The display label.
|
||||||
|
* @param route The route.
|
||||||
|
* @param context The context object for this route.
|
||||||
|
* @param current Whether the history this was generated from is at this route right now.
|
||||||
|
*/
|
||||||
|
public record BreadCrumb(String label, String route, Object context, boolean current) {}
|
|
@ -0,0 +1,127 @@
|
||||||
|
package com.andrewlalis.javafx_scene_router;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A component that tracks navigation history through a series of routes, and
|
||||||
|
* provides facilities for navigating forward and backward through the history,
|
||||||
|
* as well as pushing new routes into the history.
|
||||||
|
* <p>
|
||||||
|
* This history is designed to work much like a typical web browser, where
|
||||||
|
* a linear history is maintained, such that you can move backward and
|
||||||
|
* forward along the history, but once you navigate to a new page, any
|
||||||
|
* forward-history is cleared.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class RouteHistory {
|
||||||
|
private final List<RouteHistoryItem> items = new ArrayList<>();
|
||||||
|
private int currentItemIndex = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new history instance.
|
||||||
|
*/
|
||||||
|
public RouteHistory() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pushes a new route after the current place in the history, and clears
|
||||||
|
* all forward-routes beyond that.
|
||||||
|
* @param route The route to push.
|
||||||
|
* @param context The context object associated with the route.
|
||||||
|
*/
|
||||||
|
public void push(String route, Object context) {
|
||||||
|
int nextIndex = currentItemIndex + 1;
|
||||||
|
items.subList(nextIndex, items.size()).clear();
|
||||||
|
items.add(nextIndex, new RouteHistoryItem(route, context));
|
||||||
|
currentItemIndex = nextIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current context object, or null if none is set.
|
||||||
|
* @return The context object associated with the current route.
|
||||||
|
* @param <T> The type to implicitly cast to. Note that this may result in
|
||||||
|
* an unchecked exception if you attempt to coerce to an invalid
|
||||||
|
* type.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T getCurrentContext() {
|
||||||
|
if (currentItemIndex >= 0 && currentItemIndex < items.size()) {
|
||||||
|
return (T) items.get(currentItemIndex).context();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if it's possible to navigate back in the history.
|
||||||
|
* @return True if it is possible to go back.
|
||||||
|
*/
|
||||||
|
public boolean canGoBack() {
|
||||||
|
return currentItemIndex > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to go back in the history.
|
||||||
|
* @return If successful, the previous history item that we went back to;
|
||||||
|
* empty otherwise.
|
||||||
|
*/
|
||||||
|
public Optional<RouteHistoryItem> back() {
|
||||||
|
if (canGoBack()) {
|
||||||
|
RouteHistoryItem prev = items.get(currentItemIndex - 1);
|
||||||
|
currentItemIndex--;
|
||||||
|
return Optional.of(prev);
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if it's possible to navigate forward in the history.
|
||||||
|
* @return True if it is possible to go forward.
|
||||||
|
*/
|
||||||
|
public boolean canGoForward() {
|
||||||
|
return currentItemIndex + 1 < items.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to go forward in the history.
|
||||||
|
* @return If successful, the next history item that we went forward to;
|
||||||
|
* empty otherwise.
|
||||||
|
*/
|
||||||
|
public Optional<RouteHistoryItem> forward() {
|
||||||
|
if (canGoForward()) {
|
||||||
|
RouteHistoryItem next = items.get(currentItemIndex + 1);
|
||||||
|
currentItemIndex++;
|
||||||
|
return Optional.of(next);
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the history completely.
|
||||||
|
*/
|
||||||
|
public void clear() {
|
||||||
|
items.clear();
|
||||||
|
currentItemIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of "breadcrumbs", or a representation of the current history
|
||||||
|
* and indication of where we are in that history.
|
||||||
|
* @return The list of breadcrumbs.
|
||||||
|
*/
|
||||||
|
public List<BreadCrumb> getBreadCrumbs() {
|
||||||
|
if (items.isEmpty()) return Collections.emptyList();
|
||||||
|
List<BreadCrumb> breadCrumbs = new ArrayList<>(items.size());
|
||||||
|
for (int i = 0; i < items.size(); i++) {
|
||||||
|
var item = items.get(i);
|
||||||
|
breadCrumbs.add(new BreadCrumb(
|
||||||
|
item.route(),
|
||||||
|
item.route(),
|
||||||
|
item.context(),
|
||||||
|
i == currentItemIndex
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return breadCrumbs;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.andrewlalis.javafx_scene_router;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entry that stores information about a point in a user's route history.
|
||||||
|
* @param route The route.
|
||||||
|
* @param context The context object associated with the route.
|
||||||
|
*/
|
||||||
|
record RouteHistoryItem(String route, Object context) {}
|
|
@ -0,0 +1,163 @@
|
||||||
|
package com.andrewlalis.javafx_scene_router;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Parent;
|
||||||
|
import javafx.scene.layout.Pane;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A router that shows different content in a pane depending on which route is
|
||||||
|
* selected. Each router must be initialized with a JavaFX pane, or a consumer
|
||||||
|
* function that's called to set the content each time a new route is selected.
|
||||||
|
* <p>
|
||||||
|
* The router has a mapping of "routes" (think, Strings) to JavaFX Parent
|
||||||
|
* nodes. When a route is selected, the router will lookup the mapped node,
|
||||||
|
* and put that node into the pre-defined pane or consumer function.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* The router maintains a {@link RouteHistory} so that it's possible to
|
||||||
|
* navigate backward and forward, much like a web browser would.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class SceneRouter {
|
||||||
|
private final Consumer<Parent> setter;
|
||||||
|
private final Map<String, Parent> routeMap = new HashMap<>();
|
||||||
|
private final RouteHistory history = new RouteHistory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the router to show route content in the given pane.
|
||||||
|
* @param pane The pane to show route content in.
|
||||||
|
*/
|
||||||
|
public SceneRouter(Pane pane) {
|
||||||
|
this(p -> pane.getChildren().setAll(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the router to supply route content to the given consumer, so
|
||||||
|
* that it may place the content somewhere. For example, you might like to
|
||||||
|
* use this if you'd like to have a router place content in the center of a
|
||||||
|
* {@link javafx.scene.layout.BorderPane}, like so:
|
||||||
|
* <p><code>var router = new SceneRouter(myBorderPane::setCenter);</code></p>
|
||||||
|
* @param setter The consumer that is supplied route content to show.
|
||||||
|
*/
|
||||||
|
public SceneRouter(Consumer<Parent> setter) {
|
||||||
|
this.setter = setter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the given route to a node, so that when the route is selected, the
|
||||||
|
* given node is shown.
|
||||||
|
* @param route The route.
|
||||||
|
* @param node The node to show.
|
||||||
|
* @return This router.
|
||||||
|
*/
|
||||||
|
public SceneRouter map(String route, Parent node) {
|
||||||
|
routeMap.put(route, node);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the given route to a node that is loaded from a given FXML resource.
|
||||||
|
* @param route The route.
|
||||||
|
* @param fxml The FXML classpath resource to load from.
|
||||||
|
* @param controllerCustomizer A function that takes controller instance
|
||||||
|
* from the loaded FXML and customizes it. This
|
||||||
|
* may be null.
|
||||||
|
* @return This router.
|
||||||
|
*/
|
||||||
|
public SceneRouter map(String route, String fxml, Consumer<?> controllerCustomizer) {
|
||||||
|
return map(route, loadNode(fxml, controllerCustomizer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the given route to a node that is loaded from a given FXML resource.
|
||||||
|
* @param route The route.
|
||||||
|
* @param fxml The FXML classpath resource to load from.
|
||||||
|
* @return This router.
|
||||||
|
*/
|
||||||
|
public SceneRouter map(String route, String fxml) {
|
||||||
|
return map(route, fxml, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigates to a given route, with a given context object.
|
||||||
|
* @param route The route to navigate to.
|
||||||
|
* @param context The context that should be available at that route.
|
||||||
|
*/
|
||||||
|
public void navigate(String route, Object context) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
history.push(route, context);
|
||||||
|
setter.accept(getMappedNode(route));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigates to a given route, without any context.
|
||||||
|
* @param route The route to navigate to.
|
||||||
|
*/
|
||||||
|
public void navigate(String route) {
|
||||||
|
navigate(route, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to navigate back.
|
||||||
|
*/
|
||||||
|
public void navigateBack() {
|
||||||
|
Platform.runLater(() -> history.back()
|
||||||
|
.ifPresent(prev -> setter.accept(getMappedNode(prev.route())))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to navigate forward.
|
||||||
|
*/
|
||||||
|
public void navigateForward() {
|
||||||
|
Platform.runLater(() -> history.forward()
|
||||||
|
.ifPresent(next -> setter.accept(getMappedNode(next.route())))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the context object for the current route.
|
||||||
|
* @return The context object, or null.
|
||||||
|
* @param <T> The type of the object.
|
||||||
|
*/
|
||||||
|
public <T> T getContext() {
|
||||||
|
return history.getCurrentContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the internal history representation of this router.
|
||||||
|
* @return The history used by this router.
|
||||||
|
*/
|
||||||
|
public RouteHistory getHistory() {
|
||||||
|
return history;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Parent getMappedNode(String route) {
|
||||||
|
Parent node = routeMap.get(route);
|
||||||
|
if (node == null) throw new IllegalArgumentException("Route " + route + " is not mapped to any node.");
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> Parent loadNode(String fxml, Consumer<T> controllerCustomizer) {
|
||||||
|
FXMLLoader loader = new FXMLLoader(SceneRouter.class.getResource(fxml));
|
||||||
|
try {
|
||||||
|
Parent p = loader.load();
|
||||||
|
if (controllerCustomizer != null) {
|
||||||
|
T controller = loader.getController();
|
||||||
|
if (controller == null) throw new IllegalStateException("No controller found when loading " + fxml);
|
||||||
|
controllerCustomizer.accept(controller);
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
/**
|
||||||
|
* The JavaFX-Scene-Router module. Require this to use the library.
|
||||||
|
*/
|
||||||
|
module com.andrewlalis.javafx_scene_router {
|
||||||
|
requires javafx.base;
|
||||||
|
requires javafx.controls;
|
||||||
|
requires javafx.fxml;
|
||||||
|
|
||||||
|
exports com.andrewlalis.javafx_scene_router;
|
||||||
|
}
|
Loading…
Reference in New Issue