diff --git a/.gitee/ISSUE_TEMPLATE/bug.yml b/.gitee/ISSUE_TEMPLATE/bug.yml index 6f61ca4..de96b8f 100644 --- a/.gitee/ISSUE_TEMPLATE/bug.yml +++ b/.gitee/ISSUE_TEMPLATE/bug.yml @@ -7,12 +7,12 @@ body: attributes: value: | 感谢对项目的支持与关注。在提出问题之前,请确保你已查看相关开发或使用文档: - - https://... + - https://gitee.com/jcnc-org/docs - type: checkboxes attributes: label: 这个问题是否已经存在? options: - - label: 我已经搜索过现有的问题 (https://gitee.com/../../issues) + - label: 我已经搜索过现有的问题 (https://gitee.com/organizations/jcnc-org/issues) required: true - type: textarea attributes: @@ -48,7 +48,7 @@ body: label: 版本 description: 你当前正在使用我们软件的哪个版本/分支? options: - - 1.0.2 (默认) - - 1.0.3 (最新) + - (默认) + - (最新) validations: required: true \ No newline at end of file diff --git a/.gitignore b/.gitignore index 88fbce5..9278379 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,6 @@ build/ /src/main/JNotepad.java /.idea/ /project.txt +logs/ +/ch_language_pack.txt +/en_language_pack.txt diff --git a/libs/README.md b/libs/README.md new file mode 100644 index 0000000..833df2a --- /dev/null +++ b/libs/README.md @@ -0,0 +1,43 @@ +# 解决jlink error指南 + +## 现象 + +jlink时,如果出现如下错误,参考本文档 + +``` +"automatic module cannot be used with jlink" +``` + +## 解决方法: + +1. 为jar生成module-info.class + +```shell +jdeps --ignore-missing-deps --module-path --add-modules +javac --patch-module = +jar uf -C +``` + +以本次icu4j为例,先将依赖的jar包copy到libs目录,然后执行: + +```shell +jdeps --ignore-missing-deps --module-path libs --add-modules com.ibm.icu --generate-module-info libs/tmpOut libs/icu4j-73.2.jar +javac --patch-module com.ibm.icu=libs/icu4j-73.2.jar libs/tmpOut/com.ibm.icu/module-info.java +jar uf libs/icu4j-73.2.jar -C libs/tmpOut/com.ibm.icu module-info.class +``` + +2. pom中添加依赖 + +```xml + + + com.ibm.icu + icu4j + 73.2 + system + ${project.basedir}/libs/icu4j-73.2.jar + +``` + +## 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/libs/icu4j-73.2.jar b/libs/icu4j-73.2.jar new file mode 100644 index 0000000..696a937 Binary files /dev/null and b/libs/icu4j-73.2.jar differ diff --git a/pom.xml b/pom.xml index 319c9c6..0fed9d1 100644 --- a/pom.xml +++ b/pom.xml @@ -55,6 +55,13 @@ logback-classic 1.4.11 + + com.ibm.icu + icu4j + 73.2 + system + ${project.basedir}/libs/icu4j-73.2.jar + diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 35e74dd..82564b9 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -9,6 +9,8 @@ module org.jcnc.jnotepad { requires org.slf4j; requires ch.qos.logback.core; requires ch.qos.logback.classic; + requires com.ibm.icu; + exports org.jcnc.jnotepad; exports org.jcnc.jnotepad.tool; exports org.jcnc.jnotepad.Interface; diff --git a/src/main/java/org/jcnc/jnotepad/Interface/ConfigInterface.java b/src/main/java/org/jcnc/jnotepad/Interface/ConfigInterface.java deleted file mode 100644 index 008eb2d..0000000 --- a/src/main/java/org/jcnc/jnotepad/Interface/ConfigInterface.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.jcnc.jnotepad.Interface; - -import java.util.Properties; - -/** - * @author 许轲 - */ -public interface ConfigInterface { - void showErrorAlert(); - Properties readPropertiesFromFile(); - void initializePropertiesFile(); -} diff --git a/src/main/java/org/jcnc/jnotepad/Interface/ControllerInterface.java b/src/main/java/org/jcnc/jnotepad/Interface/ControllerInterface.java index 34c53b9..feed804 100644 --- a/src/main/java/org/jcnc/jnotepad/Interface/ControllerInterface.java +++ b/src/main/java/org/jcnc/jnotepad/Interface/ControllerInterface.java @@ -1,7 +1,5 @@ package org.jcnc.jnotepad.Interface; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; import org.jcnc.jnotepad.ui.LineNumberTextArea; import java.io.File; @@ -21,43 +19,6 @@ public interface ControllerInterface { */ LineNumberTextArea openAssociatedFileAndCreateTextArea(List rawParameters); - /** - * 获取新建文件处理事件处理程序 - * - * @param textArea 文本区域 - * @return 新建文件处理事件处理程序 - */ - EventHandler getNewFileEventHandler(LineNumberTextArea textArea); - - /** - * 获取打开文件处理事件处理程序 - * - * @return 打开文件处理事件处理程序 - */ - EventHandler getOpenFileEventHandler(); - - /** - * 获取另存为文件处理事件处理程序 - * - * @return 另存为文件处理事件处理程序 - */ - EventHandler getSaveAsFileEventHandler(); - - - /** - * 自动保存 - * - * @param textArea 文本区域 - */ - void autoSave(LineNumberTextArea textArea); - - /** - * 更新状态标签 - * - * @param textArea 文本区域 - */ - void updateStatusLabel(LineNumberTextArea textArea); - /** * 打开关联文件 * @@ -72,36 +33,6 @@ public interface ControllerInterface { */ LineNumberTextArea getText(File file); - /** - * 更新编码标签 - * - * @param text 编码标签文本 - */ - void upDateEncodingLabel(String text); - - /** - * 获取光标所在行号 - * - * @param caretPosition 光标位置 - * @param text 文本内容 - * @return 行号 - */ - int getRow(int caretPosition, String text); - - /** - * 获取光标所在列号 - * - * @param caretPosition 光标位置 - * @param text 文本内容 - * @return 列号 - */ - int getColumn(int caretPosition, String text); - - /** - * 初始化 TabPane - */ - void initTabPane(); - /** * 更新UI和标签页 * diff --git a/src/main/java/org/jcnc/jnotepad/LunchApp.java b/src/main/java/org/jcnc/jnotepad/LunchApp.java index 0c81bfc..b8d4d15 100644 --- a/src/main/java/org/jcnc/jnotepad/LunchApp.java +++ b/src/main/java/org/jcnc/jnotepad/LunchApp.java @@ -53,22 +53,12 @@ public class LunchApp extends Application { double length = AppConstants.SCREEN_LENGTH; String icon = AppConstants.APP_ICON; + + scene = new Scene(root, width, length); Application.setUserAgentStylesheet(new PrimerLight().getUserAgentStylesheet()); scene.getStylesheets().add(Objects.requireNonNull(getClass().getResource("/css/styles.css")).toExternalForm()); - primaryStage.setTitle(title); - primaryStage.setWidth(width); - primaryStage.setHeight(length); - primaryStage.setScene(scene); - primaryStage.getIcons().add(new Image(Objects.requireNonNull(getClass().getResource(icon)).toString())); - primaryStage.show(); - ViewManager viewManager = ViewManager.getInstance(scene); - viewManager.initScreen(scene); - // 初始化菜单项和标签栏 - view.initTabPane(); - view.initShortcutKey(); - // 使用线程池加载关联文件并创建文本区域 List rawParameters = getParameters().getRaw(); THREAD_POOL.execute(() -> { @@ -77,6 +67,18 @@ public class LunchApp extends Application { Platform.runLater(() -> controller.updateUiWithNewTextArea(textArea)); } }); + primaryStage.setTitle(title); + primaryStage.setWidth(width); + primaryStage.setHeight(length); + primaryStage.setScene(scene); + primaryStage.getIcons().add(new Image(Objects.requireNonNull(getClass().getResource(icon)).toString())); + primaryStage.show(); + ViewManager viewManager = ViewManager.getInstance(scene); + viewManager.initScreen(scene); + // 初始化快捷键 + view.initShortcutKey(); + + } @Override diff --git a/src/main/java/org/jcnc/jnotepad/constants/AppConstants.java b/src/main/java/org/jcnc/jnotepad/constants/AppConstants.java index 3650c4b..307078c 100644 --- a/src/main/java/org/jcnc/jnotepad/constants/AppConstants.java +++ b/src/main/java/org/jcnc/jnotepad/constants/AppConstants.java @@ -29,6 +29,7 @@ public class AppConstants { /** * 配置文件名 */ - public static final String PROPERTY_FILE_NAME = "project.txt"; + public static final String CH_LANGUAGE_PACK_NAME = "ch_language_pack.txt"; + public static final String EN_LANGUAGE_PACK_NAME = "en_language_pack.txt"; } diff --git a/src/main/java/org/jcnc/jnotepad/controller/event/handler/LineFeed.java b/src/main/java/org/jcnc/jnotepad/controller/event/handler/LineFeed.java deleted file mode 100644 index ea8c4f5..0000000 --- a/src/main/java/org/jcnc/jnotepad/controller/event/handler/LineFeed.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.jcnc.jnotepad.controller.event.handler; - -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import org.jcnc.jnotepad.app.config.GlobalConfig; - -/** - * 换行事件处理,针对当前选中tab进行格式化。
- * 配置变更时:
- * 1. 更新内存全局配置
- * 2. 对当前tab生效配置。每次tab切换,根据全局配置设置进行变更
- *

- * 用于在文本区域中插入一个换行符。 - * @see GlobalConfig - * - * @deprecated 事件处理将使用item的listener实现 - * - * @author 许轲 - */ -@Deprecated -public class LineFeed implements EventHandler { - /** - * 处理事件的方法,将一个换行符插入到文本区域的末尾。 - * - * @param event 触发的事件对象 - */ - @Override - public void handle(ActionEvent event) { - // - - } -} diff --git a/src/main/java/org/jcnc/jnotepad/controller/event/handler/NewFile.java b/src/main/java/org/jcnc/jnotepad/controller/event/handler/NewFile.java index 1e0e83f..0565aae 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/event/handler/NewFile.java +++ b/src/main/java/org/jcnc/jnotepad/controller/event/handler/NewFile.java @@ -2,12 +2,15 @@ package org.jcnc.jnotepad.controller.event.handler; import javafx.event.ActionEvent; import javafx.event.EventHandler; -import org.jcnc.jnotepad.controller.manager.Controller; +import org.jcnc.jnotepad.init.Config; import org.jcnc.jnotepad.ui.LineNumberTextArea; +import org.jcnc.jnotepad.ui.status.JNotepadStatusBox; import org.jcnc.jnotepad.ui.tab.JNotepadTab; import org.jcnc.jnotepad.ui.tab.JNotepadTabPane; import org.jcnc.jnotepad.view.manager.ViewManager; +import java.util.Properties; + /** * 新建文件事件的事件处理程序。 @@ -17,36 +20,30 @@ import org.jcnc.jnotepad.view.manager.ViewManager; * @author 许轲 */ public class NewFile implements EventHandler { + + Config config = new Config(); + Properties properties = config.readPropertiesFromFile(); + String NEW_FILE = properties.getProperty("NEW_FILE"); /** + * * 处理新建文件事件。 * * @param event 事件对象 */ @Override public void handle(ActionEvent event) { - // 获取控制器 - Controller controller = Controller.getInstance(); // 创建一个新的文本编辑区 LineNumberTextArea textArea = new LineNumberTextArea(); - textArea.setStyle( - "-fx-border-color:white ;-fx-background-color:white;" - ); - // TODO: refactor:统一TextArea新建、绑定监听器入口 - // 增加autoSave监听器绑定 - controller.autoSave(textArea); ViewManager viewManager = ViewManager.getInstance(); // 将Tab页添加到TabPane中 - JNotepadTabPane.getInstance().addNewTab(new JNotepadTab("新建文本 " + JNotepadTabPane.getInstance().addNewTab(new JNotepadTab(NEW_FILE + viewManager.selfIncreaseAndGetTabIndex(), textArea)); - // 更新状态标签 - controller.updateStatusLabel(textArea); - // 更新编码信息 - controller.upDateEncodingLabel(textArea.getMainTextArea().getText()); + JNotepadStatusBox.getInstance().updateEncodingLabel(); } } \ No newline at end of file diff --git a/src/main/java/org/jcnc/jnotepad/controller/event/handler/OpenFile.java b/src/main/java/org/jcnc/jnotepad/controller/event/handler/OpenFile.java index 4fdd55c..97fe5bb 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/event/handler/OpenFile.java +++ b/src/main/java/org/jcnc/jnotepad/controller/event/handler/OpenFile.java @@ -5,8 +5,6 @@ import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.stage.FileChooser; import org.jcnc.jnotepad.controller.manager.Controller; -import org.jcnc.jnotepad.ui.LineNumberTextArea; -import org.jcnc.jnotepad.ui.tab.JNotepadTabPane; import java.io.File; @@ -15,6 +13,7 @@ import java.io.File; * 打开文件的事件处理程序。 *

* 当用户选择打开文件时,将创建一个新的文本编辑区,并在Tab页中显示。 + * * @author 许轲 */ public class OpenFile implements EventHandler { @@ -38,8 +37,6 @@ public class OpenFile implements EventHandler { protected Void call() { // 调用控制器的getText方法,读取文件内容 controller.getText(file); - // 更新编码标签 - controller.upDateEncodingLabel(((LineNumberTextArea) JNotepadTabPane.getInstance().getSelected().getContent()).getMainTextArea().getText()); return null; } }; diff --git a/src/main/java/org/jcnc/jnotepad/controller/event/handler/SaveFile.java b/src/main/java/org/jcnc/jnotepad/controller/event/handler/SaveFile.java index a6f5f76..bab2bdd 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/event/handler/SaveFile.java +++ b/src/main/java/org/jcnc/jnotepad/controller/event/handler/SaveFile.java @@ -2,10 +2,9 @@ package org.jcnc.jnotepad.controller.event.handler; import javafx.event.ActionEvent; import javafx.event.EventHandler; -import javafx.scene.control.Tab; -import org.jcnc.jnotepad.controller.manager.Controller; import org.jcnc.jnotepad.tool.LogUtil; import org.jcnc.jnotepad.ui.LineNumberTextArea; +import org.jcnc.jnotepad.ui.tab.JNotepadTab; import org.jcnc.jnotepad.ui.tab.JNotepadTabPane; import org.slf4j.Logger; @@ -28,7 +27,7 @@ public class SaveFile implements EventHandler { @Override public void handle(ActionEvent actionEvent) { // 获取当前tab页 - Tab selectedTab = JNotepadTabPane.getInstance().getSelected(); + JNotepadTab selectedTab = JNotepadTabPane.getInstance().getSelected(); if (selectedTab == null) { return; } @@ -40,10 +39,8 @@ public class SaveFile implements EventHandler { saveTab(this.getClass()); } else { logger.info("当前保存文件为关联打开文件,调用自动保存方法"); - // 打开的是关联文件 - Controller controller = Controller.getInstance(); - // 自动保存 - controller.autoSave(textArea); + // 调用tab保存 + selectedTab.save(); } } } diff --git a/src/main/java/org/jcnc/jnotepad/controller/manager/Controller.java b/src/main/java/org/jcnc/jnotepad/controller/manager/Controller.java index 1d06777..273c1a5 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/manager/Controller.java +++ b/src/main/java/org/jcnc/jnotepad/controller/manager/Controller.java @@ -2,13 +2,8 @@ package org.jcnc.jnotepad.controller.manager; import javafx.application.Platform; import javafx.concurrent.Task; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.scene.control.Tab; import org.jcnc.jnotepad.Interface.ControllerInterface; -import org.jcnc.jnotepad.controller.event.handler.NewFile; -import org.jcnc.jnotepad.controller.event.handler.OpenFile; -import org.jcnc.jnotepad.controller.event.handler.SaveAsFile; +import org.jcnc.jnotepad.init.Config; import org.jcnc.jnotepad.tool.EncodingDetector; import org.jcnc.jnotepad.tool.LogUtil; import org.jcnc.jnotepad.ui.LineNumberTextArea; @@ -16,9 +11,13 @@ import org.jcnc.jnotepad.ui.tab.JNotepadTab; import org.jcnc.jnotepad.ui.tab.JNotepadTabPane; import org.jcnc.jnotepad.view.manager.ViewManager; -import java.io.*; -import java.util.ArrayList; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.nio.charset.Charset; import java.util.List; +import java.util.Properties; /** * 控制器类,实现ControllerInterface接口,用于管理文本编辑器的各种操作和事件处理。 @@ -27,6 +26,11 @@ import java.util.List; * @author 许轲 */ public class Controller implements ControllerInterface { + + Config config = new Config(); + Properties properties = config.readPropertiesFromFile(); + + String NEW_FILE = properties.getProperty("NEW_FILE"); private static final Controller INSTANCE = new Controller(); private Controller() { @@ -57,74 +61,6 @@ public class Controller implements ControllerInterface { } } - /** - * 获取新建文件事件处理程序。 - * - * @param textArea 文本区域 - * @return 新建文件事件处理程序 - */ - @Override - public EventHandler getNewFileEventHandler(LineNumberTextArea textArea) { - return new NewFile(); - } - - /** - * 获取打开文件事件处理程序。 - * - * @return 打开文件事件处理程序 - */ - @Override - public EventHandler getOpenFileEventHandler() { - return new OpenFile(); - } - - /** - * 自动保存文本内容。 - * - * @param textArea 文本区域 - */ - @Override - public void autoSave(LineNumberTextArea textArea) { - textArea.getMainTextArea().textProperty().addListener((observable, oldValue, newValue) -> { - Tab tab = JNotepadTabPane.getInstance().getSelected(); - if (tab != null) { - File file = (File) tab.getUserData(); - if (file != null) { - try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { - writer.write(newValue); - LogUtil.getLogger(this.getClass()).info("正在自动保存---"); - } catch (IOException ignored) { - LogUtil.getLogger(this.getClass()).info("已忽视IO异常!"); - } - } - } - }); - } - - /** - * 获取另存为文件事件处理程序。 - * - * @return 另存为文件事件处理程序 - */ - @Override - public EventHandler getSaveAsFileEventHandler() { - return new SaveAsFile(); - } - - /** - * 更新状态标签。 - * - * @param textArea 文本区域 - */ - @Override - public void updateStatusLabel(LineNumberTextArea textArea) { - int caretPosition = textArea.getMainTextArea().getCaretPosition(); - int row = getRow(caretPosition, textArea.getMainTextArea().getText()); - int column = getColumn(caretPosition, textArea.getMainTextArea().getText()); - int length = textArea.getMainTextArea().getLength(); - ViewManager.getInstance().getStatusLabel().setText("行: " + row + " \t列: " + column + " \t字数: " + length); - } - /** * 打开关联文件。 * @@ -148,7 +84,9 @@ public class Controller implements ControllerInterface { LineNumberTextArea textArea = createNewTextArea(); // 设置当前标签页关联本地文件 textArea.setRelevance(true); - try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + // 检测文件编码 + Charset encoding = EncodingDetector.detectEncodingCharset(file); + try (BufferedReader reader = new BufferedReader(new FileReader(file, encoding))) { StringBuilder textBuilder = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { @@ -158,11 +96,9 @@ public class Controller implements ControllerInterface { Platform.runLater(() -> { textArea.getMainTextArea().setText(text); - JNotepadTab tab = createNewTab(file.getName(), textArea); + JNotepadTab tab = createNewTab(file.getName(), textArea, encoding); tab.setUserData(file); JNotepadTabPane.getInstance().addNewTab(tab); - updateStatusLabel(textArea); - autoSave(textArea); }); } catch (IOException ignored) { @@ -171,74 +107,6 @@ public class Controller implements ControllerInterface { return textArea; } - /** - * 更新编码标签。 - * - * @param text 文本内容 - */ - @Override - public void upDateEncodingLabel(String text) { - String encoding = EncodingDetector.detectEncoding(text); - ViewManager.getInstance().getEnCodingLabel().setText("\t编码: " + encoding); - } - - /** - * 获取光标所在行号。 - * - * @param caretPosition 光标位置 - * @param text 文本内容 - * @return 光标所在行号 - */ - @Override - public int getRow(int caretPosition, String text) { - caretPosition = Math.min(caretPosition, text.length()); - String substring = text.substring(0, caretPosition); - int count = 0; - for (char c : substring.toCharArray()) { - if (c == '\n') { - count++; - } - } - return count + 1; - } - - /** - * 获取光标所在列号。 - * - * @param caretPosition 光标位置 - * @param text 文本内容 - * @return 光标所在列号 - */ - @Override - public int getColumn(int caretPosition, String text) { - return caretPosition - text.lastIndexOf("\n", caretPosition - 1); - } - - /** - * 初始化标签面板。 - */ - @Override - public void initTabPane() { - JNotepadTabPane.getInstance().getSelectionModel().selectedItemProperty().addListener((observable, oldTab, newTab) -> { - LineNumberTextArea textArea; - if (newTab != null) { - // 获取新选定的标签页并关联的文本区域 - textArea = (LineNumberTextArea) newTab.getContent(); - } else { - // 刷新状态 - textArea = openAssociatedFileAndCreateTextArea(new ArrayList<>()); - } - // 更新状态标签 - INSTANCE.updateStatusLabel(textArea); - - // 监听文本光标位置的变化,更新状态标签 - textArea.getMainTextArea().caretPositionProperty().addListener((caretObservable, oldPosition, newPosition) -> INSTANCE.updateStatusLabel(textArea)); - - // 更新编码标签 - INSTANCE.upDateEncodingLabel(textArea.getMainTextArea().getText()); - }); - } - /** * 更新UI和标签页 * @@ -249,9 +117,8 @@ public class Controller implements ControllerInterface { @Override public void updateUiWithNewTextArea(LineNumberTextArea textArea) { ViewManager viewManager = ViewManager.getInstance(); - String tabTitle = "新建文件 " + viewManager.selfIncreaseAndGetTabIndex(); + String tabTitle = NEW_FILE + viewManager.selfIncreaseAndGetTabIndex(); JNotepadTabPane.getInstance().addNewTab(new JNotepadTab(tabTitle, textArea)); - updateStatusLabel(textArea); } @@ -262,12 +129,6 @@ public class Controller implements ControllerInterface { */ private void configureTextArea(LineNumberTextArea textArea) { textArea.getMainTextArea().setWrapText(true); - upDateEncodingLabel(textArea.getMainTextArea().getText()); - updateStatusLabel(textArea); - - textArea.textProperty().addListener((observable, oldValue, newValue) -> updateStatusLabel(textArea)); - - autoSave(textArea); } /** @@ -276,12 +137,7 @@ public class Controller implements ControllerInterface { * @return 新的文本区域 */ private LineNumberTextArea createNewTextArea() { - LineNumberTextArea textArea = new LineNumberTextArea(); - textArea.setStyle( - "-fx-border-color:white;" + - "-fx-background-color:white" - ); - return textArea; + return new LineNumberTextArea(); } /** @@ -291,8 +147,8 @@ public class Controller implements ControllerInterface { * @param textArea 文本区域 * @return 新的标签页 */ - private JNotepadTab createNewTab(String tabName, LineNumberTextArea textArea) { - return new JNotepadTab(tabName, textArea); + private JNotepadTab createNewTab(String tabName, LineNumberTextArea textArea, Charset charset) { + return new JNotepadTab(tabName, textArea, charset); } /** @@ -305,7 +161,7 @@ public class Controller implements ControllerInterface { return new Task<>() { @Override protected Void call() { - upDateEncodingLabel(getText(file).getMainTextArea().getText()); + getText(file); return null; } }; diff --git a/src/main/java/org/jcnc/jnotepad/init/Config.java b/src/main/java/org/jcnc/jnotepad/init/Config.java index fa5f316..67374c0 100644 --- a/src/main/java/org/jcnc/jnotepad/init/Config.java +++ b/src/main/java/org/jcnc/jnotepad/init/Config.java @@ -1,43 +1,106 @@ package org.jcnc.jnotepad.init; -import javafx.scene.control.Alert; -import org.jcnc.jnotepad.Interface.ConfigInterface; - import java.io.*; +import java.nio.charset.StandardCharsets; import java.util.Properties; -import static org.jcnc.jnotepad.constants.AppConstants.PROPERTY_FILE_NAME; +import static org.jcnc.jnotepad.constants.AppConstants.CH_LANGUAGE_PACK_NAME; +import static org.jcnc.jnotepad.constants.AppConstants.EN_LANGUAGE_PACK_NAME; /** * @author 许轲 + * 该类负责配置文件的读取和初始化操作。 */ -public class Config implements ConfigInterface { +public class Config { + + String LANGUAGE_PACK_NAME; + + /** + * 从文件中读取属性配置。 + * + * @return 包含从文件中读取的属性的 Properties 对象。 + */ public Properties readPropertiesFromFile() { Properties properties = new Properties(); - try (InputStream inputStream = new FileInputStream(PROPERTY_FILE_NAME)) { - properties.load(inputStream); + + //设置语言包 + LANGUAGE_PACK_NAME = EN_LANGUAGE_PACK_NAME; + try (InputStream inputStream = new FileInputStream(LANGUAGE_PACK_NAME)) { + InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); // 使用 UTF-8 编码 + properties.load(reader); } catch (IOException e) { + // 如果读取出错,则调用初始化方法 initializePropertiesFile(); } return properties; } + /** + * 初始化属性配置文件。 + * 如果属性文件不存在,将创建一个新的属性文件并设置默认属性。 + */ public void initializePropertiesFile() { - Properties defaultProperties = new Properties(); - defaultProperties.setProperty("title", "JNotepad"); + Properties chLanguagePack = getCHLanguagePack(); - try (OutputStream outputStream = new FileOutputStream(PROPERTY_FILE_NAME)) { - defaultProperties.store(outputStream, "JNotepad Properties"); - } catch (IOException e) { - showErrorAlert(); + Properties enLanguagePack = getENLanguagePack(); + + try (OutputStream outputStream = new FileOutputStream(CH_LANGUAGE_PACK_NAME)) { + OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8); // 使用 UTF-8 编码 + chLanguagePack.store(writer, "JNotepad ch_language_pack"); + + } catch (IOException ignored) { + } + + try (OutputStream outputStream = new FileOutputStream(EN_LANGUAGE_PACK_NAME)) { + OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8); // 使用 UTF-8 编码 + enLanguagePack.store(writer, "JNotepad en_language_pack"); + + } catch (IOException ignored) { } } - public void showErrorAlert() { - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.setTitle("错误"); - alert.setHeaderText("文件读写错误"); - alert.setContentText("文件读写错误"); - alert.showAndWait(); + private static Properties getCHLanguagePack() { + Properties properties = new Properties(); + + properties.setProperty("TITLE", "JNotepad"); // 设置默认属性 + properties.setProperty("NEW_FILE", "新建文件"); + properties.setProperty("SAVA", "保存"); + properties.setProperty("FILE", "文件"); + properties.setProperty("NEW", "新建"); + properties.setProperty("OPEN", "打开"); + properties.setProperty("SAVA_AS", "另存为"); + properties.setProperty("SET", "设置"); + properties.setProperty("WORD_WRAP", "自动换行"); + properties.setProperty("PLUGIN", "插件"); + properties.setProperty("ADD_PLUGIN", "增加插件"); + properties.setProperty("STATISTICS", "统计字数"); + properties.setProperty("ROW", "行数"); + properties.setProperty("COLUMN", "列数"); + properties.setProperty("WORD_COUNT", "字数"); + properties.setProperty("ENCODE", "编码"); + return properties; } + + private static Properties getENLanguagePack() { + Properties properties = new Properties(); + + properties.setProperty("TITLE", "JNotepad"); + properties.setProperty("NEW_FILE", "New File"); + properties.setProperty("SAVA", "Save"); + properties.setProperty("FILE", "File"); + properties.setProperty("NEW", "New"); + properties.setProperty("OPEN", "Open"); + properties.setProperty("SAVA_AS", "Save As"); + properties.setProperty("SET", "Settings"); + properties.setProperty("WORD_WRAP", "Word Wrap"); + properties.setProperty("PLUGIN", "Plugins"); + properties.setProperty("ADD_PLUGIN", "Add Plugin"); + properties.setProperty("STATISTICS", "Word Count"); + properties.setProperty("ROW", "Row"); + properties.setProperty("COLUMN", "Column"); + properties.setProperty("WORD_COUNT", "Word Count"); + properties.setProperty("ENCODE", "Encoding"); + return properties; + } + } diff --git a/src/main/java/org/jcnc/jnotepad/tool/EncodingDetector.java b/src/main/java/org/jcnc/jnotepad/tool/EncodingDetector.java index 6da7196..9e77439 100644 --- a/src/main/java/org/jcnc/jnotepad/tool/EncodingDetector.java +++ b/src/main/java/org/jcnc/jnotepad/tool/EncodingDetector.java @@ -1,11 +1,21 @@ package org.jcnc.jnotepad.tool; +import com.ibm.icu.text.CharsetDetector; +import com.ibm.icu.text.CharsetMatch; import javafx.application.Platform; import org.jcnc.jnotepad.ui.LineNumberTextArea; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; /** * 编码检测工具类 @@ -13,67 +23,46 @@ import java.nio.charset.StandardCharsets; * @author 许轲 */ public class EncodingDetector { - private EncodingDetector() { - } - /** - * 检测 TextArea 中的文本编码 - * - * @param textArea 文本区域 - * @return 字符串表示的编码,如果检测失败则返回 "UNKNOWN" - */ - public static String detectEncoding(LineNumberTextArea textArea) { - String text = textArea.getMainTextArea().getText(); - return detectEncoding(text); + private static final Logger LOG = LoggerFactory.getLogger(EncodingDetector.class); + public static final String UNKNOWN = "UNKNOWN"; + + private EncodingDetector() { } /** * 检测文本编码 * - * @param text 要检测的文本 + * @param file 要检测的文件 * @return 字符串表示的编码,如果检测失败则返回 "UNKNOWN" */ - public static String detectEncoding(String text) { - // 尝试常见的编码 - for (Charset charset : commonCharsets()) { - if (isValidEncoding(text, charset)) { - Platform.runLater(() -> LogUtil.getLogger(EncodingDetector.class).info("编码监测结果:{}", isValidEncoding(text, charset))); - return charset.name(); + public static String detectEncoding(File file) { + CharsetDetector charsetDetector = new CharsetDetector(); + try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(file.getPath()))) { + charsetDetector.setText(inputStream); + CharsetMatch match = charsetDetector.detect(); + LOG.debug(match.getName() + " " + match.getConfidence()); + if (match.getConfidence() > 50) { + return match.getName(); } + } catch (Exception e) { + LOG.error("", e); } - return "UNKNOWN"; + return UNKNOWN; } /** - * 获取常见的字符集数组 + * 检测文本编码 * - * @return 常见字符集数组 + * @param file 文件 + * @return Charset编码 */ - private static Charset[] commonCharsets() { - return new Charset[]{ - StandardCharsets.UTF_8, - StandardCharsets.UTF_16, - StandardCharsets.UTF_16LE, - StandardCharsets.UTF_16BE, - StandardCharsets.ISO_8859_1 - }; + public static Charset detectEncodingCharset(File file) { + String charset = detectEncoding(file); + if (charset.equals(UNKNOWN)) { + return StandardCharsets.UTF_8; + } + return Charset.forName(charset); } - - /** - * 检查指定编码是否能够正确解码文本 - * - * @param text 要检测的文本 - * @param encoding 要尝试的编码 - * @return 如果指定编码能够正确解码文本,则返回 true,否则返回 false - */ - private static boolean isValidEncoding(String text, Charset encoding) { - // 尝试使用指定编码解码 - byte[] bytes = text.getBytes(encoding); - String decoded = new String(bytes, encoding); - - // 解码后的文本相同表示编码有效 - return text.equals(decoded); - } - } \ No newline at end of file diff --git a/src/main/java/org/jcnc/jnotepad/tool/FileUtil.java b/src/main/java/org/jcnc/jnotepad/tool/FileUtil.java index cdd2a0c..6895f9f 100644 --- a/src/main/java/org/jcnc/jnotepad/tool/FileUtil.java +++ b/src/main/java/org/jcnc/jnotepad/tool/FileUtil.java @@ -3,6 +3,7 @@ package org.jcnc.jnotepad.tool; import javafx.scene.control.Tab; import javafx.stage.FileChooser; import org.jcnc.jnotepad.ui.LineNumberTextArea; +import org.jcnc.jnotepad.ui.tab.JNotepadTab; import org.jcnc.jnotepad.ui.tab.JNotepadTabPane; import java.io.*; @@ -49,7 +50,7 @@ public class FileUtil { * @see LogUtil */ public static void saveTab(Class currentClass) { - Tab selectedTab = JNotepadTabPane.getInstance().getSelected(); + JNotepadTab selectedTab = JNotepadTabPane.getInstance().getSelected(); if (selectedTab != null) { // 创建一个文件窗口 FileChooser fileChooser = new FileChooser(); @@ -59,24 +60,13 @@ public class FileUtil { fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("文本文档", "*.txt")); File file = fileChooser.showSaveDialog(null); if (file != null) { - try ( - BufferedWriter writer = new BufferedWriter(new FileWriter(file)) - ) { - // 获取当前Tab页的文本编辑区 - LineNumberTextArea textArea = (LineNumberTextArea) selectedTab.getContent(); - // 将保存后的文件设置为已关联 - textArea.setRelevance(true); - String text = textArea.getMainTextArea().getText(); - // 写入文件内容 - writer.write(text); - writer.flush(); - // 更新Tab页标签上的文件名 - selectedTab.setText(file.getName()); - // 将文件对象保存到Tab页的UserData中 - selectedTab.setUserData(file); - } catch (IOException ignored) { - LogUtil.getLogger(currentClass).info("已忽视IO异常!"); - } + selectedTab.save(); + // 将保存后的文件设置为已关联 + selectedTab.getLineNumberTextArea().setRelevance(true); + // 更新Tab页标签上的文件名 + selectedTab.setText(file.getName()); + // 将文件对象保存到Tab页的UserData中 + selectedTab.setUserData(file); } } } diff --git a/src/main/java/org/jcnc/jnotepad/ui/LineNumberTextArea.java b/src/main/java/org/jcnc/jnotepad/ui/LineNumberTextArea.java index 583ba2a..9008a0f 100644 --- a/src/main/java/org/jcnc/jnotepad/ui/LineNumberTextArea.java +++ b/src/main/java/org/jcnc/jnotepad/ui/LineNumberTextArea.java @@ -1,8 +1,18 @@ package org.jcnc.jnotepad.ui; import javafx.beans.property.StringProperty; +import javafx.scene.control.Tab; import javafx.scene.control.TextArea; import javafx.scene.layout.BorderPane; +import org.jcnc.jnotepad.tool.LogUtil; +import org.jcnc.jnotepad.ui.status.JNotepadStatusBox; +import org.jcnc.jnotepad.ui.tab.JNotepadTab; +import org.jcnc.jnotepad.ui.tab.JNotepadTabPane; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; /** * @author 许轲 @@ -28,16 +38,50 @@ public class LineNumberTextArea extends BorderPane { // 设定自定义样式 lineNumberArea.getStyleClass().add("text-line-number"); mainTextArea.getStyleClass().add("main-text-area"); - lineNumberArea.textProperty().addListener((observable, oldValue, newValue) -> updateLineNumberWidth()); - mainTextArea.textProperty().addListener((observable, oldValue, newValue) -> updateLineNumberArea()); + this.setStyle( + "-fx-border-color:white;" + + "-fx-background-color:white" + ); + setCenter(mainTextArea); + setLeft(lineNumberArea); + initListeners(); + } + + private void initListeners() { // 当主要文本区域的垂直滚动位置发生变化时,使行号文本区域的滚动位置保持一致 mainTextArea.scrollTopProperty().addListener((observable, oldValue, newValue) -> lineNumberArea.setScrollTop(mainTextArea.getScrollTop())); // 当行号文本区域的垂直滚动位置发生变化时,使主要文本区域的滚动位置保持一致 lineNumberArea.scrollTopProperty().addListener((observable, oldValue, newValue) -> mainTextArea.setScrollTop(lineNumberArea.getScrollTop())); - setCenter(mainTextArea); - setLeft(lineNumberArea); + lineNumberArea.textProperty().addListener((observable, oldValue, newValue) -> updateLineNumberWidth()); + + this.mainTextArea.caretPositionProperty().addListener((caretObservable, oldPosition, newPosition) -> JNotepadStatusBox.getInstance().updateWordCountStatusLabel()); + this.textProperty().addListener((observable, oldValue, newValue) -> { + // 更新行号 + updateLineNumberArea(); + // 更新状态栏 + JNotepadStatusBox.getInstance().updateWordCountStatusLabel(); + // 自动保存 + save(); + }); + } + + /** + * 以原文件编码格式写回文件 + */ + public void save() { + JNotepadTab tab = JNotepadTabPane.getInstance().getSelected(); + File file = (File) tab.getUserData(); + String newValue = this.mainTextArea.getText(); + if (file != null) { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(file, tab.getCharset()))) { + writer.write(newValue); + LogUtil.getLogger(this.getClass()).info("正在自动保存---"); + } catch (IOException ignored) { + LogUtil.getLogger(this.getClass()).info("已忽视IO异常!"); + } + } } public boolean isRelevance() { @@ -91,5 +135,6 @@ public class LineNumberTextArea extends BorderPane { public TextArea getMainTextArea() { return mainTextArea; } + } diff --git a/src/main/java/org/jcnc/jnotepad/ui/menu/JNotepadMenuBar.java b/src/main/java/org/jcnc/jnotepad/ui/menu/JNotepadMenuBar.java index a0ea7c6..07a6917 100644 --- a/src/main/java/org/jcnc/jnotepad/ui/menu/JNotepadMenuBar.java +++ b/src/main/java/org/jcnc/jnotepad/ui/menu/JNotepadMenuBar.java @@ -6,11 +6,13 @@ import javafx.scene.control.MenuBar; import javafx.scene.control.MenuItem; import org.jcnc.jnotepad.app.config.GlobalConfig; import org.jcnc.jnotepad.controller.event.handler.*; +import org.jcnc.jnotepad.init.Config; import org.jcnc.jnotepad.ui.tab.JNotepadTab; import org.jcnc.jnotepad.ui.tab.JNotepadTabPane; import java.util.HashMap; import java.util.Map; +import java.util.Properties; /** * 封装菜单栏组件。 @@ -19,6 +21,24 @@ import java.util.Map; */ public class JNotepadMenuBar extends MenuBar { + Config config = new Config(); + Properties properties = config.readPropertiesFromFile(); + String SAVA = properties.getProperty("SAVA"); + String FILE = properties.getProperty("FILE"); + String NEW = properties.getProperty("NEW"); + String OPEN = properties.getProperty("OPEN"); + String SAVA_AS = properties.getProperty("SAVA_AS"); + + String SET = properties.getProperty("SET"); + + String WORD_WRAP = properties.getProperty("WORD_WRAP"); + + String PLUGIN = properties.getProperty("PLUGIN"); + + String ADD_PLUGIN = properties.getProperty("ADD_PLUGIN"); + + String STATISTICS = properties.getProperty("STATISTICS"); + private static final JNotepadMenuBar MENU_BAR = new JNotepadMenuBar(); private JNotepadMenuBar() { @@ -90,18 +110,18 @@ public class JNotepadMenuBar extends MenuBar { */ private void initFileMenu() { // 文件菜单 - fileMenu = new Menu("文件"); + fileMenu = new Menu(FILE); - newItem = new MenuItem("新建"); + newItem = new MenuItem(NEW); itemMap.put("newItem", newItem); - openItem = new MenuItem("打开"); + openItem = new MenuItem(OPEN); itemMap.put("openItem", openItem); - saveItem = new MenuItem("保存"); + saveItem = new MenuItem(SAVA); itemMap.put("saveItem", saveItem); - saveAsItem = new MenuItem("另存为"); + saveAsItem = new MenuItem(SAVA_AS); itemMap.put("saveAsItem", saveAsItem); fileMenu.getItems().addAll(newItem, openItem, saveItem, saveAsItem); @@ -112,9 +132,9 @@ public class JNotepadMenuBar extends MenuBar { */ private void initSettingMenu() { // 设置菜单 - setMenu = new Menu("设置"); + setMenu = new Menu(SET); - lineFeedItem = new CheckMenuItem("自动换行"); + lineFeedItem = new CheckMenuItem(WORD_WRAP); itemMap.put("lineFeedItem", lineFeedItem); lineFeedItem.selectedProperty().set(true); @@ -126,11 +146,11 @@ public class JNotepadMenuBar extends MenuBar { */ private void initPluginMenu() { // 插件菜单 - pluginMenu = new Menu("插件"); - addItem = new MenuItem("增加插件"); + pluginMenu = new Menu(PLUGIN); + addItem = new MenuItem(ADD_PLUGIN); itemMap.put("addItem", addItem); - countItem = new MenuItem("统计字数"); + countItem = new MenuItem(STATISTICS); itemMap.put("countItem", countItem); pluginMenu.getItems().addAll(addItem, countItem); @@ -148,7 +168,6 @@ public class JNotepadMenuBar extends MenuBar { openItem.setOnAction(new OpenFile()); saveItem.setOnAction(new SaveFile()); saveAsItem.setOnAction(new SaveAsFile()); - lineFeedItem.setOnAction(new LineFeed()); lineFeedItem.selectedProperty().addListener((observableValue, before, after) -> { // 1. 更新全局配置 GlobalConfig.getConfig().setAutoLineConfig(after); diff --git a/src/main/java/org/jcnc/jnotepad/ui/status/JNotepadStatusBox.java b/src/main/java/org/jcnc/jnotepad/ui/status/JNotepadStatusBox.java new file mode 100644 index 0000000..1de1f9a --- /dev/null +++ b/src/main/java/org/jcnc/jnotepad/ui/status/JNotepadStatusBox.java @@ -0,0 +1,128 @@ +package org.jcnc.jnotepad.ui.status; + +import javafx.geometry.Insets; +import javafx.scene.control.Label; +import javafx.scene.control.TextArea; +import javafx.scene.layout.HBox; +import org.jcnc.jnotepad.init.Config; +import org.jcnc.jnotepad.ui.tab.JNotepadTabPane; + +import java.nio.charset.Charset; +import java.util.Properties; + +/** + * 状态栏组件封装。 + * 1. 文字统计 + * 2. 编码 + * + * @author songdragon + */ +public class JNotepadStatusBox extends HBox { + + Config config = new Config(); + Properties properties = config.readPropertiesFromFile(); + String ROW = properties.getProperty("ROW"); + + String COLUMN = properties.getProperty("COLUMN"); + + String WORD_COUNT = properties.getProperty("WORD_COUNT"); + + String ENCODE = properties.getProperty("ENCODE"); + + private static final JNotepadStatusBox STATUS_BOX = new JNotepadStatusBox(); + + /** + * 字数统计及光标 + */ + private final Label statusLabel; + + /** + * 显示文本编码 + */ + private final Label enCodingLabel; + + private JNotepadStatusBox() { + // 创建状态栏 + statusLabel = new Label(ROW + ":1 \t" + COLUMN + ":1 \t" + WORD_COUNT + ":0 "); + // 创建新的标签以显示编码信息 + enCodingLabel = new Label(); + + this.getChildren().add(statusLabel); + this.getChildren().add(enCodingLabel); + this.getProperties().put("borderpane-margin", new Insets(5, 10, 5, 10)); + + } + + public static JNotepadStatusBox getInstance() { + return STATUS_BOX; + } + + public void updateEncodingLabel() { + updateEncodingLabel(null); + } + + /** + * 更新编码展示 + * + * @param encoding 文件编码 + */ + public void updateEncodingLabel(String encoding) { + if (encoding == null) { + encoding = Charset.defaultCharset().name(); + } + this.enCodingLabel.setText("\t" + ENCODE + ": " + encoding); + } + + /** + * 更新字数统计 + */ + public void updateWordCountStatusLabel() { + TextArea textArea = JNotepadTabPane.getInstance().getSelected().getLineNumberTextArea().getMainTextArea(); + int caretPosition = textArea.getCaretPosition(); + int row = getRow(caretPosition, textArea.getText()); + int column = getColumn(caretPosition, textArea.getText()); + int length = textArea.getLength(); + this.statusLabel.setText(ROW + ": " + row + " \t" + COLUMN + ": " + column + " \t" + WORD_COUNT + ": " + length); + } + + /** + * Tab选中时,更新状态栏 + * 1. 状态栏更新当前选中tab的数字统计 + * 2. 状态栏更新当前选中tab的字符编码 + */ + public void updateWhenTabSelected() { + updateWordCountStatusLabel(); + updateEncodingLabel(JNotepadTabPane.getInstance().getSelected().getCharset().name()); + } + + /** + * 获取光标所在行号。 + * + * @param caretPosition 光标位置 + * @param text 文本内容 + * @return 光标所在行号 + */ + public int getRow(int caretPosition, String text) { + caretPosition = Math.min(caretPosition, text.length()); + String substring = text.substring(0, caretPosition); + int count = 0; + for (char c : substring.toCharArray()) { + if (c == '\n') { + count++; + } + } + return count + 1; + } + + /** + * 获取光标所在列号。 + * + * @param caretPosition 光标位置 + * @param text 文本内容 + * @return 光标所在列号 + */ + public int getColumn(int caretPosition, String text) { + return caretPosition - text.lastIndexOf("\n", caretPosition - 1); + } + +} diff --git a/src/main/java/org/jcnc/jnotepad/ui/tab/JNotepadTab.java b/src/main/java/org/jcnc/jnotepad/ui/tab/JNotepadTab.java index 4dfbc50..5c41adf 100644 --- a/src/main/java/org/jcnc/jnotepad/ui/tab/JNotepadTab.java +++ b/src/main/java/org/jcnc/jnotepad/ui/tab/JNotepadTab.java @@ -4,6 +4,8 @@ import javafx.scene.control.Tab; import org.jcnc.jnotepad.app.config.GlobalConfig; import org.jcnc.jnotepad.ui.LineNumberTextArea; +import java.nio.charset.Charset; + /** * 封装标签页组件,增加属于标签页的属性,例如:自动换行开关。 * 每个Tab关联一个LineNumberTextArea。 @@ -17,16 +19,22 @@ public class JNotepadTab extends Tab { */ private boolean autoLine = false; private final LineNumberTextArea lineNumberTextArea; + private Charset charset = Charset.defaultCharset(); public JNotepadTab(String tabTitle) { this(tabTitle, new LineNumberTextArea()); } public JNotepadTab(String tabTitle, LineNumberTextArea textArea) { + this(tabTitle, textArea, Charset.defaultCharset()); + } + + public JNotepadTab(String tabTitle, LineNumberTextArea textArea, Charset charset) { super(tabTitle); lineNumberTextArea = textArea; this.setContent(lineNumberTextArea); setAutoLine(GlobalConfig.getConfig().getAutoLineConfig()); + this.charset = charset; } public boolean isAutoLine() { @@ -41,4 +49,16 @@ public class JNotepadTab extends Tab { public LineNumberTextArea getLineNumberTextArea() { return lineNumberTextArea; } + + public Charset getCharset() { + return charset; + } + + public void setCharset(Charset charset) { + this.charset = charset; + } + + public void save() { + this.lineNumberTextArea.save(); + } } diff --git a/src/main/java/org/jcnc/jnotepad/ui/tab/JNotepadTabPane.java b/src/main/java/org/jcnc/jnotepad/ui/tab/JNotepadTabPane.java index ca98c9b..c87cedb 100644 --- a/src/main/java/org/jcnc/jnotepad/ui/tab/JNotepadTabPane.java +++ b/src/main/java/org/jcnc/jnotepad/ui/tab/JNotepadTabPane.java @@ -3,6 +3,7 @@ package org.jcnc.jnotepad.ui.tab; import javafx.scene.control.TabPane; import org.jcnc.jnotepad.app.config.GlobalConfig; import org.jcnc.jnotepad.ui.menu.JNotepadMenuBar; +import org.jcnc.jnotepad.ui.status.JNotepadStatusBox; /** * 标签页布局组件封装。 @@ -25,8 +26,11 @@ public class JNotepadTabPane extends TabPane { this.getSelectionModel().selectedItemProperty().addListener( (ov, from, to) -> { if (to != null) { + // 更新菜单栏中与tab相关设置 JNotepadMenuBar.getMenuBar().updateMenuStatusBySelectedTab(); } + // 更新状态标签 + JNotepadStatusBox.getInstance().updateWhenTabSelected(); } ); } @@ -65,5 +69,6 @@ public class JNotepadTabPane extends TabPane { public void fireTabSelected() { JNotepadTab selectedTab = getSelected(); selectedTab.setAutoLine(GlobalConfig.getConfig().getAutoLineConfig()); + JNotepadStatusBox.getInstance().updateWhenTabSelected(); } } diff --git a/src/main/java/org/jcnc/jnotepad/view/init/View.java b/src/main/java/org/jcnc/jnotepad/view/init/View.java index 7055ffe..82abcdf 100644 --- a/src/main/java/org/jcnc/jnotepad/view/init/View.java +++ b/src/main/java/org/jcnc/jnotepad/view/init/View.java @@ -1,6 +1,5 @@ package org.jcnc.jnotepad.view.init; -import org.jcnc.jnotepad.controller.manager.Controller; import org.jcnc.jnotepad.controller.manager.ShortcutKey; @@ -9,10 +8,6 @@ import org.jcnc.jnotepad.controller.manager.ShortcutKey; */ public class View { - public void initTabPane() { - Controller.getInstance().initTabPane(); - } - // 初始化快捷键 public void initShortcutKey() { new ShortcutKey().createShortcutKeyByConfig(); diff --git a/src/main/java/org/jcnc/jnotepad/view/manager/ViewManager.java b/src/main/java/org/jcnc/jnotepad/view/manager/ViewManager.java index af87eb0..846d1d4 100644 --- a/src/main/java/org/jcnc/jnotepad/view/manager/ViewManager.java +++ b/src/main/java/org/jcnc/jnotepad/view/manager/ViewManager.java @@ -7,6 +7,7 @@ import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import org.jcnc.jnotepad.exception.AppException; import org.jcnc.jnotepad.ui.menu.JNotepadMenuBar; +import org.jcnc.jnotepad.ui.status.JNotepadStatusBox; import org.jcnc.jnotepad.ui.tab.JNotepadTabPane; @@ -17,11 +18,6 @@ import org.jcnc.jnotepad.ui.tab.JNotepadTabPane; */ public class ViewManager { - /** - * 显示文本编码 - */ - private Label enCodingLabel; // 显示文本编码 - private int tabIndex = 0; private Boolean line = true; @@ -30,19 +26,13 @@ public class ViewManager { // 主界面布局 private BorderPane root; // 主布局 - // 状态栏 - private Label statusLabel; private static ViewManager instance = null; - public Label getEnCodingLabel() { - return enCodingLabel; - } /** * 自增并获取标签页索引 * - * * @return int 标签页索引 * @apiNote ++tabIndex */ @@ -59,10 +49,6 @@ public class ViewManager { return root; } - public Label getStatusLabel() { - return statusLabel; - } - /** * 获取ViewManager的实例。如果实例不存在,则创建一个新实例。 @@ -109,14 +95,7 @@ public class ViewManager { // 创建标签页和文本编辑区域 root.setCenter(JNotepadTabPane.getInstance()); - - // 创建状态栏 - statusLabel = new Label("行数:1 \t列数:1 \t字数:0 "); - - enCodingLabel = new Label(); // 创建新的标签以显示编码信息 - HBox statusBox = new HBox(statusLabel, enCodingLabel); // 使用HBox放置状态标签和编码标签 - root.setBottom(statusBox); - BorderPane.setMargin(statusBox, new Insets(5, 10, 5, 10)); + root.setBottom(JNotepadStatusBox.getInstance()); scene.setRoot(root); }