🚩 实现缓存逻辑缓存逻辑

This commit is contained in:
gewuyou 2023-09-30 20:38:48 +08:00
parent b02ab2ac99
commit 35551de78b
20 changed files with 418 additions and 99 deletions

6
.gitignore vendored
View File

@ -11,6 +11,10 @@ test/
### 此处忽略了json与xml后缀
*.xml
*.json
### 此处排除证书目录
certificate/
### Eclipse ###
.apt_generated
.classpath
@ -47,4 +51,4 @@ logs/
/en_language_pack.txt
/jnotepadConfig.json
/qodana.yaml
.mvn/
.mvn/

View File

@ -20,7 +20,6 @@ module org.jcnc.jnotepad {
requires org.commonmark;
requires javafx.web;
exports org.jcnc.jnotepad;
exports org.jcnc.jnotepad.model.enums;
exports org.jcnc.jnotepad.app.config;

View File

@ -31,6 +31,8 @@ public class LunchApp extends Application {
APPLICATION_MANAGER.setPrimaryStage(primaryStage);
// 加载应用程序资源
APPLICATION_MANAGER.loadAppResources();
// 加载应用程序缓存
APPLICATION_MANAGER.loadAppCache();
// 初始化应用程序
APPLICATION_MANAGER.initializeApp();
// 初始化默认操作

View File

@ -12,6 +12,8 @@ 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.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;
@ -76,7 +78,7 @@ public class ApplicationManager {
}
public void initializeDefaultAction() {
// 使用线程池加载关联文件并创建文本区域
// 使用加载关联文件并创建文本区域
List<String> rawParameters = application.getParameters().getRaw();
Controller.getInstance().openAssociatedFileAndCreateTextArea(rawParameters);
}
@ -96,11 +98,16 @@ public class ApplicationManager {
primaryStage.getIcons().add(UiUtil.getAppIcon());
}
/**
* 加载缓存
*/
public void loadAppCache() {
// 加载缓存
CacheController.getInstance().loadCaches();
}
/**
* 加载资源
*
* @apiNote
* @since 2023/9/20 18:29
*/
public void loadAppResources() {
// 加载资源
@ -115,12 +122,18 @@ public class ApplicationManager {
* @apiNote 在停止程序之前会执行此操作
*/
public void stopApp() {
PluginConfigController instance = PluginConfigController.getInstance();
PluginConfigController pluginConfigController = PluginConfigController.getInstance();
// 刷新插件配置文件
instance.getConfig().setPlugins(PluginManager.getInstance().getPluginDescriptors());
instance.writeConfig();
pluginConfigController.getConfig().setPlugins(PluginManager.getInstance().getPluginDescriptors());
pluginConfigController.writeConfig();
// 保存配置文件
AppConfigController.getInstance().writeConfig();
// 销毁插件可能申请的资源
PluginManager.getInstance().destroyPlugins();
// 保存已打开的文件标签页
CenterTabPaneManager.getInstance().saveOpenFileTabs();
// 将缓存写入本地
CacheController.getInstance().writeCaches();
// 关闭线程池
threadPool.shutdownNow();
}

View File

@ -13,7 +13,7 @@ public abstract class AbstractCacheManager {
/**
* 缓存集合
*/
protected Map<String, Cache<?>> caches;
protected Map<String, Cache> caches;
/**
* 获取全局命名空间
@ -22,27 +22,41 @@ public abstract class AbstractCacheManager {
*/
public abstract String getGlobalNamespace();
/**
* 创建缓存类
*
* @param group 缓存组
* @param name 缓存名称
* @param cacheData 缓存数据
* @param expirationTime 过期时间
* @return 缓存类
* @apiNote 这个方法只需通过自定义的缓存管理类调用此方法无需每次指定相同地命名空间
*/
public Cache createCache(String group, String name, Object cacheData, Long expirationTime) {
return new Cache(getGlobalNamespace(), group, name, cacheData, expirationTime);
}
/**
* 获取缓存集合
*
* @return 缓存集合
*/
public abstract Map<String, Cache<?>> getCaches();
public abstract Map<String, Cache> getCaches();
/**
* 设置缓存集合
*
* @param caches 缓存集合
*/
public abstract void setCaches(Map<String, Cache<?>> caches);
public abstract void setCaches(Map<String, Cache> caches);
/**
* 添加缓存
*
* @param cache 缓存
*/
public void addCache(Cache<?> cache) {
public void addCache(Cache cache) {
String cacheKey = cache.getCacheKey();
// 如果集合中已存在该缓存则更新读写时间
if (caches.containsKey(cacheKey)) {
@ -57,18 +71,29 @@ public abstract class AbstractCacheManager {
* @param cacheKey 缓存key
* @return 缓存类
*/
public Cache<?> getCache(String cacheKey) {
if (caches.isEmpty()) {
public Cache getCache(String cacheKey) {
if (caches == null || caches.isEmpty()) {
return null;
}
if (caches.containsKey(cacheKey)) {
Cache<?> cache = caches.get(cacheKey);
Cache cache = caches.get(cacheKey);
cache.setLastReadOrWriteTime(System.currentTimeMillis());
return cache;
}
return null;
}
/**
* 获取缓存类
*
* @param group
* @param name 缓存名
* @return 缓存类
*/
public Cache getCache(String group, String name) {
return getCache(Cache.getCacheKey(getGlobalNamespace(), group, name));
}
/**
* 获取缓存数据
*
@ -76,7 +101,7 @@ public abstract class AbstractCacheManager {
* @return 缓存类
*/
public Object getCacheData(String cacheKey) {
Cache<?> cache = getCache(cacheKey);
Cache cache = getCache(cacheKey);
if (cache == null) {
return null;
}

View File

@ -22,12 +22,12 @@ public class ApplicationCacheManager extends AbstractCacheManager {
}
@Override
public Map<String, Cache<?>> getCaches() {
public Map<String, Cache> getCaches() {
return caches;
}
@Override
public void setCaches(Map<String, Cache<?>> caches) {
public void setCaches(Map<String, Cache> caches) {
this.caches = caches;
}

View File

@ -1,12 +1,23 @@
package org.jcnc.jnotepad.controller.cache;
import com.fasterxml.jackson.core.type.TypeReference;
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
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;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import static org.jcnc.jnotepad.common.constants.AppConstants.DEFAULT_PROPERTY;
@ -17,28 +28,131 @@ import static org.jcnc.jnotepad.common.constants.AppConstants.DEFAULT_PROPERTY;
*/
public class CacheController {
private static final ApplicationCacheManager APPLICATION_CACHE_MANAGER = ApplicationCacheManager.getInstance();
Logger logger = LogUtil.getLogger(this.getClass());
private static final CacheController INSTANCE = new CacheController();
private String cacheDir;
private CacheController() {
cacheDir = Paths.get(System.getProperty(DEFAULT_PROPERTY), ".jnotepad", "caches").toString();
loadCaches();
}
public static CacheController getInstance() {
return INSTANCE;
}
private void loadCaches() {
public void loadCaches() {
// 如果本地没有缓存的话就创建缓存
if (createCachesIfNotExists()) {
return;
}
// 检查并获取缓存根目录
File cacheFileDir = createCacheRootIfNotExist();
// 获取缓存命名空间
String[] namespaces = cacheFileDir.list();
// 如果缓存根目录下为空则创建缓存
if (Objects.requireNonNull(namespaces).length == 0) {
APPLICATION_CACHE_MANAGER.setCaches(new HashMap<>(16));
return;
}
Map<String, Cache> caches = new HashMap<>(16);
for (String namespace : namespaces) {
// 获取命名空间对应的文件夹
File namespaceDir = new File(cacheFileDir, namespace);
// 获取缓存组对应的文件名称列表
String[] groupNames = namespaceDir.list();
// 如果命名空间文件夹下没有文件则删除该文件夹
if (cleanEmptyFileOrFolder(namespaceDir)) {
continue;
}
for (String groupName : Objects.requireNonNull(groupNames)) {
// 获取缓存组对应的文件
File groupFile = new File(namespaceDir, groupName);
// 清理空文件
if (cleanEmptyFileOrFolder(groupFile)) {
continue;
}
// 获取缓存
try {
String cacheJson = Files.readString(groupFile.toPath());
// 获取缓存集合
Map<String, Cache> cacheMap = JsonUtil.fromJsonString(cacheJson, new TypeReference<>() {
});
// 设置缓存
cacheMap.forEach((k, v) -> setUpCache(namespace, groupName, k, v, caches));
} catch (IOException e) {
logger.error("读取缓存文件出错!", e);
}
}
// 设置缓存
APPLICATION_CACHE_MANAGER.setCaches(caches);
}
}
private void writeCaches(Map<String, Cache<?>> caches) {
File cacheFileDir = new File(cacheDir);
if (!cacheFileDir.exists()) {
cacheFileDir.mkdirs();
/**
* 设置缓存
*
* @param namespace 命名空间
* @param groupName 缓存组
* @param k 缓存名称
* @param v 缓存类
* @param caches 缓存集合
*/
private void setUpCache(String namespace, String groupName, String k, Cache v, Map<String, Cache> caches) {
// 判断缓存是否过期,没有过期才加载进内存
if (v.getLastReadOrWriteTime() + v.getExpirationTime() > System.currentTimeMillis() || v.getExpirationTime() < 0) {
v.setNamespace(namespace);
v.setGroup(groupName);
v.setName(k);
caches.put(v.getCacheKey(), v);
}
}
/**
* 清理空文件或空文件夹并返回结果
*
* @param fileOrFolder 文件或文件夹
* @return 是否清理
*/
private boolean cleanEmptyFileOrFolder(File fileOrFolder) {
try {
if (fileOrFolder.isFile() && fileOrFolder.length() == 0) {
Files.delete(fileOrFolder.toPath());
logger.info("删除缓存文件:{}", fileOrFolder);
return true;
}
if (fileOrFolder.isDirectory() && Objects.requireNonNull(fileOrFolder.list()).length == 0) {
Files.delete(fileOrFolder.toPath());
logger.info("删除缓存文件夹:{}", fileOrFolder);
return true;
}
} catch (IOException e) {
throw new AppException(e);
}
return false;
}
/**
* 写缓存(writeCache)
*/
public void writeCaches() {
writeCaches(APPLICATION_CACHE_MANAGER.getCaches());
}
/**
* 写缓存
*
* @param caches 缓存集合
*/
public void writeCaches(Map<String, Cache> caches) {
// 检查并获取缓存根目录
File cacheFileDir = createCacheRootIfNotExist();
Map<File, Map<String, Cache>> fileMap = new HashMap<>(16);
// 生成缓存
caches.forEach((key, value) -> {
// 判断当前命名空间对应目录是否创建
@ -58,17 +172,61 @@ public class CacheController {
throw new AppException(e);
}
}
fileMap.computeIfAbsent(groupFile, k -> new HashMap<>(16));
// 设置需要写入的数据
fileMap.get(groupFile).put(value.getName(), value);
});
//
Set<File> fileSet = fileMap.keySet();
// 清空原来的缓存
fileSet.forEach(file -> {
try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
fileOutputStream.write(new byte[0]);
} catch (IOException e) {
throw new AppException(e);
}
});
// 写入缓存
for (Map.Entry<File, Map<String, Cache>> entry : fileMap.entrySet()) {
try (FileWriter writer = new FileWriter(entry.getKey(), true)) {
writer.write(JsonUtil.toJsonString(entry.getValue()));
} catch (IOException e) {
throw new AppException(e);
}
}
}
/**
* 如果缓存
* 如果不存在则创建缓存根目录
*
* @return 缓存根目录
*/
private void createCachesIfNotExists() {
private File createCacheRootIfNotExist() {
File cacheFileDir = new File(cacheDir);
if (!cacheFileDir.exists()) {
cacheFileDir.mkdirs();
}
return cacheFileDir;
}
/**
* 如果本地没有缓存则创建缓存
*
* @return 是否创建成功
*/
private boolean createCachesIfNotExists() {
File cacheFileDir = createCacheRootIfNotExist();
if (Objects.requireNonNull(cacheFileDir.list()).length == 0) {
APPLICATION_CACHE_MANAGER.setCaches(new HashMap<>(16));
return true;
}
return false;
}
public String getCacheDir() {
return cacheDir;
}
public void setCacheDir(String cacheDir) {
this.cacheDir = cacheDir;
}
}

View File

@ -1,14 +1,14 @@
package org.jcnc.jnotepad.controller.event.handler.menubar;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Tab;
import javafx.stage.FileChooser;
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
import org.jcnc.jnotepad.common.constants.TextConstants;
import org.jcnc.jnotepad.common.manager.ThreadPoolManager;
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
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;
@ -24,8 +24,6 @@ import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;
import static org.jcnc.jnotepad.common.manager.ThreadPoolManager.threadContSelfSubtracting;
/**
* 打开文件的事件处理程序
* <p>
@ -34,6 +32,8 @@ import static org.jcnc.jnotepad.common.manager.ThreadPoolManager.threadContSelfS
* @author 许轲
*/
public class OpenFile implements EventHandler<ActionEvent> {
private static final ApplicationCacheManager CACHE_MANAGER = ApplicationCacheManager.getInstance();
/**
* 处理打开文件事件
*
@ -41,42 +41,28 @@ public class OpenFile implements EventHandler<ActionEvent> {
*/
@Override
public void handle(ActionEvent event) {
// 获取缓存
Cache cache = CACHE_MANAGER.getCache("folder", "openFile");
// 显示文件选择对话框并获取选中的文件
File file = BasicFileChooserFactory.getInstance().createFileChooser(
UiResourceBundle.getContent(TextConstants.OPEN),
null,
null,
cache == null ? null : new File((String) cache.getCacheData()),
new FileChooser.ExtensionFilter("All types", "*.*"))
.showOpenDialog(UiUtil.getAppWindow());
if (file == null) {
return;
}
// 设置缓存
if (cache == null) {
CACHE_MANAGER.addCache(CACHE_MANAGER.createCache("folder", "openFile", file.getParent(), CacheExpirationTime.NEVER_EXPIRES.getValue()));
} else {
cache.setCacheData(file.getParent());
CACHE_MANAGER.addCache(cache);
}
openFile(file);
}
/**
* 创建打开文件的任务
*
* @param file 文件对象
* @return 打开文件的任务
*/
public Task<Void> createOpenFileTask(File file) {
Task<Void> openFileTask = new Task<>() {
@Override
protected Void call() {
getText(file);
return null;
}
};
// 设置任务成功完成时的处理逻辑
openFileTask.setOnSucceeded(e -> threadContSelfSubtracting());
// 设置任务失败时的处理逻辑
openFileTask.setOnFailed(e -> threadContSelfSubtracting());
return openFileTask;
}
/**
* 打开文件
*
@ -98,7 +84,7 @@ public class OpenFile implements EventHandler<ActionEvent> {
return;
}
}
ThreadPoolManager.getThreadPool().submit(createOpenFileTask(file));
getText(file);
}
/**
@ -110,25 +96,24 @@ public class OpenFile implements EventHandler<ActionEvent> {
LineNumberTextArea textArea = createNewTextArea();
// 检测文件编码
Charset encoding = EncodingDetector.detectEncodingCharset(file);
StringBuilder stringBuilder = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new FileReader(file, encoding))) {
StringBuilder textBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
if (!textBuilder.isEmpty()) {
textBuilder.append("\n");
if (!stringBuilder.isEmpty()) {
stringBuilder.append("\n");
}
textBuilder.append(line);
stringBuilder.append(line);
}
String text = textBuilder.toString();
String text = stringBuilder.toString();
LogUtil.getLogger(this.getClass()).info("已调用读取文件功能");
Platform.runLater(() -> {
textArea.appendText(text);
CenterTab tab = createNewTab(file.getName(), textArea, encoding);
// 设置当前标签页关联本地文件
tab.setRelevance(true);
tab.setUserData(file);
CenterTabPaneManager.getInstance().addNewTab(tab);
});
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异常!");
}

View File

@ -139,6 +139,7 @@ public class RenameFile implements EventHandler<ActionEvent> {
private void handleRenameRelevanceFile(CenterTab centerTab) {
// 获取原始文件对象
File file = (File) centerTab.getUserData();
// 获取应用窗口并绑定
File newFile = BasicFileChooserFactory.getInstance()
.createFileChooser(

View File

@ -5,8 +5,11 @@ import javafx.event.EventHandler;
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.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;
@ -28,6 +31,7 @@ import static org.jcnc.jnotepad.controller.config.AppConfigController.CONFIG_NAM
* @author gewuyou
*/
public class SaveFile implements EventHandler<ActionEvent> {
private static final ApplicationCacheManager CACHE_MANAGER = ApplicationCacheManager.getInstance();
Logger logger = LogUtil.getLogger(this.getClass());
/**
@ -76,13 +80,20 @@ public class SaveFile implements EventHandler<ActionEvent> {
if (selectedTab == null) {
return;
}
Cache cache = CACHE_MANAGER.getCache("folder", "saveFile");
File file = BasicFileChooserFactory.getInstance().createFileChooser(
UiResourceBundle.getContent(TextConstants.SAVE_AS),
selectedTab.getText(),
null,
cache == null ? null : new File((String) cache.getCacheData()),
new FileChooser.ExtensionFilter("All types", "*.*"))
.showSaveDialog(UiUtil.getAppWindow());
if (file != null) {
if (cache == null) {
CACHE_MANAGER.addCache(CACHE_MANAGER.createCache("folder", "saveFile", file.getParent(), CacheExpirationTime.NEVER_EXPIRES.getValue()));
} else {
cache.setCacheData(file.getParent());
CACHE_MANAGER.addCache(cache);
}
LogUtil.getLogger(currentClass).info("正在保存文件: {}", file.getName());
selectedTab.save(file);
// 将保存后的文件设置为关联文件

View File

@ -1,8 +1,10 @@
package org.jcnc.jnotepad.controller.manager;
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.List;
@ -13,6 +15,7 @@ import java.util.List;
* @author 许轲
*/
public class Controller implements ControllerAble {
private static final ApplicationCacheManager CACHE_MANAGER = ApplicationCacheManager.getInstance();
private static final Controller INSTANCE = new Controller();
@ -35,10 +38,19 @@ public class Controller implements ControllerAble {
*/
@Override
public void openAssociatedFileAndCreateTextArea(List<String> rawParameters) {
// 获取上次打开的页面
Cache cache = CACHE_MANAGER.getCache("tabs", "centerTabs");
List<String> fileTab = (List<String>) cache.getCacheData();
// fileTab.forEach(filePath -> new OpenFile().openFile(new File(filePath)));
for (String filePath : fileTab) {
new OpenFile().openFile(new File(filePath));
}
if (!rawParameters.isEmpty()) {
String filePath = rawParameters.get(0);
openAssociatedFile(filePath);
} else {
return;
}
if (fileTab.isEmpty()) {
new NewFile().addNewFileTab();
}
}

View File

@ -8,7 +8,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
*
* @author gewuyou
*/
public class Cache<T> {
public class Cache {
/**
* 命名空间
*/
@ -22,12 +22,13 @@ public class Cache<T> {
/**
* 缓存名称
*/
@JsonIgnore
private String name;
/**
* 缓存数据
*/
private T cacheData;
private Object cacheData;
/**
* 过期时间<br/>如果过期时间为负数则永不过期
*/
@ -41,7 +42,7 @@ public class Cache<T> {
}
public Cache(String namespace, String group, String name, T cacheData, Long expirationTime) {
public Cache(String namespace, String group, String name, Object cacheData, Long expirationTime) {
this.namespace = namespace;
this.group = group;
this.name = name;
@ -51,12 +52,25 @@ public class Cache<T> {
}
/**
* 根据缓存key
* 生成缓存key
*
* @param namespace 命名空间
* @param group
* @param name 缓存名称
* @return 缓存key
*/
public static String getCacheKey(String namespace, String group, String name) {
return namespace + "." + group + "." + name;
}
/**
* 获取缓存key
*
* @return key
*/
@JsonIgnore
public String getCacheKey() {
return this.getNamespace() + "." + this.getGroup() + "." + this.getName();
return getCacheKey(namespace, group, name);
}
public String getNamespace() {
@ -83,11 +97,11 @@ public class Cache<T> {
this.name = name;
}
public T getCacheData() {
public Object getCacheData() {
return cacheData;
}
public void setCacheData(T cacheData) {
public void setCacheData(Object cacheData) {
this.cacheData = cacheData;
}

View File

@ -0,0 +1,44 @@
package org.jcnc.jnotepad.model.enums;
/**
* 缓存过期时间枚举
*
* @author gewuyou
*/
public enum CacheExpirationTime {
/**
* 一小时
*/
ONE_HOUR(60 * 60 * 1000L),
/**
* 一天
*/
ONE_DAY(24 * ONE_HOUR.value),
/**
* 一周
*/
ONE_WEEK(7 * ONE_DAY.value),
/**
* 一月
*/
ONE_MONTH(30 * ONE_DAY.value),
/**
* 一年
*/
ONE_YEAR(365 * ONE_DAY.value),
/**
* 永不过期
*/
NEVER_EXPIRES(-1L);
private final Long value;
CacheExpirationTime(Long value) {
this.value = value;
}
public Long getValue() {
return value;
}
}

View File

@ -99,7 +99,7 @@ public class PluginLoader {
*/
private static boolean pluginDoesNotExist(PluginDescriptor pluginDescriptor, List<PluginDescriptor> configPluginDescriptors) {
for (PluginDescriptor configPluginDescriptor : configPluginDescriptors) {
if ((configPluginDescriptor.getName() + configPluginDescriptor.getAuthor()).equals(pluginDescriptor.getName() + pluginDescriptor.getAuthor())) {
if (configPluginDescriptor.getId().equals(pluginDescriptor.getId())) {
return false;
}
}
@ -110,7 +110,7 @@ public class PluginLoader {
Iterator<PluginDescriptor> iterator = pluginDescriptors.iterator();
while (iterator.hasNext()) {
PluginDescriptor plugin = iterator.next();
if ((plugin.getName() + plugin.getAuthor()).equals(pluginDescriptor.getName() + pluginDescriptor.getAuthor())) {
if (plugin.getId().equals(pluginDescriptor.getId())) {
if (plugin.getVersion().equals(pluginDescriptor.getVersion())) {
return true;
}
@ -137,7 +137,7 @@ public class PluginLoader {
* @since 2023/9/19 18:45
*/
private static boolean disableDoNotLoad(PluginDescriptor pluginDescriptor, List<PluginDescriptor> pluginDescriptors, PluginDescriptor configPluginDescriptor) {
if ((configPluginDescriptor.getName() + configPluginDescriptor.getAuthor()).equals(pluginDescriptor.getName() + pluginDescriptor.getAuthor()) && !configPluginDescriptor.isEnabled()) {
if (configPluginDescriptor.getId().equals(pluginDescriptor.getId()) && !configPluginDescriptor.isEnabled()) {
pluginDescriptor.setEnabled(false);
pluginDescriptors.add(pluginDescriptor);
return true;

View File

@ -85,7 +85,7 @@ public class PluginManager {
try {
File pluginJar = new File(path.toString());
PluginDescriptor temp = readPlugin(pluginJar);
if ((temp.getName() + temp.getAuthor()).equals(pluginDescriptor.getName() + pluginDescriptor.getAuthor())) {
if (temp.getId().equals(pluginDescriptor.getId())) {
Files.delete(pluginJar.toPath());
}
} catch (IOException e) {

View File

@ -26,8 +26,6 @@ import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;
import org.jcnc.jnotepad.model.entity.PluginDescriptor;
import org.jcnc.jnotepad.plugin.manager.PluginManager;
import org.jcnc.jnotepad.ui.dialog.AppDialog;
import org.jcnc.jnotepad.ui.dialog.interfaces.DialogButtonAction;
import org.jcnc.jnotepad.ui.module.CustomSetButton;
import org.jcnc.jnotepad.util.LogUtil;
import org.jcnc.jnotepad.util.PopUpUtil;
@ -272,14 +270,11 @@ public class PluginManagementPane extends BorderPane {
BooleanProperty booleanProperty = toggleSwitch.selectedProperty();
state.textProperty().bind(Bindings.when(booleanProperty).then("禁用").otherwise("启用"));
uninstallItem.setOnAction(event -> PopUpUtil.warningAlert("卸载", "确定要卸载" + pluginDescriptor.getName() + "吗?", "此操作无法撤销!", new DialogButtonAction() {
@Override
public void handleAction(AppDialog dialog) {
pluginManager.unloadPlugin(pluginDescriptor);
state.setDisable(true);
toggleSwitch.setDisable(true);
dialog.close();
}
uninstallItem.setOnAction(event -> PopUpUtil.warningAlert("卸载", "确定要卸载" + pluginDescriptor.getName() + "吗?", "此操作无法撤销!", dialog -> {
pluginManager.unloadPlugin(pluginDescriptor);
state.setDisable(true);
toggleSwitch.setDisable(true);
dialog.close();
}, null));
state.getStyleClass().addAll(Styles.ACCENT);
state.setPrefWidth(80);

View File

@ -1,6 +1,7 @@
package org.jcnc.jnotepad.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -35,7 +36,7 @@ public class JsonUtil {
* 将对象转换为 JSON 字符串
*
* @param o 要转换的对象
* @return 对象的 JSON 表示如果转换失败则抛出 AppException 异常
* @return 对象的 JSON 表示
* @throws AppException 如果转换失败
*/
public static String toJsonString(Object o) {
@ -45,4 +46,36 @@ public class JsonUtil {
throw new AppException(e);
}
}
/**
* 将json字符串解析成对象
*
* @param json json字符串
* @param clazz 对象类型
* @return 对象
* @throws AppException 如果解析失败
*/
public static <T> T fromJsonString(String json, Class<T> clazz) {
try {
return OBJECT_MAPPER.readValue(json, clazz);
} catch (JsonProcessingException e) {
throw new AppException(e);
}
}
/**
* 将json字符串解析成对象
*
* @param json json字符串
* @param valueTypeRef 类型 引用
* @return 对象
* @throws AppException 如果解析失败
*/
public static <T> T fromJsonString(String json, TypeReference<T> valueTypeRef) {
try {
return OBJECT_MAPPER.readValue(json, valueTypeRef);
} catch (JsonProcessingException e) {
throw new AppException(e);
}
}
}

View File

@ -1,16 +1,25 @@
package org.jcnc.jnotepad.views.manager;
import javafx.collections.ObservableList;
import javafx.scene.control.Tab;
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
import org.jcnc.jnotepad.controller.config.AppConfigController;
import org.jcnc.jnotepad.model.enums.CacheExpirationTime;
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;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* 中心标签页窗格管理类
*
* @author gewuyou
*/
public class CenterTabPaneManager {
private static final ApplicationCacheManager CACHE_MANAGER = ApplicationCacheManager.getInstance();
private static final CenterTabPaneManager INSTANCE = new CenterTabPaneManager();
private final CenterTabPane centerTabPane = CenterTabPane.getInstance();
@ -88,4 +97,18 @@ public class CenterTabPaneManager {
selectedTab.setAutoLine(AppConfigController.getInstance().getAutoLineConfig());
bottomStatusBoxManager.updateWhenTabSelected();
}
public void saveOpenFileTabs() {
// 获取当前所有标签页
ObservableList<Tab> tabs = centerTabPane.getTabs();
List<String> filePaths = new ArrayList<>();
// 缓存当前打开关联的文件
tabs.forEach(tab -> {
File file = (File) tab.getUserData();
if (file != null) {
filePaths.add(file.getPath());
}
});
CACHE_MANAGER.addCache(CACHE_MANAGER.createCache("tabs", "centerTabs", filePaths, CacheExpirationTime.NEVER_EXPIRES.getValue()));
}
}

View File

@ -91,4 +91,5 @@ public class CenterTab extends Tab {
this.setUserData(file);
save();
}
}

View File

@ -8,7 +8,6 @@ import javafx.scene.control.TabPane;
* @author songdragon
*/
public class CenterTabPane extends TabPane {
private static final CenterTabPane INSTANCE = new CenterTabPane();
private CenterTabPane() {