From 4dc3528c3b6945180c02c45ba1dc5004cab50793 Mon Sep 17 00:00:00 2001 From: DaiYuANg <138393979+DaiYuANg@users.noreply.github.com> Date: Wed, 11 Dec 2024 23:19:02 +0800 Subject: [PATCH] feat(getting started): add NavigationPane functional --- document/build.gradle.kts | 20 ----- document/src/main/java/module-info.java | 9 -- .../org/visual/document/FindDocument.java | 30 ------- gradle/libs.versions.toml | 2 +- visual-app/build.gradle.kts | 4 +- visual-app/src/main/java/module-info.java | 2 +- .../org/visual/app/VisualApplication.java | 6 +- .../visual/app/component/NavigationBar.java | 35 ++++++++ .../visual/app/component/NavigationPane.java | 86 ++++++++++++++----- .../app/component/OnlyOneStackPane.java | 18 ++++ .../java/org/visual/app/component/Route.java | 33 +++++++ .../visual/app/constant/EventBusNaming.java | 6 ++ .../app/controller/MainLayoutController.java | 10 ++- .../dialog/GettingStartedController.java | 56 ++++++++---- .../DatabaseConnectionFormController.java | 14 +-- .../workspace/ObjectBrowserController.java | 4 +- .../controller/workspace/TabController.java | 4 +- .../workspace/TopToolBarController.java | 4 +- .../workspace/WorkspaceController.java | 4 +- .../visual/app/event/WindowCloseEvent.java | 13 +++ .../lifecycle/CheckWorkspaceLifecycle.java | 13 ++- .../java/org/visual/app/util/FXMLHelper.java | 1 + .../java/org/visual/app/view/VisualUI.java | 1 - .../app/view/dialog/GettingStarted.fxml | 73 +++++++++------- .../app/component/NavigationPaneTest.java | 44 ++++++++++ .../src/main/java/module-info.java | 1 + .../database/DatabaseConnectionService.java | 14 +-- 27 files changed, 344 insertions(+), 163 deletions(-) delete mode 100644 document/src/main/java/module-info.java delete mode 100644 document/src/main/java/org/visual/document/FindDocument.java create mode 100644 visual-app/src/main/java/org/visual/app/component/NavigationBar.java create mode 100644 visual-app/src/main/java/org/visual/app/component/OnlyOneStackPane.java create mode 100644 visual-app/src/main/java/org/visual/app/component/Route.java create mode 100644 visual-app/src/main/java/org/visual/app/constant/EventBusNaming.java create mode 100644 visual-app/src/main/java/org/visual/app/event/WindowCloseEvent.java create mode 100644 visual-app/src/test/java/org/visual/app/component/NavigationPaneTest.java diff --git a/document/build.gradle.kts b/document/build.gradle.kts index 5a0f7b2..e346a1a 100644 --- a/document/build.gradle.kts +++ b/document/build.gradle.kts @@ -7,15 +7,8 @@ plugins { idea } -apply() - -group = "org.visual.document" repositories { ruby { gems() } } -dependencies { - implementation(libs.guava) -} - asciidoctorj { modules { diagram.use() } } tasks.asciidoctor { @@ -31,8 +24,6 @@ tasks.asciidoctor { } } -tasks.build { dependsOn(tasks.asciidoctor) } - idea { module { sourceDirs = @@ -41,15 +32,4 @@ idea { .sourceFileTree .toMutableSet() } -} - -tasks.create("copyDocument", Copy::class) { - group = "build" - from(layout.buildDirectory.dir("docs")) - destinationDir = layout.buildDirectory.dir("classes/java/main/org/visual/document").get().asFile - dependsOn(tasks.asciidoctor) -} - -tasks.jar { - dependsOn("copyDocument") } \ No newline at end of file diff --git a/document/src/main/java/module-info.java b/document/src/main/java/module-info.java deleted file mode 100644 index a4b3083..0000000 --- a/document/src/main/java/module-info.java +++ /dev/null @@ -1,9 +0,0 @@ -module org.visual.document { - requires static lombok; - requires com.google.common; - requires org.jetbrains.annotations; - requires org.slf4j; - requires io.vavr; - - exports org.visual.document; -} diff --git a/document/src/main/java/org/visual/document/FindDocument.java b/document/src/main/java/org/visual/document/FindDocument.java deleted file mode 100644 index 07eca8d..0000000 --- a/document/src/main/java/org/visual/document/FindDocument.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.visual.document; - -import io.vavr.control.Option; -import lombok.SneakyThrows; -import lombok.experimental.UtilityClass; -import lombok.extern.slf4j.Slf4j; -import lombok.val; -import org.jetbrains.annotations.NotNull; - -import java.net.URI; -import java.net.URL; -import java.util.Locale; -import java.util.Optional; - -@UtilityClass -@Slf4j -public class FindDocument { - - @SneakyThrows - public Optional getDocumentURL(final @NotNull Locale locale) { - val language = locale.getLanguage(); - log.atInfo().log("Language:{}", language); - - val root = FindDocument.class.getClassLoader().getResource("org/visual/document/asciidoc/" + language + "index.html"); - return Option.ofOptional(Optional.ofNullable(root)) - .toTry() - .mapTry(URL::toURI) - .toJavaOptional(); - } -} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1a2867b..2879408 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,7 +71,7 @@ fluentuiIcon = { group = "org.kordamp.ikonli", name = "ikonli-fluentui-pack", ve devicons = { group = "org.kordamp.ikonli", name = "ikonli-devicons-pack", version.ref = "ikonli" } materialIcons = { group = "org.kordamp.ikonli", name = "ikonli-materialdesign2-pack", version.ref = "ikonli" } fontawesome5 = { group = "org.kordamp.ikonli", name = "ikonli-fontawesome5-pack", version.ref = "ikonli" } -javafxUnitTest = { group = "org.testfx", name = "testfx-junit5", version = "4.0.18" } +testfx-junit5 = { group = "org.testfx", name = "testfx-junit5", version = "4.0.18" } atlantafx = { group = "io.github.mkpaz", name = "atlantafx-base", version = "2.0.1" } controlfx = { group = "org.controlsfx", name = "controlsfx", version = "11.2.1" } ikonliJavafx = { group = "org.kordamp.ikonli", name = "ikonli-javafx", version.ref = "ikonliJavafx" } diff --git a/visual-app/build.gradle.kts b/visual-app/build.gradle.kts index 01cec5d..af0da74 100644 --- a/visual-app/build.gradle.kts +++ b/visual-app/build.gradle.kts @@ -58,7 +58,7 @@ dependencies { implementation(libs.logback) - testImplementation(libs.javafxUnitTest) + testImplementation(libs.testfx.junit5) runtimeOnly(libs.h2) implementation(libs.ebean.api) @@ -118,8 +118,6 @@ dependencies { implementation(libs.avaje.inject) annotationProcessor(libs.avaje.inject.generator) testImplementation(libs.avaje.inject.test) - - implementation(projects.document) } javafx { diff --git a/visual-app/src/main/java/module-info.java b/visual-app/src/main/java/module-info.java index 6146bbf..1d0729b 100644 --- a/visual-app/src/main/java/module-info.java +++ b/visual-app/src/main/java/module-info.java @@ -48,7 +48,6 @@ requires org.visual.core; requires org.visual.database; requires org.visual.data.structure; - requires org.visual.document; requires com.fasterxml.jackson.annotation; requires com.fasterxml.jackson.databind; @@ -73,6 +72,7 @@ requires org.github.gestalt.core; requires org.github.gestalt.toml; requires org.github.gestalt.yaml; + requires io.vertx.core; exports org.visual.app.entity; exports org.visual.app.lifecycle; diff --git a/visual-app/src/main/java/org/visual/app/VisualApplication.java b/visual-app/src/main/java/org/visual/app/VisualApplication.java index 9b0782f..2bd6ce7 100644 --- a/visual-app/src/main/java/org/visual/app/VisualApplication.java +++ b/visual-app/src/main/java/org/visual/app/VisualApplication.java @@ -5,20 +5,20 @@ import lombok.extern.slf4j.Slf4j; import lombok.val; import org.visual.app.command.VisualCommand; -import org.visual.app.context.DIContext; import org.visual.app.exception.GlobalExceptionHandler; import static java.lang.Thread.setDefaultUncaughtExceptionHandler; +import static org.visual.app.context.DIContext.INSTANCE; @Slf4j public class VisualApplication { static { - val exceptionHandler = DIContext.INSTANCE.get(GlobalExceptionHandler.class); + val exceptionHandler = INSTANCE.get(GlobalExceptionHandler.class); setDefaultUncaughtExceptionHandler(exceptionHandler); } @SneakyThrows public static void main(String[] args) { - DIContext.INSTANCE.get(VisualCommand.class).run(); + INSTANCE.get(VisualCommand.class).run(); } } diff --git a/visual-app/src/main/java/org/visual/app/component/NavigationBar.java b/visual-app/src/main/java/org/visual/app/component/NavigationBar.java new file mode 100644 index 0000000..8359b90 --- /dev/null +++ b/visual-app/src/main/java/org/visual/app/component/NavigationBar.java @@ -0,0 +1,35 @@ +package org.visual.app.component; + +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.geometry.Pos; +import javafx.scene.control.Button; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; +import lombok.Getter; + +import static javafx.scene.layout.Priority.ALWAYS; + +@Getter +public class NavigationBar extends HBox { + + private final Button backButton = new Button("Back"); + private final Button forwardButton = new Button("Forward"); + + private final Region spacer = new Region(); + + public NavigationBar() { + super(20); + setAlignment(Pos.CENTER); + HBox.setHgrow(spacer, ALWAYS); + getChildren().addAll(backButton, spacer, forwardButton); + } + + public void setOnForward(EventHandler event) { + forwardButton.setOnAction(event); + } + + public void setOnBack(EventHandler event) { + backButton.setOnAction(event); + } +} diff --git a/visual-app/src/main/java/org/visual/app/component/NavigationPane.java b/visual-app/src/main/java/org/visual/app/component/NavigationPane.java index 069de5e..0b27f9e 100644 --- a/visual-app/src/main/java/org/visual/app/component/NavigationPane.java +++ b/visual-app/src/main/java/org/visual/app/component/NavigationPane.java @@ -1,26 +1,27 @@ package org.visual.app.component; -import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; -import javafx.collections.FXCollections; -import javafx.collections.MapChangeListener; -import javafx.collections.ObservableMap; +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; import javafx.scene.Node; -import javafx.scene.layout.StackPane; +import javafx.scene.control.Separator; +import javafx.scene.layout.VBox; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import lombok.val; -import org.apache.commons.collections4.CollectionUtils; import org.eclipse.collections.api.factory.Stacks; import org.eclipse.collections.api.stack.MutableStack; +import static javafx.collections.FXCollections.observableArrayList; + @Slf4j @SuppressWarnings("unused") @Getter -public class NavigationPane extends StackPane { +public class NavigationPane extends VBox { - private final ObservableMap page = FXCollections.observableMap(Object2ObjectMaps.emptyMap()); + private final ObservableList routes = observableArrayList(new ObjectArrayList<>()); private final StringProperty currentPage = new SimpleStringProperty(); @@ -30,12 +31,21 @@ public class NavigationPane extends StackPane { private final StringProperty index = new SimpleStringProperty("/"); + private final StringProperty current = new SimpleStringProperty(); + + private final OnlyOneStackPane stackPane = new OnlyOneStackPane(); + + private final NavigationBar navigationBar = new NavigationBar(); + { - page.addListener((MapChangeListener) change -> { - log.atInfo().log("change{}", change); - }); - index.addListener((observable, oldValue, newValue) -> { - log.atInfo().log(oldValue); + routes.addListener((ListChangeListener) c -> { + log.atInfo().log("c:{}", c); + log.atInfo().log("Routes:{}", routes); + stackPane.getChildren().clear(); + c.getList().stream() + .filter(route -> route.getPath().equals(index.get())) + .findFirst() + .ifPresent(route -> stackPane.setContent(route.getContent())); }); } @@ -50,22 +60,44 @@ public NavigationPane(Node... children) { } private void setup() { - val children = getChildren(); - if (CollectionUtils.isNotEmpty(children)) { - page.put(index.get(), children.getFirst()); - } + navigationBar.setOnBack(event -> back()); + navigationBar.setOnForward(event -> forward()); + this.getChildren().addAll(navigationBar, new Separator(), stackPane); } - public void to(String route) { - + public void to(String to) { + + routes.stream() + .filter(route -> route.getPath().equals(to)) + .findFirst() + .ifPresent(route -> { + // 当前页面加入到 backStack + backStack.push(stackPane.getContent()); + // 清空 forwardStack,因为我们从一个新的页面跳转过来 + forwardStack.clear(); + // 设置新的内容 + stackPane.setContent(route.getContent()); + // 更新当前的 index +// setIndex(to); + }); } public void back() { - + if (backStack.isEmpty()) { + return; + } + forwardStack.push(stackPane.getContent()); + val lastContent = backStack.pop(); + stackPane.setContent(lastContent); } public void forward() { - + if (forwardStack.isEmpty()) { + return; + } + backStack.push(stackPane.getContent()); + val nextContent = forwardStack.pop(); + stackPane.setContent(nextContent); } public void setIndex(String index) { @@ -75,4 +107,16 @@ public void setIndex(String index) { public String getIndex() { return this.index.get(); } + + public void setCurrent(String currentPage) { + current.set(currentPage); + } + + public String getCurrent() { + return current.get(); + } + + public void addRoute(Route route) { + routes.add(route); + } } diff --git a/visual-app/src/main/java/org/visual/app/component/OnlyOneStackPane.java b/visual-app/src/main/java/org/visual/app/component/OnlyOneStackPane.java new file mode 100644 index 0000000..0796b8d --- /dev/null +++ b/visual-app/src/main/java/org/visual/app/component/OnlyOneStackPane.java @@ -0,0 +1,18 @@ +package org.visual.app.component; + +import javafx.scene.Node; +import javafx.scene.layout.StackPane; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class OnlyOneStackPane extends StackPane { + + public void setContent(Node content) { + getChildren().clear(); + getChildren().addFirst(content); + } + + public Node getContent() { + return getChildren().getFirst(); + } +} diff --git a/visual-app/src/main/java/org/visual/app/component/Route.java b/visual-app/src/main/java/org/visual/app/component/Route.java new file mode 100644 index 0000000..89141e0 --- /dev/null +++ b/visual-app/src/main/java/org/visual/app/component/Route.java @@ -0,0 +1,33 @@ +package org.visual.app.component; + +import javafx.beans.DefaultProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.scene.Node; +import lombok.EqualsAndHashCode; + +@DefaultProperty("content") +@EqualsAndHashCode +public class Route { + private final StringProperty path = new SimpleStringProperty(); + + private final ObjectProperty content = new SimpleObjectProperty<>(); + + public String getPath() { + return path.get(); + } + + public void setPath(String path) { + this.path.set(path); + } + + public Node getContent() { + return content.get(); + } + + public void setContent(Node content) { + this.content.set(content); + } +} diff --git a/visual-app/src/main/java/org/visual/app/constant/EventBusNaming.java b/visual-app/src/main/java/org/visual/app/constant/EventBusNaming.java new file mode 100644 index 0000000..031b004 --- /dev/null +++ b/visual-app/src/main/java/org/visual/app/constant/EventBusNaming.java @@ -0,0 +1,6 @@ +package org.visual.app.constant; + +public interface EventBusNaming { + + String CLOSE_GETTING_START_WINDOW = "CLOSE.GETTING.START.WINDOW"; +} diff --git a/visual-app/src/main/java/org/visual/app/controller/MainLayoutController.java b/visual-app/src/main/java/org/visual/app/controller/MainLayoutController.java index 3e1642c..17e8252 100644 --- a/visual-app/src/main/java/org/visual/app/controller/MainLayoutController.java +++ b/visual-app/src/main/java/org/visual/app/controller/MainLayoutController.java @@ -11,11 +11,14 @@ import lombok.extern.slf4j.Slf4j; import lombok.val; +import java.net.URL; +import java.util.ResourceBundle; + @Lazy @Singleton @Slf4j @RequiredArgsConstructor -public class MainLayoutController { +public class MainLayoutController extends BaseController { @FXML private VBox table1; @@ -47,4 +50,9 @@ private void showAlert(String message) { alert.setContentText(message); alert.showAndWait(); } + + @Override + public void initialize(URL location, ResourceBundle resources) { + + } } diff --git a/visual-app/src/main/java/org/visual/app/controller/dialog/GettingStartedController.java b/visual-app/src/main/java/org/visual/app/controller/dialog/GettingStartedController.java index 6ece314..2443f93 100644 --- a/visual-app/src/main/java/org/visual/app/controller/dialog/GettingStartedController.java +++ b/visual-app/src/main/java/org/visual/app/controller/dialog/GettingStartedController.java @@ -1,20 +1,23 @@ package org.visual.app.controller.dialog; +import dev.dirs.UserDirectories; import io.vertx.mutiny.core.eventbus.EventBus; import jakarta.inject.Singleton; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; -import javafx.scene.layout.StackPane; import javafx.scene.web.WebView; +import javafx.stage.DirectoryChooser; +import javafx.stage.FileChooser; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import lombok.val; -import org.visual.document.FindDocument; +import org.visual.app.component.NavigationPane; +import org.visual.app.constant.EventBusNaming; +import java.io.File; import java.net.URL; -import java.util.Locale; import java.util.ResourceBundle; @Singleton @@ -23,12 +26,14 @@ public class GettingStartedController implements Initializable { @FXML - private WebView webView; + private WebView webview; @FXML - private StackPane root; + private NavigationPane root; private final EventBus eventBus; + private final File userDir = new File(UserDirectories.get().homeDir); + @Override public void initialize(URL url, ResourceBundle resourceBundle) { @@ -39,27 +44,44 @@ public void handleCreateNewProject(ActionEvent actionEvent) { } public void handleOpenExistingProject(ActionEvent actionEvent) { + val window = root.getScene().getWindow(); + val chooser = new DirectoryChooser(); + chooser.setInitialDirectory(userDir); + val dir = chooser.showDialog(window); + log.atInfo().log("Choose :{}", dir); } @SneakyThrows public void handleViewDocumentation(ActionEvent actionEvent) { - val parent = root.getParent(); - log.atInfo().log("Parent:{}", parent); - root.getChildren().clear(); - val documentPath = FindDocument.getDocumentURL(Locale.CHINA); - log.atInfo().log("DOcument Path:{}", documentPath); -// webView.setVisible(true); -// webView.getEngine().load(resourceInfo.url().toExternalForm()); - - // 将 WebView 添加到 StackPane 中 - root.getChildren().add(webView); + root.to("/document"); + webview.getEngine().load("https://github.com/DaiYuANg/Visual"); } public void handleSettings(ActionEvent actionEvent) { } - public void handleExit(ActionEvent actionEvent) { - eventBus.publish("close-dialog", "close"); + public void handleCreateNewWorkspace(ActionEvent actionEvent) { + + } + + public void handleCreateNewDiagram(ActionEvent actionEvent) { + } + + public void handleExit() { + closeGettingStartWindow(); + } + + private void closeGettingStartWindow() { + eventBus.send(EventBusNaming.CLOSE_GETTING_START_WINDOW, null); + } + + public void handleOpenExistingDiagram() { + val chooser = new FileChooser(); + chooser.setInitialDirectory(userDir); + val window = root.getScene().getWindow(); + chooser.setSelectedExtensionFilter(new FileChooser.ExtensionFilter("visual file", ".visual")); + val file = chooser.showOpenDialog(window); + log.atInfo().log("Choose:{}", file); } } diff --git a/visual-app/src/main/java/org/visual/app/controller/menu/DatabaseConnectionFormController.java b/visual-app/src/main/java/org/visual/app/controller/menu/DatabaseConnectionFormController.java index 7dd1899..6b5dc0b 100644 --- a/visual-app/src/main/java/org/visual/app/controller/menu/DatabaseConnectionFormController.java +++ b/visual-app/src/main/java/org/visual/app/controller/menu/DatabaseConnectionFormController.java @@ -20,6 +20,7 @@ import java.net.URL; import java.util.ResourceBundle; +import java.util.concurrent.Executor; @Singleton @Slf4j @@ -52,10 +53,11 @@ public class DatabaseConnectionFormController implements Initializable { private PasswordField passwordField; @FXML private Button connectButton; + private final Executor executor; @Override public void initialize(URL url, ResourceBundle resourceBundle) { - log.atInfo().log("Theme,{}", applicationContext.get("DARK", Boolean.class)); +// log.atInfo().log("Theme,{}", applicationContext.get("DARK", Boolean.class)); val validationSupport = new ValidationSupport(); validationSupport.registerValidator(hostField, Validator.createEmptyValidator("Host is required.")); val dbTypes = FXCollections.observableArrayList(SupportDatabaseType.values()); @@ -77,12 +79,9 @@ public void handleConnect() { public void handleTestConnect() { testConnect.setVisible(false); testConnect.setManaged(false); - // 显示 ProgressIndicator progressIndicator.setVisible(true); - // 模拟加载过程,使用 PauseTransition 延迟操作 val pause = new PauseTransition(Duration.seconds(3)); pause.setOnFinished(e -> { - // 加载完成后 progressIndicator.setVisible(false); // 隐藏 ProgressIndicator testConnect.setVisible(true); // 启用按钮 testConnect.setManaged(true); @@ -91,6 +90,11 @@ public void handleTestConnect() { pause.play(); val form = viewModel.toDatabaseConnectForm(); log.atInfo().log("Connect Form:{}", form); - val isConnectSuccess = databaseConnectionService.checkConnectable(form); + databaseConnectionService.checkConnectable(form) + .subscribe() + .with(t -> { + pause.stop(); + log.atInfo().log("Is success:{}", t); + }); } } diff --git a/visual-app/src/main/java/org/visual/app/controller/workspace/ObjectBrowserController.java b/visual-app/src/main/java/org/visual/app/controller/workspace/ObjectBrowserController.java index 386c8a6..35321ed 100644 --- a/visual-app/src/main/java/org/visual/app/controller/workspace/ObjectBrowserController.java +++ b/visual-app/src/main/java/org/visual/app/controller/workspace/ObjectBrowserController.java @@ -3,10 +3,10 @@ import io.avaje.inject.Lazy; import jakarta.inject.Singleton; import javafx.fxml.FXML; -import javafx.fxml.Initializable; import javafx.scene.control.TreeItem; import javafx.scene.control.TreeView; import lombok.extern.slf4j.Slf4j; +import org.visual.app.controller.BaseController; import org.visual.app.model.DatabaseObj; import java.net.URL; @@ -15,7 +15,7 @@ @Singleton @Lazy @Slf4j -public class ObjectBrowserController implements Initializable { +public class ObjectBrowserController extends BaseController { @FXML public TreeView treeView; diff --git a/visual-app/src/main/java/org/visual/app/controller/workspace/TabController.java b/visual-app/src/main/java/org/visual/app/controller/workspace/TabController.java index 2a24fad..e29fd01 100644 --- a/visual-app/src/main/java/org/visual/app/controller/workspace/TabController.java +++ b/visual-app/src/main/java/org/visual/app/controller/workspace/TabController.java @@ -2,10 +2,10 @@ import jakarta.inject.Singleton; import javafx.fxml.FXML; -import javafx.fxml.Initializable; import javafx.scene.control.TabPane; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.visual.app.controller.BaseController; import java.net.URL; import java.util.ResourceBundle; @@ -13,7 +13,7 @@ @Slf4j @RequiredArgsConstructor @Singleton -public class TabController implements Initializable { +public class TabController extends BaseController { @FXML private TabPane root; diff --git a/visual-app/src/main/java/org/visual/app/controller/workspace/TopToolBarController.java b/visual-app/src/main/java/org/visual/app/controller/workspace/TopToolBarController.java index 57149f8..007a51f 100644 --- a/visual-app/src/main/java/org/visual/app/controller/workspace/TopToolBarController.java +++ b/visual-app/src/main/java/org/visual/app/controller/workspace/TopToolBarController.java @@ -1,9 +1,9 @@ package org.visual.app.controller.workspace; import jakarta.inject.Singleton; -import javafx.fxml.Initializable; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.visual.app.controller.BaseController; import java.net.URL; import java.util.ResourceBundle; @@ -11,7 +11,7 @@ @Slf4j @RequiredArgsConstructor @Singleton -public class TopToolBarController implements Initializable { +public class TopToolBarController extends BaseController { @Override public void initialize(URL url, ResourceBundle resourceBundle) { diff --git a/visual-app/src/main/java/org/visual/app/controller/workspace/WorkspaceController.java b/visual-app/src/main/java/org/visual/app/controller/workspace/WorkspaceController.java index 72279ec..f3394cc 100644 --- a/visual-app/src/main/java/org/visual/app/controller/workspace/WorkspaceController.java +++ b/visual-app/src/main/java/org/visual/app/controller/workspace/WorkspaceController.java @@ -2,7 +2,6 @@ import jakarta.inject.Singleton; import javafx.fxml.FXML; -import javafx.fxml.Initializable; import javafx.scene.Cursor; import javafx.scene.control.Separator; import javafx.scene.input.MouseEvent; @@ -11,6 +10,7 @@ import lombok.extern.slf4j.Slf4j; import lombok.val; import org.jetbrains.annotations.NotNull; +import org.visual.app.controller.BaseController; import java.net.URL; import java.util.ResourceBundle; @@ -18,7 +18,7 @@ @Singleton @Slf4j @RequiredArgsConstructor -public class WorkspaceController implements Initializable { +public class WorkspaceController extends BaseController { @FXML private Separator separator; @FXML diff --git a/visual-app/src/main/java/org/visual/app/event/WindowCloseEvent.java b/visual-app/src/main/java/org/visual/app/event/WindowCloseEvent.java new file mode 100644 index 0000000..5758c6f --- /dev/null +++ b/visual-app/src/main/java/org/visual/app/event/WindowCloseEvent.java @@ -0,0 +1,13 @@ +package org.visual.app.event; + + +import javafx.event.Event; +import javafx.event.EventType; + +public class WindowCloseEvent extends Event { + public static final EventType CLOSE = new EventType<>(ANY, "CLOSE"); + + public WindowCloseEvent() { + super(CLOSE); + } +} \ No newline at end of file diff --git a/visual-app/src/main/java/org/visual/app/lifecycle/CheckWorkspaceLifecycle.java b/visual-app/src/main/java/org/visual/app/lifecycle/CheckWorkspaceLifecycle.java index a58a5e4..dffad07 100644 --- a/visual-app/src/main/java/org/visual/app/lifecycle/CheckWorkspaceLifecycle.java +++ b/visual-app/src/main/java/org/visual/app/lifecycle/CheckWorkspaceLifecycle.java @@ -5,16 +5,18 @@ import jakarta.inject.Singleton; import javafx.application.Platform; import javafx.scene.Scene; -import javafx.scene.layout.StackPane; import javafx.stage.Stage; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import lombok.val; import org.visual.app.component.DialogStage; -import org.visual.app.constant.ViewConstant; +import org.visual.app.component.NavigationPane; import org.visual.app.repository.SavedStateRepository; import org.visual.app.util.FXMLHelper; +import static org.visual.app.constant.EventBusNaming.CLOSE_GETTING_START_WINDOW; +import static org.visual.app.constant.ViewConstant.GETTING_STARTED; + @Singleton @Slf4j @Lazy @@ -38,11 +40,8 @@ public void beforeShown(Stage stage) { private void showGettingStarted() { log.atInfo().log("Show init dialog"); val stage = new DialogStage(); - eventBus.consumer("close-dialog", message -> { - log.atInfo().log("message:{}", message.body()); - Platform.runLater(stage::close); - }); - val rootNode = fxmlHelper.loadView(ViewConstant.GETTING_STARTED, StackPane.class); + eventBus.consumer(CLOSE_GETTING_START_WINDOW, (m) -> Platform.runLater(stage::close)); + val rootNode = fxmlHelper.loadView(GETTING_STARTED, NavigationPane.class); val scene = new Scene(rootNode); stage.setScene(scene); stage.showAndWait(); diff --git a/visual-app/src/main/java/org/visual/app/util/FXMLHelper.java b/visual-app/src/main/java/org/visual/app/util/FXMLHelper.java index fdd2d78..642bc95 100644 --- a/visual-app/src/main/java/org/visual/app/util/FXMLHelper.java +++ b/visual-app/src/main/java/org/visual/app/util/FXMLHelper.java @@ -33,6 +33,7 @@ public T loadView(@NotNull ViewConstant prefix, @NotNull Clas .mapTry(Pair::getKey) .andThenTry(view -> Preconditions.checkArgument(type.isInstance(view), "FXML cache contains a mismatched type.")) .map(type::cast) + .onFailure(throwable -> log.atError().log(throwable.getMessage(), throwable)) .get(); } diff --git a/visual-app/src/main/java/org/visual/app/view/VisualUI.java b/visual-app/src/main/java/org/visual/app/view/VisualUI.java index afae9bd..6929ed5 100644 --- a/visual-app/src/main/java/org/visual/app/view/VisualUI.java +++ b/visual-app/src/main/java/org/visual/app/view/VisualUI.java @@ -3,7 +3,6 @@ import javafx.application.Application; import javafx.stage.Stage; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.visual.app.lifecycle.StageLifecycle; diff --git a/visual-app/src/main/resources/org/visual/app/view/dialog/GettingStarted.fxml b/visual-app/src/main/resources/org/visual/app/view/dialog/GettingStarted.fxml index ec58e3b..a99240c 100644 --- a/visual-app/src/main/resources/org/visual/app/view/dialog/GettingStarted.fxml +++ b/visual-app/src/main/resources/org/visual/app/view/dialog/GettingStarted.fxml @@ -5,41 +5,54 @@ - + + + prefHeight="500.0" prefWidth="700.0" fx:id="root" index="/"> - - - - - - - test - + + + + + + + + + + + + + + + + + diff --git a/visual-app/src/test/java/org/visual/app/component/NavigationPaneTest.java b/visual-app/src/test/java/org/visual/app/component/NavigationPaneTest.java new file mode 100644 index 0000000..6f9c734 --- /dev/null +++ b/visual-app/src/test/java/org/visual/app/component/NavigationPaneTest.java @@ -0,0 +1,44 @@ +package org.visual.app.component; + +import javafx.scene.Scene; +import javafx.scene.control.Label; +import javafx.stage.Stage; +import lombok.val; +import org.junit.jupiter.api.Test; +import org.testfx.api.FxAssert; +import org.testfx.framework.junit5.ApplicationTest; +import org.testfx.matcher.control.LabeledMatchers; + +class NavigationPaneTest extends ApplicationTest { + + private Route route; + + private Label label; + + @Override + public void start(Stage stage) throws Exception { + super.start(stage); + val pane = new NavigationPane(); + val scene = new Scene(pane); + route = new Route(); + route.setPath("/"); + label = new Label("test"); + route.setContent(label); + pane.addRoute(route); + stage.setScene(scene); + stage.show(); + } + + @Test + void testIndex() { + FxAssert.verifyThat(label, LabeledMatchers.hasText("test")); + } + + @Test + void back() { + } + + @Test + void forward() { + } +} \ No newline at end of file diff --git a/visual-database/src/main/java/module-info.java b/visual-database/src/main/java/module-info.java index 5852473..dc98992 100644 --- a/visual-database/src/main/java/module-info.java +++ b/visual-database/src/main/java/module-info.java @@ -9,6 +9,7 @@ requires io.vavr; requires io.avaje.inject; requires schemacrawler; + requires io.smallrye.mutiny; provides io.avaje.validation.spi.ValidationExtension with org.visual.database.valid.GeneratedValidatorComponent; provides io.avaje.inject.spi.InjectExtension with org.visual.database.DatabaseModule; diff --git a/visual-database/src/main/java/org/visual/database/DatabaseConnectionService.java b/visual-database/src/main/java/org/visual/database/DatabaseConnectionService.java index e3527c6..653405c 100644 --- a/visual-database/src/main/java/org/visual/database/DatabaseConnectionService.java +++ b/visual-database/src/main/java/org/visual/database/DatabaseConnectionService.java @@ -1,13 +1,15 @@ package org.visual.database; import io.avaje.validation.Validator; +import io.smallrye.mutiny.Uni; import jakarta.inject.Singleton; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import lombok.val; import org.jetbrains.annotations.NotNull; +import java.util.concurrent.Executor; + @Singleton @Slf4j @RequiredArgsConstructor @@ -16,10 +18,10 @@ public class DatabaseConnectionService { private final Validator validator; @SneakyThrows - public Boolean checkConnectable(@NotNull DBConnection connection) { - validator.validate(connection); - val url = connection.buildConnectionUrl(); - log.atInfo().log("URL:{}", url); - return connection.testConnect(); + public Uni checkConnectable(@NotNull DBConnection connection) { + return Uni.createFrom().item(connection) + .invoke(validator::validate) + .log() + .map(DBConnection::testConnect); } }