diff --git a/pom.xml b/pom.xml
index f9d8aa1bb1e7ffe1f99210c7ef6a79bce9e53251..df454d8fe00ac48eede61e7219cf7ced94c030a5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -25,6 +25,19 @@
system
${project.basedir}/libs/richtextfx-fat-0.11.1.jar
+
+
+ org.commonmark
+ commonmark
+ 0.21.0
+
+
+
+ org.openjfx
+ javafx-web
+ ${javafx.version}
+
+
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 63ed10b1d6004b8ba71dfcf3167a097c2f3fcb71..dd4e9601c30bf7c23c3acc4d6fe2273fe7f9c0c7 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -16,6 +16,11 @@ module org.jcnc.jnotepad {
requires org.kordamp.ikonli.javafx;
requires org.kordamp.ikonli.antdesignicons;
requires richtextfx.fat;
+ requires java.desktop;
+ requires org.commonmark;
+ requires javafx.web;
+
+
exports org.jcnc.jnotepad;
exports org.jcnc.jnotepad.model.enums;
exports org.jcnc.jnotepad.app.config;
diff --git a/src/main/java/org/jcnc/jnotepad/ui/pluginstage/PluginManagementPane.java b/src/main/java/org/jcnc/jnotepad/ui/pluginstage/PluginManagementPane.java
index 2c5b3e9fe2758536b3510378ecdfed7efd64ab09..3a0566e4a603421f377fc29004f319c663206380 100644
--- a/src/main/java/org/jcnc/jnotepad/ui/pluginstage/PluginManagementPane.java
+++ b/src/main/java/org/jcnc/jnotepad/ui/pluginstage/PluginManagementPane.java
@@ -2,18 +2,30 @@ package org.jcnc.jnotepad.ui.pluginstage;
import atlantafx.base.controls.Tile;
import atlantafx.base.controls.ToggleSwitch;
-import atlantafx.base.theme.PrimerLight;
-import javafx.application.Application;
+import atlantafx.base.theme.Styles;
+import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.Button;
-import javafx.scene.control.Label;
-import javafx.scene.control.Tab;
-import javafx.scene.control.TabPane;
+import javafx.scene.web.WebEngine;
+import javafx.scene.web.WebView;
+import org.commonmark.parser.Parser;
+import org.commonmark.renderer.html.HtmlRenderer;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.control.*;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
+import javafx.scene.text.Text;
import org.jcnc.jnotepad.util.LogUtil;
import org.slf4j.Logger;
+import java.awt.*;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
@@ -26,10 +38,24 @@ import java.util.Map;
*/
public class PluginManagementPane extends BorderPane {
- Logger logger = LogUtil.getLogger(this.getClass());
+ /**
+ * 图标大小常量
+ */
+ public static int ICON_SIZE = 40;
+ /**
+ * 日志记录器
+ */
+ Logger logger = LogUtil.getLogger(this.getClass());
+ /**
+ * 自定义分割面板
+ */
private CustomSplitPane customSplitPane;
+
+ /**
+ * 用于存储Tile与其内容节点的映射关系
+ */
private final Map tileContentMap = new HashMap<>();
/**
@@ -44,7 +70,7 @@ public class PluginManagementPane extends BorderPane {
*/
private void init() {
// 创建选项卡面板
- TabPane tabPane = new TabPane();
+ TabPane rootTabPane = new TabPane();
// 创建市场、已安装和设置选项卡
Tab marketTab = new Tab("市场");
@@ -66,12 +92,11 @@ public class PluginManagementPane extends BorderPane {
marketTabContent.setCenter(customSplitPane);
// 获取插件列表
- var box = getBox();
- customSplitPane.setLeftContent(box);
+ customSplitPane.setLeftContent(getScrollPane());
// 创建示例按钮并添加到已安装和设置选项卡中
- installedTabContent.setCenter(new Button("2"));
- myTabContent.setCenter(new Button("3"));
+ installedTabContent.setCenter(new Button("已安装"));
+ myTabContent.setCenter(new Button("设置"));
// 将选项卡内容设置到选项卡中
marketTab.setContent(marketTabContent);
@@ -79,27 +104,53 @@ public class PluginManagementPane extends BorderPane {
myTab.setContent(myTabContent);
// 将选项卡添加到选项卡面板中
- tabPane.getTabs().addAll(marketTab, installedTab, myTab);
+ rootTabPane.getTabs().addAll(marketTab, installedTab, myTab);
// 将选项卡面板设置为插件管理面板的中心内容
- this.setCenter(tabPane);
+ this.setCenter(rootTabPane);
}
/**
- * 创建包含插件列表的VBox。
+ * 创建包含插件列表的VBox,并将其包装在滚动面板中。
*
- * @return 包含插件列表的VBox
+ * @return 包含插件列表的滚动面板
*/
- private VBox getBox() {
+ private ScrollPane getScrollPane() {
// 创建示例插件列表项
- var tile1 = createTile("运行插件", "这是一个运行插件\t\t\t\t\t\t\t ");
- var tile2 = createTile("终端插件", "这是一个终端插件");
- var tile3 = createTile("构建插件", "这是一个构建插件");
+ var image1 = new Image("plug.png");
+ var tile1 = createTile("运行插件", "这是一个运行插件\t\t\t\t\t\t", image1);
+
+ var image2 = new Image("plug.png");
+ var tile2 = createTile("终端插件", "这是一个终端插件", image2);
+
+ var image3 = new Image("plug.png");
+ var tile3 = createTile("构建插件", "这是一个构建插件", image3);
+
+ var image4 = new Image("plug.png");
+ var tile4 = createTile("1", "这是一个构建插件", image4);
+
+ var image5 = new Image("plug.png");
+ var tile5 = createTile("2", "这是一个构建插件", image5);
+
+ var image6 = new Image("plug.png");
+ var tile6 = createTile("4", "这是一个构建插件", image6);
+
+ var image7 = new Image("plug.png");
+ var tile7 = createTile("5", "这是一个构建插件", image7);
// 创建VBox并将插件列表项添加到其中
- var box = new VBox(tile1, tile2, tile3);
+ var box = new VBox(tile1, tile2, tile3, tile4, tile5, tile6, tile7);
+
+ // 创建滚动面板并将VBox设置为其内容
+ var scrollPane = new ScrollPane(box);
+
+ // 设置滚动面板的宽度适应父容器
+ scrollPane.setFitToWidth(true);
+ // 隐藏滚动条
+ scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
+ scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
- return box;
+ return scrollPane;
}
/**
@@ -107,24 +158,37 @@ public class PluginManagementPane extends BorderPane {
*
* @param title 插件标题
* @param description 插件描述
+ * @param image 插件图标
* @return 创建的插件列表项Tile
*/
- private Tile createTile(String title, String description) {
+ private Tile createTile(String title, String description, Image image) {
+ // 创建一个title
var tile = new Tile(title, description);
+ // 创建一个按钮
var tgl = new ToggleSwitch();
+ // 创建一个图标
+ ImageView icon = new ImageView(image);
+ // 指定要缩放的固定像素大小
+ double iconSize = ICON_SIZE;
+
+ // 设置图像视图的宽度和高度,以便等比例缩放到指定像素大小
+ icon.setFitWidth(iconSize);
+ icon.setFitHeight(iconSize);
+
+ // 设置Tile的图标
+ tile.setGraphic(icon);
+
// 设置Tile的操作和操作处理程序
tile.setAction(tgl);
tile.setActionHandler(() -> {
customSplitPane.setRightContent(tileContentMap.get(tile));
logger.info("点击了" + tile);
-
});
// 创建专属的customSplitPane内容
var content = createCustomSplitPaneContent(title);
-
// 将内容与Tile关联起来
tileContentMap.put(tile, content);
@@ -134,12 +198,142 @@ public class PluginManagementPane extends BorderPane {
/**
* 创建专属于每个插件的CustomSplitPane内容。
*
- * @param title 插件标题
+ * @param titleName 插件标题
* @return 创建的CustomSplitPane内容
*/
- private Node createCustomSplitPaneContent(String title) {
- // TODO: 2023/9/23 未完成
- return new Label("详情" + title);
+ private Node createCustomSplitPaneContent(String titleName) {
+ VBox content = new VBox(8);
+ content.setPadding(new Insets(10));
+ var titleLabel = new Text(titleName);
+ titleLabel.getStyleClass().addAll(Styles.TITLE_1);
+
+ var authorBox = new HBox(10);
+ var author = new Text("JCNC团队");
+ var authorLink = getAuthorLink();
+ authorBox.getChildren().addAll(author, authorLink);
+
+ var state = new Text("未启用");
+
+ var main = new VBox(10);
+
+ // 创建TabPane并添加标签页
+ TabPane tabPane = new TabPane();
+
+ Tab detailsTab = new Tab("细节");
+ detailsTab.setClosable(false);
+ Tab featuresTab = new Tab("实现功能");
+ featuresTab.setClosable(false);
+ Tab changelogTab = new Tab("更新日志");
+ changelogTab.setClosable(false);
+
+ // 在标签页中添加内容
+ VBox detailsContent = new VBox(10);
+
+ // 创建一个WebView来显示Markdown内容
+ WebView webView = new WebView();
+ WebEngine engine = webView.getEngine();
+
+ // 从外部文件加载Markdown内容
+ String markdownContent = loadMarkdownFromFile("README.md");
+ String htmlContent = markdownToHtml(markdownContent);
+
+ // 加载HTML内容到WebView
+ engine.loadContent(htmlContent);
+ // 将WebView添加到detailsContent
+ detailsContent.getChildren().addAll(webView);
+
+ VBox featuresContent = new VBox(10);
+ VBox changelogContent = new VBox(10);
+
+ detailsTab.setContent(detailsContent);
+ featuresTab.setContent(featuresContent);
+ changelogTab.setContent(changelogContent);
+
+ tabPane.getTabs().addAll(detailsTab, featuresTab, changelogTab);
+
+ main.getChildren().addAll(tabPane);
+
+ content.getChildren().addAll(titleLabel, authorBox, state, main);
+
+ // 将内容包装在滚动面板中
+ ScrollPane scrollPane = new ScrollPane(content);
+ scrollPane.setFitToWidth(true);
+ scrollPane.setFitToHeight(true);
+
+ return scrollPane;
+ }
+
+ /**
+ * 将Markdown内容转换为HTML格式。
+ *
+ * @param markdownContent Markdown格式的内容
+ * @return HTML格式的内容
+ */
+ private String markdownToHtml(String markdownContent) {
+ // 创建Markdown解析器
+ Parser parser = Parser.builder().build();
+
+ // 解析Markdown内容
+
+ org.commonmark.node.Node document = parser.parse(markdownContent);
+
+ // 创建HTML渲染器
+ HtmlRenderer renderer = HtmlRenderer.builder().build();
+
+ // 将Markdown文档渲染为HTML
+ return renderer.render(document);
+ }
+
+ /**
+ * 从文件加载Markdown内容。
+ *
+ * @param filePath 文件路径
+ * @return 加载的Markdown内容
+ */
+ private String loadMarkdownFromFile(String filePath) {
+ try {
+ return new String(Files.readAllBytes(Paths.get(filePath)));
+ } catch (IOException e) {
+ logger.info("正在运行" + "loadMarkdownFromFile");
+ return "";
+ }
+ }
+
+ /**
+ * 获取作者链接。
+ *
+ * @return 作者链接
+ */
+ private Hyperlink getAuthorLink() {
+ var authorLink = new Hyperlink("插件仓库地址");
+ authorLink.setVisited(true);
+ authorLink.setStyle("-fx-text-fill: blue; -fx-visited-link-color: blue;");
+ authorLink.setOnAction(event -> {
+ // 定义要打开的链接
+ String url = "https://gitee.com/jcnc-org/JNotepad";
+
+ try {
+ // 创建URI对象
+ URI uri = new URI(url);
+ // 检查系统是否支持Desktop类
+ if (Desktop.isDesktopSupported()) {
+ Desktop desktop = Desktop.getDesktop();
+
+ // 检查是否支持浏览器启动
+ if (desktop.isSupported(Desktop.Action.BROWSE)) {
+ // 打开默认浏览器并访问链接
+ desktop.browse(uri);
+ } else {
+ logger.info("系统不支持浏览器启动操作!");
+ }
+ } else {
+ logger.info("系统不支持Desktop类!");
+ }
+ } catch (Exception e) {
+ logger.info("启动" + authorLink + "失败!");
+ }
+ });
+ return authorLink;
}
}
diff --git a/src/main/java/org/jcnc/jnotepad/views/root/top/menu/TopMenuBar.java b/src/main/java/org/jcnc/jnotepad/views/root/top/menu/TopMenuBar.java
index 18e1bb5116a3e7ab1494af9f11e2c71f8a08cea5..4798632fbf57ac809d08e7410feef66772f3343e 100644
--- a/src/main/java/org/jcnc/jnotepad/views/root/top/menu/TopMenuBar.java
+++ b/src/main/java/org/jcnc/jnotepad/views/root/top/menu/TopMenuBar.java
@@ -277,7 +277,7 @@ public class TopMenuBar extends MenuBar {
PluginManagementPane pluginManagementPane = new PluginManagementPane();
- Scene scene = new Scene(pluginManagementPane, 900, 500);
+ Scene scene = new Scene(pluginManagementPane, 900, 600);
newStage.setScene(scene);
newStage.show();
});
diff --git a/src/main/resources/plug.png b/src/main/resources/plug.png
new file mode 100644
index 0000000000000000000000000000000000000000..68b925df731c9c302471b890cb6e6fbc03f6f1fe
Binary files /dev/null and b/src/main/resources/plug.png differ