From 9f4c734b40eaead57cb4e103eb571812b0dad464 Mon Sep 17 00:00:00 2001 From: gewuyou <1063891901@qq.com> Date: Sun, 17 Sep 2023 21:22:57 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E9=87=8D=E6=96=B0=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 27 +- libs/README.md | 1 + .../jcnc/jnotepad/plugin/PluginManager.java | 2 +- .../plugin/PluginManagerInterface.java | 8 +- .../jnotepad/ui/dialog/AppDialogBuilder.java | 249 +++++++++--------- .../ui/dialog/factory/FileChooserFactory.java | 6 +- .../jnotepad/ui/module/SettingsComponent.java | 4 +- .../java/org/jcnc/jnotepad/util/UiUtil.java | 6 +- src/main/resources/css/styles.css | 1 - 9 files changed, 150 insertions(+), 154 deletions(-) diff --git a/README.md b/README.md index 9e4b714..fba4a69 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,6 @@ JNotepad使用Java语言编写,并基于JavaFX框架开发,具有良好的 [docs-url]: https://gitee.com/jcnc-org/docs - - [下载][gitee-download] 2. Linux/MacOS 平台,查看入门指南 @@ -103,24 +102,22 @@ JNotepad使用Java语言编写,并基于JavaFX框架开发,具有良好的 - `插件 > 增加插件`:(管理插件系统,待完善)。 - ## 依赖项 POM文件中的全部依赖项: -| 组ID | 工件ID | 版本 | 功能描述 | -|--------------------------------|------------------------------|--------|------------------------------------------------| -| org.kordamp.ikonli | ikonli-javafx | 12.3.1 | 提供JavaFX应用程序中的图标集成。 | -| org.kordamp.ikonli | ikonli-antdesignicons-pack | 12.3.1 | 包含Ant Design图标集的Ikonli图标包。 | -| io.github.mkpaz | atlantafx-base | 2.0.1 | 提供Atlantafx库的基本功能。 | -| org.openjfx | javafx-fxml | 20.0.2 | JavaFX的FXML模块,用于构建用户界面。 | -| org.junit.jupiter | junit-jupiter-api | 5.9.2 | 用于JUnit 5测试框架的API。 | -| com.fasterxml.jackson.core | jackson-databind | 2.15.2 | 用于JSON数据的序列化和反序列化。 | -| org.slf4j | slf4j-api | 2.0.7 | 简单日志门面,用于处理日志记录。 | -| ch.qos.logback | logback-core | 1.4.11 | Logback的核心组件,用于日志记录。 | -| ch.qos.logback | logback-classic | 1.4.11 | Logback的经典模块,提供日志记录功能。 | -| com.ibm.icu | icu4j | 73.2 | ICU(International Components for Unicode)库,用于处理Unicode字符和文本。| - +| 组ID | 工件ID | 版本 | 功能描述 | +|----------------------------|----------------------------|--------|--------------------------------------------------------------| +| org.kordamp.ikonli | ikonli-javafx | 12.3.1 | 提供JavaFX应用程序中的图标集成。 | +| org.kordamp.ikonli | ikonli-antdesignicons-pack | 12.3.1 | 包含Ant Design图标集的Ikonli图标包。 | +| io.github.mkpaz | atlantafx-base | 2.0.1 | 提供Atlantafx库的基本功能。 | +| org.openjfx | javafx-fxml | 20.0.2 | JavaFX的FXML模块,用于构建用户界面。 | +| org.junit.jupiter | junit-jupiter-api | 5.9.2 | 用于JUnit 5测试框架的API。 | +| com.fasterxml.jackson.core | jackson-databind | 2.15.2 | 用于JSON数据的序列化和反序列化。 | +| org.slf4j | slf4j-api | 2.0.7 | 简单日志门面,用于处理日志记录。 | +| ch.qos.logback | logback-core | 1.4.11 | Logback的核心组件,用于日志记录。 | +| ch.qos.logback | logback-classic | 1.4.11 | Logback的经典模块,提供日志记录功能。 | +| com.ibm.icu | icu4j | 73.2 | ICU(International Components for Unicode)库,用于处理Unicode字符和文本。 | ## 软件运行截图 diff --git a/libs/README.md b/libs/README.md index 833df2a..29806ca 100644 --- a/libs/README.md +++ b/libs/README.md @@ -40,4 +40,5 @@ jar uf libs/icu4j-73.2.jar -C libs/tmpOut/com.ibm.icu module-info.class ``` ## Reference + 1. [java_jlink_automatic_module_cannot_be_used_with_jlink](https://tacosteemers.com/articles/java_jlink_automatic_module_cannot_be_used_with_jlink.html) \ No newline at end of file diff --git a/src/main/java/org/jcnc/jnotepad/plugin/PluginManager.java b/src/main/java/org/jcnc/jnotepad/plugin/PluginManager.java index 79150c2..76a35b3 100644 --- a/src/main/java/org/jcnc/jnotepad/plugin/PluginManager.java +++ b/src/main/java/org/jcnc/jnotepad/plugin/PluginManager.java @@ -28,7 +28,6 @@ import static org.jcnc.jnotepad.plugin.PluginLoader.readPlugin; */ public class PluginManager { private static final PluginManager INSTANCE = new PluginManager(); - Logger logger = LogUtil.getLogger(this.getClass()); /** * 插件类别 */ @@ -37,6 +36,7 @@ public class PluginManager { * 插件信息 */ private final List pluginInfos = new ArrayList<>(); + Logger logger = LogUtil.getLogger(this.getClass()); private PluginManager() { diff --git a/src/main/java/org/jcnc/jnotepad/plugin/PluginManagerInterface.java b/src/main/java/org/jcnc/jnotepad/plugin/PluginManagerInterface.java index c8c945e..a36beea 100644 --- a/src/main/java/org/jcnc/jnotepad/plugin/PluginManagerInterface.java +++ b/src/main/java/org/jcnc/jnotepad/plugin/PluginManagerInterface.java @@ -27,6 +27,10 @@ public class PluginManagerInterface { private static final PluginManagerInterface INSTANCE = new PluginManagerInterface(); Logger logger = LogUtil.getLogger(this.getClass()); + public static PluginManagerInterface getInstance() { + return INSTANCE; + } + /** * 启动插件演示界面 * @@ -54,10 +58,6 @@ public class PluginManagerInterface { primaryStage.show(); } - public static PluginManagerInterface getInstance() { - return INSTANCE; - } - /** * 显示已加载插件的信息 * diff --git a/src/main/java/org/jcnc/jnotepad/ui/dialog/AppDialogBuilder.java b/src/main/java/org/jcnc/jnotepad/ui/dialog/AppDialogBuilder.java index 327b896..fcb0616 100644 --- a/src/main/java/org/jcnc/jnotepad/ui/dialog/AppDialogBuilder.java +++ b/src/main/java/org/jcnc/jnotepad/ui/dialog/AppDialogBuilder.java @@ -86,112 +86,11 @@ public class AppDialogBuilder { } } - /** - * 设置应用图标 - */ - public AppDialogBuilder setAppIcon(Image appIcon) { - this.appIcon = appIcon; - return this; - } - public AppDialog build() { appDialog = new AppDialog(this); return appDialog; } - /** - * 设置对话框标题 - */ - public AppDialogBuilder setTitle(String title) { - this.title = title; - return this; - } - - - /** - * 设置对话框头部文本 - */ - public AppDialogBuilder setHeaderText(String headerText) { - this.headerText = headerText; - return this; - } - - /** - * 设置自定义文本 - */ - public AppDialogBuilder setCustomText(String customText) { - this.customText = customText; - return this; - } - - /** - * 设置对话框宽度 - */ - public AppDialogBuilder setWidth(double width) { - this.width = width; - return this; - } - - /** - * 设置对话框高度 - */ - public AppDialogBuilder setHeight(double height) { - this.height = height; - return this; - } - - /** - * 设置对话框左侧图标 - */ - public AppDialogBuilder setIcon(FontIcon icon) { - this.icon = icon; - return this; - } - - /** - * 设置左按钮操作 - */ - public AppDialogBuilder setLeftBtnAction(DialogButtonAction leftBtnAction) { - if (leftBtnAction != null) { - this.leftBtnAction = leftBtnAction; - } - return this; - } - - /** - * 设置右按钮操作 - */ - public AppDialogBuilder setRightBtnAction(DialogButtonAction rightBtnAction) { - if (rightBtnAction != null) { - this.rightBtnAction = rightBtnAction; - } - return this; - } - - /** - * 设置左按钮文本 - */ - public AppDialogBuilder setLeftBtnText(String leftBtnText) { - this.leftBtnText = leftBtnText; - return this; - } - - /** - * 设置右按钮文本 - */ - public AppDialogBuilder setRightBtnText(String rightBtnText) { - this.rightBtnText = rightBtnText; - return this; - } - - /** - * 设置图标边距 - */ - public AppDialogBuilder setIconCoxPaddingInsets(Insets iconCoxPaddingInsets) { - this.iconCoxPaddingInsets = iconCoxPaddingInsets; - return this; - } - /** * 设置水平盒子边距 */ @@ -200,14 +99,6 @@ public class AppDialogBuilder { return this; } - /** - * 设置是否可调整大小 - */ - public AppDialogBuilder setResizable(boolean resizable) { - isResizable = resizable; - return this; - } - /** * 设置水平盒子间距 */ @@ -216,14 +107,6 @@ public class AppDialogBuilder { return this; } - /** - * 设置垂直盒子位置 - */ - public AppDialogBuilder setVboxPos(Pos vboxPos) { - this.vboxPos = vboxPos; - return this; - } - /** * 设置水平盒子位置 */ @@ -232,62 +115,154 @@ public class AppDialogBuilder { return this; } - /** - * 设置模态性 - */ - public AppDialogBuilder setModality(Modality modality) { - this.modality = modality; - return this; - } - public Image getAppIcon() { return appIcon; } + /** + * 设置应用图标 + */ + public AppDialogBuilder setAppIcon(Image appIcon) { + this.appIcon = appIcon; + return this; + } + public String getTitle() { return title; } + /** + * 设置对话框标题 + */ + public AppDialogBuilder setTitle(String title) { + this.title = title; + return this; + } + public String getHeaderText() { return headerText; } + /** + * 设置对话框头部文本 + */ + public AppDialogBuilder setHeaderText(String headerText) { + this.headerText = headerText; + return this; + } + public String getCustomText() { return customText; } + /** + * 设置自定义文本 + */ + public AppDialogBuilder setCustomText(String customText) { + this.customText = customText; + return this; + } + public double getWidth() { return width; } + /** + * 设置对话框宽度 + */ + public AppDialogBuilder setWidth(double width) { + this.width = width; + return this; + } + public double getHeight() { return height; } + /** + * 设置对话框高度 + */ + public AppDialogBuilder setHeight(double height) { + this.height = height; + return this; + } + public FontIcon getIcon() { return icon; } + /** + * 设置对话框左侧图标 + */ + public AppDialogBuilder setIcon(FontIcon icon) { + this.icon = icon; + return this; + } + public DialogButtonAction getLeftBtnAction() { return leftBtnAction; } + /** + * 设置左按钮操作 + */ + public AppDialogBuilder setLeftBtnAction(DialogButtonAction leftBtnAction) { + if (leftBtnAction != null) { + this.leftBtnAction = leftBtnAction; + } + return this; + } + public DialogButtonAction getRightBtnAction() { return rightBtnAction; } + /** + * 设置右按钮操作 + */ + public AppDialogBuilder setRightBtnAction(DialogButtonAction rightBtnAction) { + if (rightBtnAction != null) { + this.rightBtnAction = rightBtnAction; + } + return this; + } + public String getLeftBtnText() { return leftBtnText; } + /** + * 设置左按钮文本 + */ + public AppDialogBuilder setLeftBtnText(String leftBtnText) { + this.leftBtnText = leftBtnText; + return this; + } + public String getRightBtnText() { return rightBtnText; } + /** + * 设置右按钮文本 + */ + public AppDialogBuilder setRightBtnText(String rightBtnText) { + this.rightBtnText = rightBtnText; + return this; + } + public Insets getIconCoxPaddingInsets() { return iconCoxPaddingInsets; } + /** + * 设置图标边距 + */ + public AppDialogBuilder setIconCoxPaddingInsets(Insets iconCoxPaddingInsets) { + this.iconCoxPaddingInsets = iconCoxPaddingInsets; + return this; + } + public Insets gethBoxPaddingInsets() { return hBoxPaddingInsets; } @@ -296,6 +271,14 @@ public class AppDialogBuilder { return isResizable; } + /** + * 设置是否可调整大小 + */ + public AppDialogBuilder setResizable(boolean resizable) { + isResizable = resizable; + return this; + } + public double getHBoxSpacing() { return hBoxSpacing; } @@ -304,6 +287,14 @@ public class AppDialogBuilder { return vboxPos; } + /** + * 设置垂直盒子位置 + */ + public AppDialogBuilder setVboxPos(Pos vboxPos) { + this.vboxPos = vboxPos; + return this; + } + public Pos getHboxPos() { return hboxPos; } @@ -311,4 +302,12 @@ public class AppDialogBuilder { public Modality getModality() { return modality; } + + /** + * 设置模态性 + */ + public AppDialogBuilder setModality(Modality modality) { + this.modality = modality; + return this; + } } diff --git a/src/main/java/org/jcnc/jnotepad/ui/dialog/factory/FileChooserFactory.java b/src/main/java/org/jcnc/jnotepad/ui/dialog/factory/FileChooserFactory.java index 46457a7..7f465b3 100644 --- a/src/main/java/org/jcnc/jnotepad/ui/dialog/factory/FileChooserFactory.java +++ b/src/main/java/org/jcnc/jnotepad/ui/dialog/factory/FileChooserFactory.java @@ -22,9 +22,9 @@ public interface FileChooserFactory { /** * 创建详细的文件选择对话框。 * - * @param title 对话框标题 - * @param filename 默认选中的文件名 - * @param directory 初始目录 + * @param title 对话框标题 + * @param filename 默认选中的文件名 + * @param directory 初始目录 * @param extensionFilters 文件类型过滤器 * @return javafx.stage.FileChooser 详细文件选择对话框对象 * @apiNote 该方法用于创建一个带有标题、默认文件名、初始目录和文件类型过滤器的详细文件选择对话框。 diff --git a/src/main/java/org/jcnc/jnotepad/ui/module/SettingsComponent.java b/src/main/java/org/jcnc/jnotepad/ui/module/SettingsComponent.java index 1edb1ba..cbb2180 100644 --- a/src/main/java/org/jcnc/jnotepad/ui/module/SettingsComponent.java +++ b/src/main/java/org/jcnc/jnotepad/ui/module/SettingsComponent.java @@ -33,8 +33,8 @@ public class SettingsComponent extends VBox { /** * 创建一个设置组件实例。 * - * @param labelText 标签文本 - * @param buttonText 按钮文本 + * @param labelText 标签文本 + * @param buttonText 按钮文本 */ public SettingsComponent(String labelText, String buttonText) { setSpacing(10); diff --git a/src/main/java/org/jcnc/jnotepad/util/UiUtil.java b/src/main/java/org/jcnc/jnotepad/util/UiUtil.java index d19778c..0d1f073 100644 --- a/src/main/java/org/jcnc/jnotepad/util/UiUtil.java +++ b/src/main/java/org/jcnc/jnotepad/util/UiUtil.java @@ -44,9 +44,6 @@ public class UiUtil { private static final FontIcon SUCCESS_ICON = FontIcon.of(CHECK_CIRCLE); - private UiUtil() { - } - static { // 暂时设置颜色 ERROR_ICON.getStyleClass().addAll(Styles.DANGER); @@ -56,6 +53,9 @@ public class UiUtil { SUCCESS_ICON.getStyleClass().addAll(Styles.SUCCESS); } + private UiUtil() { + } + /** * 获取应用程序图标。 * diff --git a/src/main/resources/css/styles.css b/src/main/resources/css/styles.css index 1f9270c..6167aad 100644 --- a/src/main/resources/css/styles.css +++ b/src/main/resources/css/styles.css @@ -5,7 +5,6 @@ } - /* tab修改标签样式 */ .tab-title-editable { -fx-fx-border-width: 0; From 7c1a313023b5a4eeba2bce78e6b4796d830619cf Mon Sep 17 00:00:00 2001 From: gewuyou <1063891901@qq.com> Date: Mon, 18 Sep 2023 18:26:24 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=94=A5=20=E7=A7=BB=E9=99=A4=E6=9A=82?= =?UTF-8?q?=E6=97=B6=E7=94=A8=E4=B8=8D=E5=88=B0=E7=9A=84=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jcnc/jnotepad/plugin/interfaces/Plugin.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/main/java/org/jcnc/jnotepad/plugin/interfaces/Plugin.java b/src/main/java/org/jcnc/jnotepad/plugin/interfaces/Plugin.java index 905e7fa..a4143b4 100644 --- a/src/main/java/org/jcnc/jnotepad/plugin/interfaces/Plugin.java +++ b/src/main/java/org/jcnc/jnotepad/plugin/interfaces/Plugin.java @@ -1,8 +1,6 @@ package org.jcnc.jnotepad.plugin.interfaces; -import java.util.Map; - /** * 插件接口 *

@@ -20,19 +18,4 @@ public interface Plugin { * 执行插件的逻辑 */ void execute(); - - /** - * 获取插件的配置参数 - * - * @return 插件的配置参数 - */ - Map getConfig(); - - /** - * 设置插件的配置参数 - * - * @param config 插件的配置参数 - */ - void setConfig(Map config); - } From 399ef925a5e6eb09cc1c8f9524bea75c743283ca Mon Sep 17 00:00:00 2001 From: gewuyou <1063891901@qq.com> Date: Tue, 19 Sep 2023 14:36:57 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E7=B1=BB=E5=8A=A0=E8=BD=BD=E9=80=BB=E8=BE=91?= =?UTF-8?q?=20=F0=9F=90=9B=20=E4=BF=AE=E5=A4=8D=20=E5=AF=BC=E5=85=A5?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E9=94=99=E8=AF=AF=20=E2=9E=95=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=B7=A5=E5=85=B7=E6=A0=8F=E6=8F=92=E4=BB=B6=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/module-info.java | 4 +- src/main/java/org/jcnc/jnotepad/LunchApp.java | 10 +- .../jnotepad/app/config/PluginConfig.java | 8 +- ...{PluginInfo.java => PluginDescriptor.java} | 2 +- .../jcnc/jnotepad/plugin/PluginLoader.java | 118 +++++++++++------- .../jcnc/jnotepad/plugin/PluginManager.java | 48 +++---- .../jnotepad/plugin/interfaces/Plugin.java | 6 + .../jnotepad/views/manager/ViewManager.java | 3 + .../bottom/RootBottomSideBarVerticalBox.java | 33 +++-- .../views/root/bottom/cmd/CmdStatusBox.java | 118 ------------------ .../root/bottom/function/FunctionBox.java | 34 +++++ .../AbstractFunctionChildrenBox.java | 38 ++++++ 12 files changed, 214 insertions(+), 208 deletions(-) rename src/main/java/org/jcnc/jnotepad/model/entity/{PluginInfo.java => PluginDescriptor.java} (98%) delete mode 100644 src/main/java/org/jcnc/jnotepad/views/root/bottom/cmd/CmdStatusBox.java create mode 100644 src/main/java/org/jcnc/jnotepad/views/root/bottom/function/FunctionBox.java create mode 100644 src/main/java/org/jcnc/jnotepad/views/root/bottom/function/interfaces/AbstractFunctionChildrenBox.java diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 232b63d..366e078 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -31,11 +31,13 @@ module org.jcnc.jnotepad { exports org.jcnc.jnotepad.common.interfaces; opens org.jcnc.jnotepad.app.config; exports org.jcnc.jnotepad.plugin.interfaces; + exports org.jcnc.jnotepad.views.root.bottom.function; + exports org.jcnc.jnotepad.views.root.bottom.function.interfaces; exports org.jcnc.jnotepad.ui.dialog; exports org.jcnc.jnotepad.ui.dialog.interfaces; + exports org.jcnc.jnotepad.ui.module; exports org.jcnc.jnotepad.model.entity; exports org.jcnc.jnotepad.views.root.bottom; exports org.jcnc.jnotepad.views.root.bottom.status; - exports org.jcnc.jnotepad.views.root.bottom.cmd; } \ No newline at end of file diff --git a/src/main/java/org/jcnc/jnotepad/LunchApp.java b/src/main/java/org/jcnc/jnotepad/LunchApp.java index 25b5825..76161c8 100644 --- a/src/main/java/org/jcnc/jnotepad/LunchApp.java +++ b/src/main/java/org/jcnc/jnotepad/LunchApp.java @@ -83,12 +83,14 @@ public class LunchApp extends Application { // 1. 加载语言 LocalizationController.initLocal(); - - // 2. 加载组件 + // 2. 加载资源 + ResourceController.getInstance().loadResources(); + // 3. 初始化插件 + PluginManager.getInstance().initializePlugins(); + // 3. 加载组件 ViewManager viewManager = ViewManager.getInstance(SCENE); viewManager.initScreen(SCENE); - // 3. 加载资源 - ResourceController.getInstance().loadResources(); + // 使用线程池加载关联文件并创建文本区域 List rawParameters = getParameters().getRaw(); Controller.getInstance().openAssociatedFileAndCreateTextArea(rawParameters); diff --git a/src/main/java/org/jcnc/jnotepad/app/config/PluginConfig.java b/src/main/java/org/jcnc/jnotepad/app/config/PluginConfig.java index ac113d9..1859b7d 100644 --- a/src/main/java/org/jcnc/jnotepad/app/config/PluginConfig.java +++ b/src/main/java/org/jcnc/jnotepad/app/config/PluginConfig.java @@ -1,6 +1,6 @@ package org.jcnc.jnotepad.app.config; -import org.jcnc.jnotepad.model.entity.PluginInfo; +import org.jcnc.jnotepad.model.entity.PluginDescriptor; import java.util.ArrayList; import java.util.List; @@ -11,7 +11,7 @@ import java.util.List; * @author gewuyou */ public class PluginConfig { - private List plugins; + private List plugins; /** * 生成默认的插件配置文件 @@ -26,11 +26,11 @@ public class PluginConfig { return pluginConfig; } - public List getPlugins() { + public List getPlugins() { return plugins; } - public void setPlugins(List plugins) { + public void setPlugins(List plugins) { this.plugins = plugins; } } diff --git a/src/main/java/org/jcnc/jnotepad/model/entity/PluginInfo.java b/src/main/java/org/jcnc/jnotepad/model/entity/PluginDescriptor.java similarity index 98% rename from src/main/java/org/jcnc/jnotepad/model/entity/PluginInfo.java rename to src/main/java/org/jcnc/jnotepad/model/entity/PluginDescriptor.java index eb40f42..d66d106 100644 --- a/src/main/java/org/jcnc/jnotepad/model/entity/PluginInfo.java +++ b/src/main/java/org/jcnc/jnotepad/model/entity/PluginDescriptor.java @@ -8,7 +8,7 @@ import org.jcnc.jnotepad.plugin.interfaces.Plugin; * * @author gewuyou */ -public class PluginInfo { +public class PluginDescriptor { /** * 插件名称 */ diff --git a/src/main/java/org/jcnc/jnotepad/plugin/PluginLoader.java b/src/main/java/org/jcnc/jnotepad/plugin/PluginLoader.java index a74cb7f..672d6ec 100644 --- a/src/main/java/org/jcnc/jnotepad/plugin/PluginLoader.java +++ b/src/main/java/org/jcnc/jnotepad/plugin/PluginLoader.java @@ -2,7 +2,7 @@ package org.jcnc.jnotepad.plugin; import org.jcnc.jnotepad.controller.config.PluginConfigController; import org.jcnc.jnotepad.exception.AppException; -import org.jcnc.jnotepad.model.entity.PluginInfo; +import org.jcnc.jnotepad.model.entity.PluginDescriptor; import org.jcnc.jnotepad.plugin.interfaces.Plugin; import org.jcnc.jnotepad.util.JsonUtil; import org.jcnc.jnotepad.util.LogUtil; @@ -12,10 +12,8 @@ import java.io.*; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.zip.ZipEntry; @@ -29,11 +27,11 @@ public class PluginLoader { Logger logger = LogUtil.getLogger(this.getClass()); /** - * 从插件jar包中读取 json 文件到 PluginInfo 类 + * 从插件jar包中读取 json 文件到 PluginDescriptor 类 * * @param pluginJar jar 包 */ - public static PluginInfo readPlugin(File pluginJar) throws IOException { + public static PluginDescriptor readPlugin(File pluginJar) throws IOException { InputStream is; StringBuilder sb; try (JarFile jarFile = new JarFile(pluginJar)) { @@ -48,7 +46,7 @@ public class PluginLoader { } } } - return JsonUtil.OBJECT_MAPPER.readValue(sb.toString(), PluginInfo.class); + return JsonUtil.OBJECT_MAPPER.readValue(sb.toString(), PluginDescriptor.class); } public static PluginLoader getInstance() { @@ -58,38 +56,38 @@ public class PluginLoader { /** * 检查插件 * - * @param configPluginInfos 配置文件插件信息 - * @param pluginInfo 插件信息类 - * @param pluginInfos 插件信息集合 + * @param configPluginDescriptors 配置文件插件信息 + * @param pluginDescriptor 插件信息类 + * @param pluginDescriptors 插件信息集合 * @return boolean 是否检查通过 * @apiNote * @since 2023/9/16 14:04 */ - private static boolean checkPlugin(List configPluginInfos, PluginInfo pluginInfo, List pluginInfos) { + private static boolean checkPlugin(List configPluginDescriptors, PluginDescriptor pluginDescriptor, List pluginDescriptors) { // 如果应用程序配置文件为空则默认插件被禁用 - if (configPluginInfos.isEmpty()) { - return disabledByDefault(configPluginInfos, pluginInfo, pluginInfos); + if (configPluginDescriptors.isEmpty()) { + return disabledByDefault(configPluginDescriptors, pluginDescriptor, pluginDescriptors); } // 如果应用程序配置文件中该插件禁用则不加载 - for (PluginInfo configPluginInfo : configPluginInfos) { - if (disableDoNotLoad(pluginInfo, pluginInfos, configPluginInfo)) { + for (PluginDescriptor configPluginDescriptor : configPluginDescriptors) { + if (disableDoNotLoad(pluginDescriptor, pluginDescriptors, configPluginDescriptor)) { return true; } } // 判断该插件是否已经加载 - return loaded(pluginInfo, pluginInfos); + return loaded(pluginDescriptor, pluginDescriptors); } - private static boolean loaded(PluginInfo pluginInfo, List pluginInfos) { - Iterator iterator = pluginInfos.iterator(); + private static boolean loaded(PluginDescriptor pluginDescriptor, List pluginDescriptors) { + Iterator iterator = pluginDescriptors.iterator(); while (iterator.hasNext()) { - PluginInfo plugin = iterator.next(); - if ((plugin.getName() + plugin.getAuthor()).equals(pluginInfo.getName() + pluginInfo.getAuthor())) { - if (plugin.getVersion().equals(pluginInfo.getVersion())) { + PluginDescriptor plugin = iterator.next(); + if ((plugin.getName() + plugin.getAuthor()).equals(pluginDescriptor.getName() + pluginDescriptor.getAuthor())) { + if (plugin.getVersion().equals(pluginDescriptor.getVersion())) { return true; } // 如果当前插件版本更低则更新 - if (plugin.getVersion().compareTo(pluginInfo.getVersion()) < 0) { + if (plugin.getVersion().compareTo(pluginDescriptor.getVersion()) < 0) { // 删除当前的插件 iterator.remove(); } else { @@ -100,19 +98,19 @@ public class PluginLoader { return false; } - private static boolean disableDoNotLoad(PluginInfo pluginInfo, List pluginInfos, PluginInfo configPluginInfo) { - if ((configPluginInfo.getName() + configPluginInfo.getAuthor()).equals(pluginInfo.getName() + pluginInfo.getAuthor()) && !configPluginInfo.isEnabled()) { - pluginInfo.setEnabled(false); - pluginInfos.add(pluginInfo); + private static boolean disableDoNotLoad(PluginDescriptor pluginDescriptor, List pluginDescriptors, PluginDescriptor configPluginDescriptor) { + if ((configPluginDescriptor.getName() + configPluginDescriptor.getAuthor()).equals(pluginDescriptor.getName() + pluginDescriptor.getAuthor()) && !configPluginDescriptor.isEnabled()) { + pluginDescriptor.setEnabled(false); + pluginDescriptors.add(pluginDescriptor); return true; } return false; } - private static boolean disabledByDefault(List configPluginInfos, PluginInfo pluginInfo, List pluginInfos) { - pluginInfo.setEnabled(false); - pluginInfos.add(pluginInfo); - configPluginInfos.add(pluginInfo); + private static boolean disabledByDefault(List configPluginDescriptors, PluginDescriptor pluginDescriptor, List pluginDescriptors) { + pluginDescriptor.setEnabled(false); + pluginDescriptors.add(pluginDescriptor); + configPluginDescriptors.add(pluginDescriptor); PluginConfigController.getInstance().writeConfig(); return true; } @@ -131,36 +129,32 @@ public class PluginLoader { * 根据文件加载插件 * * @param pluginJar 插件jar包 - * @param configPluginInfos 配置文件插件信息集合 + * @param configPluginDescriptors 配置文件插件信息集合 * @apiNote * @since 2023/9/16 14:05 */ - public void loadPluginByFile(File pluginJar, List configPluginInfos) { + public void loadPluginByFile(File pluginJar, List configPluginDescriptors) { PluginManager pluginManager = PluginManager.getInstance(); Map> categories = pluginManager.getLoadedPluginsByCategory(); - List pluginInfos = pluginManager.getPluginInfos(); + List pluginDescriptors = pluginManager.getPluginInfos(); if (pluginJar.exists() && pluginJar.isFile()) { try { - PluginInfo pluginInfo = readPlugin(pluginJar); + PluginDescriptor pluginDescriptor = readPlugin(pluginJar); // 检查插件状态 - if (checkPlugin(configPluginInfos, pluginInfo, pluginInfos)) { + if (checkPlugin(configPluginDescriptors, pluginDescriptor, pluginDescriptors)) { return; } - pluginInfo.setEnabled(true); - pluginInfos.add(pluginInfo); + pluginDescriptor.setEnabled(true); + pluginDescriptors.add(pluginDescriptor); // 创建URLClassLoader以加载Jar文件中的类 - Class pluginClass; - try (URLClassLoader classLoader = new URLClassLoader(new URL[]{pluginJar.toURI().toURL()})) { - logger.info("{}", pluginInfo.getMainClass()); - pluginClass = classLoader.loadClass(pluginInfo.getMainClass()); - } + Class pluginClass = loaderJarFileClass(pluginJar, pluginDescriptor); if (pluginClass == null) { return; } Plugin plugin; plugin = (Plugin) pluginClass.getDeclaredConstructor().newInstance(); - pluginInfo.setPlugin(plugin); - categories.computeIfAbsent(pluginInfo.getCategory(), k -> new ArrayList<>()).add(pluginInfo.getName()); + pluginDescriptor.setPlugin(plugin); + categories.computeIfAbsent(pluginDescriptor.getCategory(), k -> new ArrayList<>()).add(pluginDescriptor.getName()); } catch (IOException | InvocationTargetException | InstantiationException | IllegalAccessException e) { throw new AppException(e); } catch (ClassNotFoundException e) { @@ -170,7 +164,39 @@ public class PluginLoader { } } else { - LogUtil.getLogger(this.getClass()).info("PluginInfo file not found"); + LogUtil.getLogger(this.getClass()).info("PluginDescriptor file not found"); } } + + /** + * 加载类中的class文件并返回插件主类 + * + * @param pluginJar 插件jar包 + * @param pluginDescriptor 插件描述 + * @return java.lang.Class 插件主类 + * @apiNote + * @since 2023/9/19 14:00 + */ + private Class loaderJarFileClass(File pluginJar, PluginDescriptor pluginDescriptor) throws IOException, ClassNotFoundException { + Class pluginClass; + try ( + URLClassLoader classLoader = new URLClassLoader(new URL[]{pluginJar.toURI().toURL()}); + JarFile jar = new JarFile(pluginJar) + ) { + logger.info("{}", pluginDescriptor.getMainClass()); + // 加载插件所需的依赖类 + Enumeration entries = jar.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + if (entry.getName().endsWith(".class")) { + String className = entry.getName().replace("/", ".").replace(".class", ""); + if (!pluginDescriptor.getMainClass().equals(className) && !"module-info".equals(className)) { + classLoader.loadClass(className); + } + } + } + pluginClass = classLoader.loadClass(pluginDescriptor.getMainClass()); + } + return pluginClass; + } } diff --git a/src/main/java/org/jcnc/jnotepad/plugin/PluginManager.java b/src/main/java/org/jcnc/jnotepad/plugin/PluginManager.java index 76a35b3..8b0a498 100644 --- a/src/main/java/org/jcnc/jnotepad/plugin/PluginManager.java +++ b/src/main/java/org/jcnc/jnotepad/plugin/PluginManager.java @@ -2,7 +2,7 @@ package org.jcnc.jnotepad.plugin; import org.jcnc.jnotepad.common.manager.ThreadPoolManager; import org.jcnc.jnotepad.controller.config.PluginConfigController; -import org.jcnc.jnotepad.model.entity.PluginInfo; +import org.jcnc.jnotepad.model.entity.PluginDescriptor; import org.jcnc.jnotepad.util.LogUtil; import org.slf4j.Logger; @@ -35,7 +35,7 @@ public class PluginManager { /** * 插件信息 */ - private final List pluginInfos = new ArrayList<>(); + private final List pluginDescriptors = new ArrayList<>(); Logger logger = LogUtil.getLogger(this.getClass()); private PluginManager() { @@ -50,14 +50,14 @@ public class PluginManager { /** * 卸载插件 * - * @param pluginInfo 插件信息类 + * @param pluginDescriptor 插件信息类 * @since 2023/9/11 12:28 */ - public void unloadPlugin(PluginInfo pluginInfo) { + public void unloadPlugin(PluginDescriptor pluginDescriptor) { // 删除集合中的插件信息 - pluginInfos.remove(pluginInfo); + pluginDescriptors.remove(pluginDescriptor); PluginConfigController instance = PluginConfigController.getInstance(); - instance.getConfig().getPlugins().remove(pluginInfo); + instance.getConfig().getPlugins().remove(pluginDescriptor); // 刷新配置 instance.writeConfig(); // 删除本地插件jar包 @@ -66,8 +66,8 @@ public class PluginManager { pathStream.filter(path -> path.toString().endsWith(".jar")).forEach(path -> { try { File pluginJar = new File(path.toString()); - PluginInfo temp = readPlugin(pluginJar); - if ((temp.getName() + temp.getAuthor()).equals(pluginInfo.getName() + pluginInfo.getAuthor())) { + PluginDescriptor temp = readPlugin(pluginJar); + if ((temp.getName() + temp.getAuthor()).equals(pluginDescriptor.getName() + pluginDescriptor.getAuthor())) { Files.delete(pluginJar.toPath()); } } catch (IOException e) { @@ -83,17 +83,17 @@ public class PluginManager { /** * 禁用插件 * - * @param pluginInfo 需要禁用的某个插件的插件类 + * @param pluginDescriptor 需要禁用的某个插件的插件类 * @apiNote * @since 2023/9/11 12:34 */ - public void disablePlugIn(PluginInfo pluginInfo) { - pluginInfo.setEnabled(false); - pluginInfo.setPlugin(null); + public void disablePlugIn(PluginDescriptor pluginDescriptor) { + pluginDescriptor.setEnabled(false); + pluginDescriptor.setPlugin(null); ThreadPoolManager.getThreadPool().submit(() -> { PluginConfigController instance = PluginConfigController.getInstance(); instance.getConfig().getPlugins().forEach(plugin -> { - if ((pluginInfo.getName() + pluginInfo.getAuthor()).equals(plugin.getName() + plugin.getAuthor())) { + if ((pluginDescriptor.getName() + pluginDescriptor.getAuthor()).equals(plugin.getName() + plugin.getAuthor())) { plugin.setEnabled(false); } }); @@ -106,9 +106,9 @@ public class PluginManager { * 初始化所有启用的插件 */ public void initializePlugins() { - for (PluginInfo pluginInfo : pluginInfos) { - if (pluginInfo.isEnabled()) { - pluginInfo.getPlugin().initialize(); + for (PluginDescriptor pluginDescriptor : pluginDescriptors) { + if (pluginDescriptor.isEnabled()) { + pluginDescriptor.getPlugin().initialize(); } } } @@ -116,12 +116,12 @@ public class PluginManager { /** * 执行插件 * - * @param pluginInfo 需要执行的插件的信息类 + * @param pluginDescriptor 需要执行的插件的信息类 * @apiNote * @since 2023/9/16 14:58 */ - public void executePlugin(PluginInfo pluginInfo) { - pluginInfo.getPlugin().execute(); + public void executePlugin(PluginDescriptor pluginDescriptor) { + pluginDescriptor.getPlugin().execute(); } /** @@ -129,9 +129,9 @@ public class PluginManager { * todo 待移除 */ public void executePlugins() { - for (PluginInfo pluginInfo : pluginInfos) { - if (pluginInfo.isEnabled()) { - pluginInfo.getPlugin().execute(); + for (PluginDescriptor pluginDescriptor : pluginDescriptors) { + if (pluginDescriptor.isEnabled()) { + pluginDescriptor.getPlugin().execute(); } } } @@ -145,7 +145,7 @@ public class PluginManager { return categories; } - public List getPluginInfos() { - return pluginInfos; + public List getPluginInfos() { + return pluginDescriptors; } } diff --git a/src/main/java/org/jcnc/jnotepad/plugin/interfaces/Plugin.java b/src/main/java/org/jcnc/jnotepad/plugin/interfaces/Plugin.java index a4143b4..daab29f 100644 --- a/src/main/java/org/jcnc/jnotepad/plugin/interfaces/Plugin.java +++ b/src/main/java/org/jcnc/jnotepad/plugin/interfaces/Plugin.java @@ -9,6 +9,7 @@ package org.jcnc.jnotepad.plugin.interfaces; * @author luke gewuyou */ public interface Plugin { + /** * 初始化插件 */ @@ -18,4 +19,9 @@ public interface Plugin { * 执行插件的逻辑 */ void execute(); + + /** + * 销毁资源 + */ + void destroyed(); } diff --git a/src/main/java/org/jcnc/jnotepad/views/manager/ViewManager.java b/src/main/java/org/jcnc/jnotepad/views/manager/ViewManager.java index ffe07a4..9a57f5f 100644 --- a/src/main/java/org/jcnc/jnotepad/views/manager/ViewManager.java +++ b/src/main/java/org/jcnc/jnotepad/views/manager/ViewManager.java @@ -5,6 +5,8 @@ import javafx.scene.layout.BorderPane; import org.jcnc.jnotepad.exception.AppException; import org.jcnc.jnotepad.views.root.RootBorderPane; +import static org.jcnc.jnotepad.views.root.bottom.RootBottomSideBarVerticalBox.initSidebarVerticalBox; + /** * 视图管理器类,用于管理记事本应用程序的视图组件。 * @@ -72,5 +74,6 @@ public class ViewManager { root.setCenter(RootBorderPane.getInstance()); scene.setRoot(root); + initSidebarVerticalBox(); } } diff --git a/src/main/java/org/jcnc/jnotepad/views/root/bottom/RootBottomSideBarVerticalBox.java b/src/main/java/org/jcnc/jnotepad/views/root/bottom/RootBottomSideBarVerticalBox.java index cbb2f53..b5d6830 100644 --- a/src/main/java/org/jcnc/jnotepad/views/root/bottom/RootBottomSideBarVerticalBox.java +++ b/src/main/java/org/jcnc/jnotepad/views/root/bottom/RootBottomSideBarVerticalBox.java @@ -2,7 +2,7 @@ package org.jcnc.jnotepad.views.root.bottom; import javafx.scene.layout.VBox; import org.jcnc.jnotepad.ui.module.AbstractVerticalBox; -import org.jcnc.jnotepad.views.root.bottom.cmd.CmdStatusBox; +import org.jcnc.jnotepad.views.root.bottom.function.FunctionBox; import org.jcnc.jnotepad.views.root.bottom.status.BottomStatusBox; /** @@ -14,7 +14,10 @@ import org.jcnc.jnotepad.views.root.bottom.status.BottomStatusBox; */ public class RootBottomSideBarVerticalBox extends AbstractVerticalBox { - VBox bottomSideBarVerticalBox; + /** + * VBox实例 + */ + private static final VBox V_BOX_INSTANCE = new VBox(); /** * 获取 RootBottomSideBarVerticalBox 的唯一实例。 @@ -25,20 +28,30 @@ public class RootBottomSideBarVerticalBox extends AbstractVerticalBox { return INSTANCE; } - public void initSidebarVerticalBox() { - bottomSideBarVerticalBox = new VBox(); + public RootBottomSideBarVerticalBox() { - bottomSideBarVerticalBox.getChildren().addAll(CmdStatusBox.getInstance(), BottomStatusBox.getInstance()); - - - getChildren().addAll(bottomSideBarVerticalBox); + } + /** + * 获取vbox实例 + * + * @return VBox + */ + public static VBox getVboxInstance() { + return V_BOX_INSTANCE; } private static final RootBottomSideBarVerticalBox INSTANCE = new RootBottomSideBarVerticalBox(); - public RootBottomSideBarVerticalBox() { - initSidebarVerticalBox(); + public static void initSidebarVerticalBox() { + FunctionBox functionBox = FunctionBox.getInstance(); + if (!FunctionBox.getMenuBar().getMenus().isEmpty()) { + functionBox.getChildren().add(FunctionBox.getMenuBar()); + V_BOX_INSTANCE.getChildren().addAll(functionBox); + } + V_BOX_INSTANCE.getChildren().addAll(BottomStatusBox.getInstance()); + INSTANCE.getChildren().addAll(V_BOX_INSTANCE); + } } diff --git a/src/main/java/org/jcnc/jnotepad/views/root/bottom/cmd/CmdStatusBox.java b/src/main/java/org/jcnc/jnotepad/views/root/bottom/cmd/CmdStatusBox.java deleted file mode 100644 index 74842f6..0000000 --- a/src/main/java/org/jcnc/jnotepad/views/root/bottom/cmd/CmdStatusBox.java +++ /dev/null @@ -1,118 +0,0 @@ -package org.jcnc.jnotepad.views.root.bottom.cmd; - -import javafx.geometry.Insets; -import javafx.scene.Scene; -import javafx.scene.control.Label; -import javafx.scene.control.Menu; -import javafx.scene.control.MenuBar; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; -import javafx.stage.Stage; -import org.jcnc.jnotepad.ui.module.TerminalEmulatorComponent; -import org.jcnc.jnotepad.util.UiUtil; - -/** - * CmdStatusBox 类表示应用程序的命令状态框。 - *

- * 该框包括一个菜单栏,用于运行、终端和构建命令。用户可以点击终端菜单项以切换终端的显示状态。 - * 终端显示时,将创建一个新的窗口以显示终端模拟器组件。 - * - * @author luke - */ -public class CmdStatusBox extends HBox { - - Stage terminalStage = new Stage(); - - private static final CmdStatusBox CMD_STATUS_BOX = new CmdStatusBox(); - - /** - * 用于跟踪终端的显示状态 - */ - private boolean terminalVisible = false; - - private CmdStatusBox() { - initStatusBox(); - } - - /** - * 获取 CmdStatusBox 的实例。 - * - * @return CmdStatusBox 的实例 - */ - public static CmdStatusBox getInstance() { - return CMD_STATUS_BOX; - } - - /** - * 初始化命令状态框。 - */ - public void initStatusBox() { - var menuBar = new MenuBar(); - HBox.setHgrow(menuBar, Priority.ALWAYS); - menuBar.setPadding(new Insets(-3, 0, -3, 35)); - - var runMenu = new Menu(); - var cmdMenu = new Menu(); - var buildMenu = new Menu(); - - var runLabel = new Label("运行"); - var cmdLabel = new Label("终端"); - var buildLabel = new Label("构建"); - - runMenu.setGraphic(runLabel); - cmdMenu.setGraphic(cmdLabel); - buildMenu.setGraphic(buildLabel); - - cmdLabel.setOnMouseClicked(mouseEvent -> { - toggleTerminal(); // 切换终端的显示/隐藏状态 - }); - - menuBar.getMenus().addAll(runMenu, cmdMenu, buildMenu); - this.getChildren().add(menuBar); - } - - /** - * 切换终端的显示/隐藏状态。 - */ - private void toggleTerminal() { - if (terminalVisible) { - // 隐藏终端 - terminalVisible = false; - hideTerminal(); - } else { - // 显示终端 - terminalVisible = true; - showTerminal(); - } - } - - /** - * 隐藏终端窗口。 - */ - private void hideTerminal() { - terminalStage.close(); - } - - /** - * 显示终端窗口。 - */ - private void showTerminal() { - // 创建一个新的舞台(窗口) - terminalStage.setTitle("终端"); - terminalStage.getIcons().add(UiUtil.getAppIcon()); - - // 创建一个根节点(布局) - BorderPane root = new BorderPane(); - Scene scene = new Scene(root, UiUtil.getAppWindow().getWidth() - 50, UiUtil.getAppWindow().getHeight() / 3); - - // 创建TerminalEmulatorComponent并添加到根节点 - TerminalEmulatorComponent terminal = new TerminalEmulatorComponent(); - - root.setCenter(terminal); - terminalStage.setScene(scene); - - // 显示窗口 - terminalStage.show(); - } -} diff --git a/src/main/java/org/jcnc/jnotepad/views/root/bottom/function/FunctionBox.java b/src/main/java/org/jcnc/jnotepad/views/root/bottom/function/FunctionBox.java new file mode 100644 index 0000000..0fcd58e --- /dev/null +++ b/src/main/java/org/jcnc/jnotepad/views/root/bottom/function/FunctionBox.java @@ -0,0 +1,34 @@ +package org.jcnc.jnotepad.views.root.bottom.function; + +import javafx.geometry.Insets; +import javafx.scene.control.MenuBar; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; + +/** + * 功能栏 + * + * @author gewuyou + */ +public class FunctionBox extends HBox { + private static final FunctionBox INSTANCE = new FunctionBox(); + + private static final MenuBar MENU_BAR = new MenuBar(); + + static { + HBox.setHgrow(MENU_BAR, Priority.ALWAYS); + MENU_BAR.setPadding(new Insets(-3, 0, -3, 35)); + } + + private FunctionBox() { + + } + + public static FunctionBox getInstance() { + return INSTANCE; + } + + public static MenuBar getMenuBar() { + return MENU_BAR; + } +} diff --git a/src/main/java/org/jcnc/jnotepad/views/root/bottom/function/interfaces/AbstractFunctionChildrenBox.java b/src/main/java/org/jcnc/jnotepad/views/root/bottom/function/interfaces/AbstractFunctionChildrenBox.java new file mode 100644 index 0000000..785c429 --- /dev/null +++ b/src/main/java/org/jcnc/jnotepad/views/root/bottom/function/interfaces/AbstractFunctionChildrenBox.java @@ -0,0 +1,38 @@ +package org.jcnc.jnotepad.views.root.bottom.function.interfaces; + +import javafx.scene.control.Label; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuBar; +import org.jcnc.jnotepad.views.root.bottom.function.FunctionBox; + +/** + * 子功能栏抽象类(用于构建一个基本的子功能栏) + * + * @author gewuyou + */ +public abstract class AbstractFunctionChildrenBox { + protected final FunctionBox functionBox; + + protected final MenuBar menuBar; + + protected final Label label = new Label(getFunctionName()); + + protected Menu menu = new Menu(); + + protected AbstractFunctionChildrenBox() { + functionBox = FunctionBox.getInstance(); + menuBar = FunctionBox.getMenuBar(); + } + + public void initialize() { + menu.setGraphic(label); + menuBar.getMenus().add(menu); + } + + /** + * 获取功能按钮名称 + * + * @return 功能按钮名称 + */ + protected abstract String getFunctionName(); +}