diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index ac75d3f..353c159 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -30,7 +30,7 @@ module org.jcnc.jnotepad { exports org.jcnc.jnotepad.controller.i18n; exports org.jcnc.jnotepad.controller.event.handler.setting; exports org.jcnc.jnotepad.controller.event.handler.menubar; - exports org.jcnc.jnotepad.util; + exports org.jcnc.jnotepad.common.util; exports org.jcnc.jnotepad.common.interfaces; opens org.jcnc.jnotepad.app.config; exports org.jcnc.jnotepad.plugin.interfaces; diff --git a/src/main/java/org/jcnc/jnotepad/app/manager/ApplicationManager.java b/src/main/java/org/jcnc/jnotepad/app/manager/ApplicationManager.java index b6f39e6..67176e3 100644 --- a/src/main/java/org/jcnc/jnotepad/app/manager/ApplicationManager.java +++ b/src/main/java/org/jcnc/jnotepad/app/manager/ApplicationManager.java @@ -11,13 +11,13 @@ import org.jcnc.jnotepad.app.i18n.UiResourceBundle; import org.jcnc.jnotepad.common.constants.AppConstants; import org.jcnc.jnotepad.common.constants.TextConstants; import org.jcnc.jnotepad.common.manager.ThreadPoolManager; +import org.jcnc.jnotepad.common.util.UiUtil; import org.jcnc.jnotepad.controller.ResourceController; import org.jcnc.jnotepad.controller.cache.CacheController; import org.jcnc.jnotepad.controller.config.AppConfigController; import org.jcnc.jnotepad.controller.config.PluginConfigController; import org.jcnc.jnotepad.controller.manager.Controller; import org.jcnc.jnotepad.plugin.manager.PluginManager; -import org.jcnc.jnotepad.util.UiUtil; import org.jcnc.jnotepad.views.manager.*; import java.util.List; diff --git a/src/main/java/org/jcnc/jnotepad/app/util/ApplicationRestarter.java b/src/main/java/org/jcnc/jnotepad/app/util/ApplicationRestarter.java index 0794af8..7f22075 100644 --- a/src/main/java/org/jcnc/jnotepad/app/util/ApplicationRestarter.java +++ b/src/main/java/org/jcnc/jnotepad/app/util/ApplicationRestarter.java @@ -1,7 +1,7 @@ package org.jcnc.jnotepad.app.util; import org.jcnc.jnotepad.LunchApp; -import org.jcnc.jnotepad.util.LogUtil; +import org.jcnc.jnotepad.common.util.LogUtil; import java.io.IOException; diff --git a/src/main/java/org/jcnc/jnotepad/common/manager/AbstractCacheManager.java b/src/main/java/org/jcnc/jnotepad/common/manager/AbstractCacheManager.java index 9a77a0b..5c176c6 100644 --- a/src/main/java/org/jcnc/jnotepad/common/manager/AbstractCacheManager.java +++ b/src/main/java/org/jcnc/jnotepad/common/manager/AbstractCacheManager.java @@ -42,14 +42,18 @@ public abstract class AbstractCacheManager { * @return 缓存集合 */ - public abstract Map getCaches(); + public Map getCaches() { + return caches; + } /** * 设置缓存集合 * * @param caches 缓存集合 */ - public abstract void setCaches(Map caches); + public void setCaches(Map caches) { + this.caches = caches; + } /** * 添加缓存 @@ -97,11 +101,12 @@ public abstract class AbstractCacheManager { /** * 获取缓存数据 * - * @param cacheKey 缓存key + * @param group 组 + * @param name 缓存名 * @return 缓存类 */ - public Object getCacheData(String cacheKey) { - Cache cache = getCache(cacheKey); + public Object getCacheData(String group, String name) { + Cache cache = getCache(group, name); if (cache == null) { return null; } diff --git a/src/main/java/org/jcnc/jnotepad/common/manager/ApplicationCacheManager.java b/src/main/java/org/jcnc/jnotepad/common/manager/ApplicationCacheManager.java index 65161db..69282b0 100644 --- a/src/main/java/org/jcnc/jnotepad/common/manager/ApplicationCacheManager.java +++ b/src/main/java/org/jcnc/jnotepad/common/manager/ApplicationCacheManager.java @@ -1,9 +1,5 @@ package org.jcnc.jnotepad.common.manager; -import org.jcnc.jnotepad.model.entity.Cache; - -import java.util.Map; - /** * 应用程序缓存管理类 * @@ -21,16 +17,6 @@ public class ApplicationCacheManager extends AbstractCacheManager { return INSTANCE; } - @Override - public Map getCaches() { - return caches; - } - - @Override - public void setCaches(Map caches) { - this.caches = caches; - } - @Override public String getGlobalNamespace() { return "jcnc"; diff --git a/src/main/java/org/jcnc/jnotepad/common/manager/ThreadPoolManager.java b/src/main/java/org/jcnc/jnotepad/common/manager/ThreadPoolManager.java index 709e7c8..ffe01c0 100644 --- a/src/main/java/org/jcnc/jnotepad/common/manager/ThreadPoolManager.java +++ b/src/main/java/org/jcnc/jnotepad/common/manager/ThreadPoolManager.java @@ -1,6 +1,6 @@ package org.jcnc.jnotepad.common.manager; -import org.jcnc.jnotepad.util.LogUtil; +import org.jcnc.jnotepad.common.util.LogUtil; import org.slf4j.Logger; import java.util.concurrent.*; diff --git a/src/main/java/org/jcnc/jnotepad/util/EncodingDetector.java b/src/main/java/org/jcnc/jnotepad/common/util/EncodingDetector.java similarity index 98% rename from src/main/java/org/jcnc/jnotepad/util/EncodingDetector.java rename to src/main/java/org/jcnc/jnotepad/common/util/EncodingDetector.java index 9511288..8bdf43b 100644 --- a/src/main/java/org/jcnc/jnotepad/util/EncodingDetector.java +++ b/src/main/java/org/jcnc/jnotepad/common/util/EncodingDetector.java @@ -1,4 +1,4 @@ -package org.jcnc.jnotepad.util; +package org.jcnc.jnotepad.common.util; import com.ibm.icu.text.CharsetDetector; import com.ibm.icu.text.CharsetMatch; diff --git a/src/main/java/org/jcnc/jnotepad/common/util/FileUtil.java b/src/main/java/org/jcnc/jnotepad/common/util/FileUtil.java new file mode 100644 index 0000000..e78bed3 --- /dev/null +++ b/src/main/java/org/jcnc/jnotepad/common/util/FileUtil.java @@ -0,0 +1,129 @@ +package org.jcnc.jnotepad.common.util; + +import org.jcnc.jnotepad.controller.event.handler.menubar.OpenFile; +import org.jcnc.jnotepad.exception.AppException; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.charset.Charset; +import java.nio.file.Path; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * 文件工具 + * + * @author gewuyou + */ +public class FileUtil { + private static final MessageDigest MESSAGE_DIGEST_SHA_256; + private static final int BUFFER_SIZE = 8192; + + static { + try { + MESSAGE_DIGEST_SHA_256 = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + throw new AppException(e); + } + } + + private FileUtil() { + + } + + /** + * 将字节数组转换为String类型哈希值 + * + * @param bytes 字节数组 + * @return 哈希值 + */ + private static String bytes2HashCode(byte[] bytes) { + StringBuilder hashString = new StringBuilder(); + for (byte b : bytes) { + hashString.append(String.format("%02x", b)); + } + return hashString.toString(); + } + + + /** + * 获取本地文件Sha256哈希值字符串 + * + * @param file 本地文件 + * @return 本地文件Sha256哈希值 + */ + public static String getLocalFileSha256HashString(File file) { + try ( + // 获取文件输入流 + FileInputStream fileInputStream = new FileInputStream(file); + // 获取字节流通道 + FileChannel channel = fileInputStream.getChannel() + ) { + // 设置8k缓冲区 + ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); + while (channel.read(buffer) != -1) { + buffer.flip(); + MESSAGE_DIGEST_SHA_256.update(buffer); + buffer.clear(); + } + } catch (IOException e) { + throw new AppException(e); + } + return bytes2HashCode(MESSAGE_DIGEST_SHA_256.digest()); + } + + /** + * 获取本地文件Sha256哈希值字符串 + * + * @param pathStr 本地文件路径字符串 + * @return 本地文件Sha256哈希值 + */ + public static String getLocalFileSha256HashString(String pathStr) { + return getLocalFileSha256HashString(new File(pathStr)); + } + + /** + * 获取本地文件Sha256哈希值字符串 + * + * @param path 本地文件路径 + * @return 本地文件Sha256哈希值 + */ + public static String getLocalFileSha256HashString(Path path) { + return getLocalFileSha256HashString(path.toFile()); + } + + /** + * 获取文件中的文本内容。 + * + * @param file 文件对象 + * @return 文本内容 + */ + public static String getFileText(File file) { + return getFileText(file, EncodingDetector.detectEncodingCharset(file)); + } + + + /** + * 获取文件中的文本内容。 + * + * @param file 文件对象 + * @param encoding 文件编码 + * @return 文本内容 + */ + public static String getFileText(File file, Charset encoding) { + StringBuilder stringBuilder = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new FileReader(file, encoding))) { + String line; + while ((line = reader.readLine()) != null) { + if (!stringBuilder.isEmpty()) { + stringBuilder.append("\n"); + } + stringBuilder.append(line); + } + } catch (IOException ignored) { + LogUtil.getLogger(OpenFile.class).info("已忽视IO异常!"); + } + return stringBuilder.toString(); + } +} diff --git a/src/main/java/org/jcnc/jnotepad/util/JsonUtil.java b/src/main/java/org/jcnc/jnotepad/common/util/JsonUtil.java similarity index 98% rename from src/main/java/org/jcnc/jnotepad/util/JsonUtil.java rename to src/main/java/org/jcnc/jnotepad/common/util/JsonUtil.java index a83f6ee..ee21c6c 100644 --- a/src/main/java/org/jcnc/jnotepad/util/JsonUtil.java +++ b/src/main/java/org/jcnc/jnotepad/common/util/JsonUtil.java @@ -1,4 +1,4 @@ -package org.jcnc.jnotepad.util; +package org.jcnc.jnotepad.common.util; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; diff --git a/src/main/java/org/jcnc/jnotepad/util/LogUtil.java b/src/main/java/org/jcnc/jnotepad/common/util/LogUtil.java similarity index 95% rename from src/main/java/org/jcnc/jnotepad/util/LogUtil.java rename to src/main/java/org/jcnc/jnotepad/common/util/LogUtil.java index 34eb0d4..3359952 100644 --- a/src/main/java/org/jcnc/jnotepad/util/LogUtil.java +++ b/src/main/java/org/jcnc/jnotepad/common/util/LogUtil.java @@ -1,4 +1,4 @@ -package org.jcnc.jnotepad.util; +package org.jcnc.jnotepad.common.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/jcnc/jnotepad/util/PopUpUtil.java b/src/main/java/org/jcnc/jnotepad/common/util/PopUpUtil.java similarity index 81% rename from src/main/java/org/jcnc/jnotepad/util/PopUpUtil.java rename to src/main/java/org/jcnc/jnotepad/common/util/PopUpUtil.java index b329514..51fce4d 100644 --- a/src/main/java/org/jcnc/jnotepad/util/PopUpUtil.java +++ b/src/main/java/org/jcnc/jnotepad/common/util/PopUpUtil.java @@ -1,4 +1,4 @@ -package org.jcnc.jnotepad.util; +package org.jcnc.jnotepad.common.util; import org.jcnc.jnotepad.model.enums.DialogType; import org.jcnc.jnotepad.ui.dialog.AppDialogBuilder; @@ -110,6 +110,32 @@ public class PopUpUtil { .build().showAndWait(); } + /** + * 设置疑问弹窗 + * + * @param title 弹窗标题 + * @param headerText 头文本 + * @param message 消息文本 + * @param leftBtnAction 左侧按钮点击事件 + * @param rightBtnAction 右侧按钮点击事件 + * @apiNote + * @since 2023/9/3 11:54 + */ + public static void questionAlert( + String title, String headerText, String message, + DialogButtonAction leftBtnAction, DialogButtonAction rightBtnAction, String leftBtnText, String rightBtnText) { + getCustomDialog() + .setDialogType(DialogType.QUESTION) + .setTitle(title) + .setHeaderText(headerText) + .setCustomText(message) + .setLeftBtnAction(leftBtnAction) + .setRightBtnAction(rightBtnAction) + .setLeftBtnText(leftBtnText) + .setRightBtnText(rightBtnText) + .build().showAndWait(); + } + public static void successAlert( String title, String headerText, String message, DialogButtonAction leftBtnAction, DialogButtonAction rightBtnAction) { diff --git a/src/main/java/org/jcnc/jnotepad/util/UiUtil.java b/src/main/java/org/jcnc/jnotepad/common/util/UiUtil.java similarity index 98% rename from src/main/java/org/jcnc/jnotepad/util/UiUtil.java rename to src/main/java/org/jcnc/jnotepad/common/util/UiUtil.java index 250cc33..6ccbe97 100644 --- a/src/main/java/org/jcnc/jnotepad/util/UiUtil.java +++ b/src/main/java/org/jcnc/jnotepad/common/util/UiUtil.java @@ -1,4 +1,4 @@ -package org.jcnc.jnotepad.util; +package org.jcnc.jnotepad.common.util; import atlantafx.base.theme.Styles; import javafx.scene.image.Image; diff --git a/src/main/java/org/jcnc/jnotepad/controller/ResourceController.java b/src/main/java/org/jcnc/jnotepad/controller/ResourceController.java index f48d6f6..ba4a70c 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/ResourceController.java +++ b/src/main/java/org/jcnc/jnotepad/controller/ResourceController.java @@ -1,10 +1,10 @@ package org.jcnc.jnotepad.controller; +import org.jcnc.jnotepad.common.util.LogUtil; import org.jcnc.jnotepad.controller.config.PluginConfigController; import org.jcnc.jnotepad.controller.i18n.LocalizationController; import org.jcnc.jnotepad.exception.AppException; import org.jcnc.jnotepad.plugin.PluginLoader; -import org.jcnc.jnotepad.util.LogUtil; import org.slf4j.Logger; import java.io.IOException; diff --git a/src/main/java/org/jcnc/jnotepad/controller/cache/CacheController.java b/src/main/java/org/jcnc/jnotepad/controller/cache/CacheController.java index 3cbd792..3f9f87d 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/cache/CacheController.java +++ b/src/main/java/org/jcnc/jnotepad/controller/cache/CacheController.java @@ -2,10 +2,10 @@ package org.jcnc.jnotepad.controller.cache; import com.fasterxml.jackson.core.type.TypeReference; import org.jcnc.jnotepad.common.manager.ApplicationCacheManager; +import org.jcnc.jnotepad.common.util.JsonUtil; +import org.jcnc.jnotepad.common.util.LogUtil; import org.jcnc.jnotepad.exception.AppException; import org.jcnc.jnotepad.model.entity.Cache; -import org.jcnc.jnotepad.util.JsonUtil; -import org.jcnc.jnotepad.util.LogUtil; import org.slf4j.Logger; import java.io.File; diff --git a/src/main/java/org/jcnc/jnotepad/controller/config/BaseConfigController.java b/src/main/java/org/jcnc/jnotepad/controller/config/BaseConfigController.java index 134ded9..b640d96 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/config/BaseConfigController.java +++ b/src/main/java/org/jcnc/jnotepad/controller/config/BaseConfigController.java @@ -1,10 +1,10 @@ package org.jcnc.jnotepad.controller.config; +import org.jcnc.jnotepad.common.util.JsonUtil; +import org.jcnc.jnotepad.common.util.LogUtil; +import org.jcnc.jnotepad.common.util.PopUpUtil; import org.jcnc.jnotepad.controller.interfaces.ConfigController; import org.jcnc.jnotepad.exception.AppException; -import org.jcnc.jnotepad.util.JsonUtil; -import org.jcnc.jnotepad.util.LogUtil; -import org.jcnc.jnotepad.util.PopUpUtil; import org.slf4j.Logger; import java.io.BufferedWriter; diff --git a/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/OpenConfig.java b/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/OpenConfig.java index 89e179d..0f02c63 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/OpenConfig.java +++ b/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/OpenConfig.java @@ -1,8 +1,8 @@ package org.jcnc.jnotepad.controller.event.handler.menubar; import javafx.event.ActionEvent; +import org.jcnc.jnotepad.common.util.LogUtil; import org.jcnc.jnotepad.controller.config.AppConfigController; -import org.jcnc.jnotepad.util.LogUtil; import java.io.File; diff --git a/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/OpenFile.java b/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/OpenFile.java index 9e25d9e..6c419d8 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/OpenFile.java +++ b/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/OpenFile.java @@ -7,23 +7,22 @@ import javafx.stage.FileChooser; import org.jcnc.jnotepad.app.i18n.UiResourceBundle; import org.jcnc.jnotepad.common.constants.TextConstants; import org.jcnc.jnotepad.common.manager.ApplicationCacheManager; +import org.jcnc.jnotepad.common.util.EncodingDetector; +import org.jcnc.jnotepad.common.util.LogUtil; +import org.jcnc.jnotepad.common.util.UiUtil; import org.jcnc.jnotepad.model.entity.Cache; import org.jcnc.jnotepad.model.enums.CacheExpirationTime; import org.jcnc.jnotepad.ui.dialog.factory.impl.BasicFileChooserFactory; import org.jcnc.jnotepad.ui.module.LineNumberTextArea; -import org.jcnc.jnotepad.util.EncodingDetector; -import org.jcnc.jnotepad.util.LogUtil; -import org.jcnc.jnotepad.util.UiUtil; import org.jcnc.jnotepad.views.manager.CenterTabPaneManager; import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab; import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTabPane; -import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; -import java.io.IOException; import java.nio.charset.Charset; +import static org.jcnc.jnotepad.common.util.FileUtil.getFileText; + /** * 打开文件的事件处理程序。 *

@@ -68,7 +67,7 @@ public class OpenFile implements EventHandler { * * @param file 文件对象 */ - public void openFile(File file) { + public static void openFile(File file) { // 获取标签页集合 CenterTabPane jnotepadTabPane = CenterTabPane.getInstance(); // 遍历标签页,查找匹配的标签页 @@ -92,39 +91,30 @@ public class OpenFile implements EventHandler { * * @param file 文件对象 */ - public void getText(File file) { + public static void getText(File file) { LineNumberTextArea textArea = createNewTextArea(); // 检测文件编码 Charset encoding = EncodingDetector.detectEncodingCharset(file); - StringBuilder stringBuilder = new StringBuilder(); - try (BufferedReader reader = new BufferedReader(new FileReader(file, encoding))) { - String line; - while ((line = reader.readLine()) != null) { - if (!stringBuilder.isEmpty()) { - stringBuilder.append("\n"); - } - stringBuilder.append(line); - } - String text = stringBuilder.toString(); - LogUtil.getLogger(this.getClass()).info("已调用读取文件功能"); - - textArea.appendText(text); - CenterTab tab = createNewTab(file.getName(), textArea, encoding); - // 设置当前标签页关联本地文件 - tab.setRelevance(true); - tab.setUserData(file); - CenterTabPaneManager.getInstance().addNewTab(tab); - } catch (IOException ignored) { - LogUtil.getLogger(this.getClass()).info("已忽视IO异常!"); - } + String fileText = getFileText(file, encoding); + LogUtil.getLogger(OpenFile.class).info("已调用读取文件功能"); + textArea.appendText(fileText); + CenterTab tab = createNewTab(file.getName(), textArea, encoding); + // 设置当前标签页关联本地文件 + tab.setRelevance(true); + // 设置标签页关联文件 + tab.setUserData(file); + // 设置关联文件最后的修改时间 + tab.setLastModifiedTimeOfAssociatedFile(file.lastModified()); + CenterTabPaneManager.getInstance().addNewTab(tab); } + /** * 创建新的文本区域。 * * @return 新的文本区域 */ - private LineNumberTextArea createNewTextArea() { + private static LineNumberTextArea createNewTextArea() { return new LineNumberTextArea(); } @@ -135,7 +125,7 @@ public class OpenFile implements EventHandler { * @param textArea 文本区域 * @return 新的标签页 */ - private CenterTab createNewTab(String tabName, LineNumberTextArea textArea, Charset charset) { + private static CenterTab createNewTab(String tabName, LineNumberTextArea textArea, Charset charset) { return new CenterTab(tabName, textArea, charset); } } diff --git a/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/RenameFile.java b/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/RenameFile.java index 9b4999b..f52f27a 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/RenameFile.java +++ b/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/RenameFile.java @@ -7,10 +7,10 @@ import javafx.scene.input.KeyCode; import javafx.stage.FileChooser; import org.jcnc.jnotepad.app.i18n.UiResourceBundle; import org.jcnc.jnotepad.common.constants.TextConstants; +import org.jcnc.jnotepad.common.util.LogUtil; +import org.jcnc.jnotepad.common.util.PopUpUtil; +import org.jcnc.jnotepad.common.util.UiUtil; import org.jcnc.jnotepad.ui.dialog.factory.impl.BasicFileChooserFactory; -import org.jcnc.jnotepad.util.LogUtil; -import org.jcnc.jnotepad.util.PopUpUtil; -import org.jcnc.jnotepad.util.UiUtil; import org.jcnc.jnotepad.views.manager.CenterTabPaneManager; import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab; import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTabPane; diff --git a/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/SaveAsFile.java b/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/SaveAsFile.java index fe1143c..0ea14f3 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/SaveAsFile.java +++ b/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/SaveAsFile.java @@ -1,7 +1,7 @@ package org.jcnc.jnotepad.controller.event.handler.menubar; import javafx.event.ActionEvent; -import org.jcnc.jnotepad.util.LogUtil; +import org.jcnc.jnotepad.common.util.LogUtil; /** diff --git a/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/SaveFile.java b/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/SaveFile.java index c649919..2e66f7a 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/SaveFile.java +++ b/src/main/java/org/jcnc/jnotepad/controller/event/handler/menubar/SaveFile.java @@ -6,13 +6,13 @@ import javafx.stage.FileChooser; import org.jcnc.jnotepad.app.i18n.UiResourceBundle; import org.jcnc.jnotepad.common.constants.TextConstants; import org.jcnc.jnotepad.common.manager.ApplicationCacheManager; +import org.jcnc.jnotepad.common.util.LogUtil; +import org.jcnc.jnotepad.common.util.UiUtil; import org.jcnc.jnotepad.controller.config.AppConfigController; import org.jcnc.jnotepad.controller.i18n.LocalizationController; import org.jcnc.jnotepad.model.entity.Cache; import org.jcnc.jnotepad.model.enums.CacheExpirationTime; import org.jcnc.jnotepad.ui.dialog.factory.impl.BasicFileChooserFactory; -import org.jcnc.jnotepad.util.LogUtil; -import org.jcnc.jnotepad.util.UiUtil; import org.jcnc.jnotepad.views.manager.CenterTabPaneManager; import org.jcnc.jnotepad.views.manager.TopMenuBarManager; import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab; 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 c424d35..cd3bba8 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/manager/Controller.java +++ b/src/main/java/org/jcnc/jnotepad/controller/manager/Controller.java @@ -4,11 +4,11 @@ import org.jcnc.jnotepad.common.interfaces.ControllerAble; import org.jcnc.jnotepad.common.manager.ApplicationCacheManager; import org.jcnc.jnotepad.controller.event.handler.menubar.NewFile; import org.jcnc.jnotepad.controller.event.handler.menubar.OpenFile; -import org.jcnc.jnotepad.model.entity.Cache; import java.io.File; import java.util.Collections; import java.util.List; +import java.util.Optional; /** * 控制器类,实现 ControllerAble 接口,用于管理文本编辑器的各种操作和事件处理。 @@ -40,14 +40,11 @@ public class Controller implements ControllerAble { @Override public void openAssociatedFileAndCreateTextArea(List rawParameters) { // 获取上次打开的页面 - Cache cache = CACHE_MANAGER.getCache("tabs", "centerTabs"); - List fileTab; - if (cache == null) { - fileTab = Collections.emptyList(); - } else { - fileTab = (List) cache.getCacheData(); - } - fileTab.forEach(filePath -> new OpenFile().openFile(new File(filePath))); + Optional cacheData = Optional.of(CACHE_MANAGER.getCacheData("tabs", "centerTabs")); + // 判空 + List fileTab = (List) cacheData.orElse(Collections.emptyList()); + // 打开上次打开的标签页 + fileTab.forEach(filePath -> OpenFile.openFile(new File(filePath))); if (!rawParameters.isEmpty()) { String filePath = rawParameters.get(0); @@ -68,7 +65,7 @@ public class Controller implements ControllerAble { public void openAssociatedFile(String filePath) { File file = new File(filePath); if (file.exists() && file.isFile()) { - new OpenFile().openFile(file); + OpenFile.openFile(file); } } } diff --git a/src/main/java/org/jcnc/jnotepad/plugin/PluginLoader.java b/src/main/java/org/jcnc/jnotepad/plugin/PluginLoader.java index 79c9e8e..9b7512e 100644 --- a/src/main/java/org/jcnc/jnotepad/plugin/PluginLoader.java +++ b/src/main/java/org/jcnc/jnotepad/plugin/PluginLoader.java @@ -1,13 +1,13 @@ package org.jcnc.jnotepad.plugin; import org.jcnc.jnotepad.common.manager.ThreadPoolManager; +import org.jcnc.jnotepad.common.util.JsonUtil; +import org.jcnc.jnotepad.common.util.LogUtil; import org.jcnc.jnotepad.controller.config.PluginConfigController; import org.jcnc.jnotepad.exception.AppException; import org.jcnc.jnotepad.model.entity.PluginDescriptor; import org.jcnc.jnotepad.plugin.interfaces.Plugin; import org.jcnc.jnotepad.plugin.manager.PluginManager; -import org.jcnc.jnotepad.util.JsonUtil; -import org.jcnc.jnotepad.util.LogUtil; import org.slf4j.Logger; import java.io.*; diff --git a/src/main/java/org/jcnc/jnotepad/plugin/PluginManagerInterface.java b/src/main/java/org/jcnc/jnotepad/plugin/PluginManagerInterface.java index 0bda44a..de20f47 100644 --- a/src/main/java/org/jcnc/jnotepad/plugin/PluginManagerInterface.java +++ b/src/main/java/org/jcnc/jnotepad/plugin/PluginManagerInterface.java @@ -6,11 +6,11 @@ import javafx.scene.control.Label; import javafx.scene.layout.VBox; import javafx.stage.FileChooser; import javafx.stage.Stage; +import org.jcnc.jnotepad.common.util.LogUtil; +import org.jcnc.jnotepad.common.util.PopUpUtil; +import org.jcnc.jnotepad.common.util.UiUtil; import org.jcnc.jnotepad.plugin.manager.PluginManager; import org.jcnc.jnotepad.ui.dialog.factory.impl.BasicFileChooserFactory; -import org.jcnc.jnotepad.util.LogUtil; -import org.jcnc.jnotepad.util.PopUpUtil; -import org.jcnc.jnotepad.util.UiUtil; import org.slf4j.Logger; import java.io.File; diff --git a/src/main/java/org/jcnc/jnotepad/plugin/manager/PluginManager.java b/src/main/java/org/jcnc/jnotepad/plugin/manager/PluginManager.java index 5bfd38a..686ec0f 100644 --- a/src/main/java/org/jcnc/jnotepad/plugin/manager/PluginManager.java +++ b/src/main/java/org/jcnc/jnotepad/plugin/manager/PluginManager.java @@ -1,12 +1,11 @@ package org.jcnc.jnotepad.plugin.manager; -import org.jcnc.jnotepad.app.manager.ApplicationManager; import org.jcnc.jnotepad.app.util.ApplicationRestarter; import org.jcnc.jnotepad.common.manager.ThreadPoolManager; +import org.jcnc.jnotepad.common.util.LogUtil; +import org.jcnc.jnotepad.common.util.PopUpUtil; import org.jcnc.jnotepad.controller.config.PluginConfigController; import org.jcnc.jnotepad.model.entity.PluginDescriptor; -import org.jcnc.jnotepad.util.LogUtil; -import org.jcnc.jnotepad.util.PopUpUtil; import org.slf4j.Logger; import java.io.File; 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 47ebc8e..ff69a43 100644 --- a/src/main/java/org/jcnc/jnotepad/ui/dialog/AppDialogBuilder.java +++ b/src/main/java/org/jcnc/jnotepad/ui/dialog/AppDialogBuilder.java @@ -5,9 +5,9 @@ import javafx.geometry.Pos; import javafx.scene.image.Image; import javafx.stage.Modality; import javafx.stage.Stage; +import org.jcnc.jnotepad.common.util.UiUtil; import org.jcnc.jnotepad.model.enums.DialogType; import org.jcnc.jnotepad.ui.dialog.interfaces.DialogButtonAction; -import org.jcnc.jnotepad.util.UiUtil; import org.kordamp.ikonli.javafx.FontIcon; /** diff --git a/src/main/java/org/jcnc/jnotepad/ui/setstage/DeveloperDebugStage.java b/src/main/java/org/jcnc/jnotepad/ui/setstage/DeveloperDebugStage.java index 700ecd7..c6f69fc 100644 --- a/src/main/java/org/jcnc/jnotepad/ui/setstage/DeveloperDebugStage.java +++ b/src/main/java/org/jcnc/jnotepad/ui/setstage/DeveloperDebugStage.java @@ -8,9 +8,9 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.stage.Stage; import org.jcnc.jnotepad.app.util.ApplicationRestarter; -import org.jcnc.jnotepad.util.LogUtil; -import org.jcnc.jnotepad.util.PopUpUtil; -import org.jcnc.jnotepad.util.UiUtil; +import org.jcnc.jnotepad.common.util.LogUtil; +import org.jcnc.jnotepad.common.util.PopUpUtil; +import org.jcnc.jnotepad.common.util.UiUtil; import org.slf4j.Logger; /** diff --git a/src/main/java/org/jcnc/jnotepad/ui/setstage/HelpPaneStage.java b/src/main/java/org/jcnc/jnotepad/ui/setstage/HelpPaneStage.java index 5ad3a3a..b8fea56 100644 --- a/src/main/java/org/jcnc/jnotepad/ui/setstage/HelpPaneStage.java +++ b/src/main/java/org/jcnc/jnotepad/ui/setstage/HelpPaneStage.java @@ -17,8 +17,8 @@ import javafx.scene.input.ClipboardContent; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.stage.Stage; -import org.jcnc.jnotepad.util.LogUtil; -import org.jcnc.jnotepad.util.UiUtil; +import org.jcnc.jnotepad.common.util.LogUtil; +import org.jcnc.jnotepad.common.util.UiUtil; import org.jcnc.jnotepad.views.manager.RootManager; import static org.jcnc.jnotepad.common.constants.AppConstants.*; diff --git a/src/main/java/org/jcnc/jnotepad/ui/setstage/SetStage.java b/src/main/java/org/jcnc/jnotepad/ui/setstage/SetStage.java index 279989e..95554a0 100644 --- a/src/main/java/org/jcnc/jnotepad/ui/setstage/SetStage.java +++ b/src/main/java/org/jcnc/jnotepad/ui/setstage/SetStage.java @@ -12,10 +12,10 @@ import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.stage.Stage; +import org.jcnc.jnotepad.common.util.UiUtil; import org.jcnc.jnotepad.plugin.PluginManagerInterface; import org.jcnc.jnotepad.ui.module.CustomSetButton; import org.jcnc.jnotepad.ui.module.SettingsComponent; -import org.jcnc.jnotepad.util.UiUtil; import static org.jcnc.jnotepad.common.constants.AppConstants.SCREEN_LENGTH; import static org.jcnc.jnotepad.common.constants.AppConstants.SCREEN_WIDTH; diff --git a/src/main/java/org/jcnc/jnotepad/ui/setstage/pluginstage/PluginManagementPane.java b/src/main/java/org/jcnc/jnotepad/ui/setstage/pluginstage/PluginManagementPane.java index 9ede60f..61db8c6 100644 --- a/src/main/java/org/jcnc/jnotepad/ui/setstage/pluginstage/PluginManagementPane.java +++ b/src/main/java/org/jcnc/jnotepad/ui/setstage/pluginstage/PluginManagementPane.java @@ -25,13 +25,13 @@ import javafx.scene.web.WebView; import javafx.stage.Stage; import org.commonmark.parser.Parser; import org.commonmark.renderer.html.HtmlRenderer; +import org.jcnc.jnotepad.common.util.LogUtil; +import org.jcnc.jnotepad.common.util.PopUpUtil; +import org.jcnc.jnotepad.common.util.UiUtil; import org.jcnc.jnotepad.model.entity.PluginDescriptor; import org.jcnc.jnotepad.plugin.manager.PluginManager; import org.jcnc.jnotepad.ui.module.CustomSetButton; import org.jcnc.jnotepad.ui.setstage.AbstractPaneStage; -import org.jcnc.jnotepad.util.LogUtil; -import org.jcnc.jnotepad.util.PopUpUtil; -import org.jcnc.jnotepad.util.UiUtil; import org.slf4j.Logger; import java.awt.*; diff --git a/src/main/java/org/jcnc/jnotepad/views/manager/CenterTabPaneManager.java b/src/main/java/org/jcnc/jnotepad/views/manager/CenterTabPaneManager.java index c8b48a3..c579d7e 100644 --- a/src/main/java/org/jcnc/jnotepad/views/manager/CenterTabPaneManager.java +++ b/src/main/java/org/jcnc/jnotepad/views/manager/CenterTabPaneManager.java @@ -2,9 +2,15 @@ package org.jcnc.jnotepad.views.manager; import javafx.collections.ObservableList; import javafx.scene.control.Tab; +import javafx.stage.Stage; +import org.jcnc.jnotepad.app.manager.ApplicationManager; import org.jcnc.jnotepad.common.manager.ApplicationCacheManager; +import org.jcnc.jnotepad.common.util.FileUtil; +import org.jcnc.jnotepad.common.util.LogUtil; +import org.jcnc.jnotepad.common.util.PopUpUtil; import org.jcnc.jnotepad.controller.config.AppConfigController; import org.jcnc.jnotepad.model.enums.CacheExpirationTime; +import org.jcnc.jnotepad.ui.module.LineNumberTextArea; import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab; import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTabPane; import org.jcnc.jnotepad.views.root.top.menu.TopMenuBar; @@ -48,15 +54,58 @@ public class CenterTabPaneManager { private void initListeners() { // tab选中行为监听器,用于tab切换后,更新与当前tab相关的组件 centerTabPane.getSelectionModel().selectedItemProperty().addListener( - (ov, from, to) -> { - if (to != null) { + (ov, preTab, currTab) -> { + if (currTab != null) { // 更新菜单栏中与tab相关设置 TopMenuBar.getInstance().updateMenuStatusBySelectedTab(); + // 判断当前标签页是否关联文件 + CenterTab tab = (CenterTab) currTab; + // 检查文件标签页状态 + checkFileTabStatus(tab); } // 更新状态标签 bottomStatusBoxManager.updateWhenTabSelected(); } ); + ApplicationManager.getInstance().getPrimaryStage().focusedProperty().addListener((observable, oldValue, newValue) -> { + if (Boolean.TRUE.equals(newValue)) { + checkFileTabStatus(getSelected()); + } + }); + } + + + /** + * 检查文件标签页状态 + * + * @apiNote 该方法检查当前文件是否被修改,如果被修改,则返回true + */ + private void checkFileTabStatus(CenterTab tab) { + if (tab.isRelevance()) { + LogUtil.getLogger(this.getClass()).info("当前标签页关联文件"); + + // 获取当前文本域对象 + LineNumberTextArea lineNumberTextArea = tab.getLineNumberTextArea(); + // 获取当前标签页对应文件上次修改时间 + Long lastModifiedTime = tab.getLastModifiedTimeOfAssociatedFile(); + // 获取对应文件上次修改时间 + File file = (File) tab.getUserData(); + + Long lastModifiedTimeOfFile = file.lastModified(); + if (lastModifiedTimeOfFile.equals(lastModifiedTime)) { + return; + } + //fixme 这行代码不能直接放到绑定的方法中,猜测匿名内部类的延迟执行特性可能会导致在获取 FileUtil.getFileText(file) 的返回值时,文件内容还没有被正确读取,导致空串,暂无解决办法 + String fileText = FileUtil.getFileText(file); + // 当前文件已被外部修改 + PopUpUtil.questionAlert( + "重新加载", file.getAbsolutePath(), "此文件已被外部修改,是否重新加载该文件?", + appDialog -> { + lineNumberTextArea.clear(); + lineNumberTextArea.appendText(fileText); + appDialog.close(); + }, Stage::close, "是", "否"); + } } /** diff --git a/src/main/java/org/jcnc/jnotepad/views/manager/TopMenuBarManager.java b/src/main/java/org/jcnc/jnotepad/views/manager/TopMenuBarManager.java index c74bf91..b258033 100644 --- a/src/main/java/org/jcnc/jnotepad/views/manager/TopMenuBarManager.java +++ b/src/main/java/org/jcnc/jnotepad/views/manager/TopMenuBarManager.java @@ -9,14 +9,14 @@ import javafx.scene.control.*; import javafx.scene.input.KeyCombination; import javafx.stage.Stage; import org.jcnc.jnotepad.app.i18n.UiResourceBundle; +import org.jcnc.jnotepad.common.util.LogUtil; +import org.jcnc.jnotepad.common.util.UiUtil; import org.jcnc.jnotepad.controller.config.AppConfigController; import org.jcnc.jnotepad.controller.event.handler.menubar.*; import org.jcnc.jnotepad.controller.i18n.LocalizationController; import org.jcnc.jnotepad.model.entity.ShortcutKey; import org.jcnc.jnotepad.ui.setstage.HelpPaneStage; import org.jcnc.jnotepad.ui.setstage.pluginstage.PluginManagementPane; -import org.jcnc.jnotepad.util.LogUtil; -import org.jcnc.jnotepad.util.UiUtil; import org.jcnc.jnotepad.views.root.top.menu.TopMenuBar; import org.slf4j.Logger; diff --git a/src/main/java/org/jcnc/jnotepad/views/root/center/main/center/tab/CenterTab.java b/src/main/java/org/jcnc/jnotepad/views/root/center/main/center/tab/CenterTab.java index b095ea8..b698b83 100644 --- a/src/main/java/org/jcnc/jnotepad/views/root/center/main/center/tab/CenterTab.java +++ b/src/main/java/org/jcnc/jnotepad/views/root/center/main/center/tab/CenterTab.java @@ -2,9 +2,9 @@ package org.jcnc.jnotepad.views.root.center.main.center.tab; import javafx.scene.control.Tab; import org.fxmisc.flowless.VirtualizedScrollPane; +import org.jcnc.jnotepad.common.util.LogUtil; import org.jcnc.jnotepad.controller.config.AppConfigController; import org.jcnc.jnotepad.ui.module.LineNumberTextArea; -import org.jcnc.jnotepad.util.LogUtil; import org.jcnc.jnotepad.views.manager.BottomStatusBoxManager; import org.jcnc.jnotepad.views.manager.CenterTabPaneManager; import org.slf4j.Logger; @@ -32,6 +32,10 @@ public class CenterTab extends Tab { * 是否与本地文件关联 */ private boolean isRelevance = false; + /** + * 关联文件上次修改时间 + */ + private Long lastModifiedTimeOfAssociatedFile; private Charset charset = Charset.defaultCharset(); public CenterTab(String tabTitle) { @@ -113,6 +117,8 @@ public class CenterTab extends Tab { // 如果发生IO异常,记录忽视的日志信息,但不中断程序执行 LogUtil.getLogger(this.getClass()).info("已忽视IO异常!"); } + // 更新最后修改时间 + tab.setLastModifiedTimeOfAssociatedFile(file.lastModified()); } /** @@ -138,4 +144,11 @@ public class CenterTab extends Tab { saveSelectedFileTab(); } + public Long getLastModifiedTimeOfAssociatedFile() { + return lastModifiedTimeOfAssociatedFile; + } + + public void setLastModifiedTimeOfAssociatedFile(Long lastModifiedTimeOfAssociatedFile) { + this.lastModifiedTimeOfAssociatedFile = lastModifiedTimeOfAssociatedFile; + } }