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(); +}