Merge remote-tracking branch '我的仓库/release-v1.1.13' into release-v1.1.13

This commit is contained in:
许轲 2023-10-05 18:58:14 +08:00
commit 52c8f13355
16 changed files with 238 additions and 71 deletions

View File

@ -125,9 +125,13 @@ POM文件中的全部依赖项
- Windows 平台 - Windows 平台
![Windows](screenshot/windows-1.png) ![Windows](screenshot/windows-1.png)
- MacOS 平台
- MacOS 平台 (待更新,原因:没有设备)
![MacOS](screenshot/Mac0S-1.png) ![MacOS](screenshot/Mac0S-1.png)
- Linux 平台
![Linux](screenshot/Linux-1.png)
# 参与贡献 # 参与贡献
1. 加入JCNC社区 1. 加入JCNC社区

BIN
screenshot/Linux-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

View File

@ -27,7 +27,7 @@ public class LunchApp extends Application {
@Override @Override
public void start(Stage primaryStage) { public void start(Stage primaryStage) {
// 获取当前启动位置 // 获取当前启动位置a
String currentWorkingDirectory = System.getProperty("user.dir"); String currentWorkingDirectory = System.getProperty("user.dir");
LogUtil.getLogger(this.getClass()).info("当前启动位置:{}", currentWorkingDirectory); LogUtil.getLogger(this.getClass()).info("当前启动位置:{}", currentWorkingDirectory);
@ -47,6 +47,6 @@ public class LunchApp extends Application {
@Override @Override
public void stop() { public void stop() {
APPLICATION_MANAGER.stopApp(); APPLICATION_MANAGER.operationBeforeStopping();
} }
} }

View File

@ -22,7 +22,9 @@ import java.nio.file.Paths;
*/ */
public abstract class BaseConfigController<T> implements ConfigController<T> { public abstract class BaseConfigController<T> implements ConfigController<T> {
public static final String ROOT_CONFIG_DIR = "config"; protected final String rootConfigDir = "config";
protected final String systemConfigDir = "system";
protected T config; protected T config;
Logger logger = LogUtil.getLogger(this.getClass()); Logger logger = LogUtil.getLogger(this.getClass());

View File

@ -1,8 +1,15 @@
package org.jcnc.jnotepad.app.config; package org.jcnc.jnotepad.app.config;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.io.File;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import static org.jcnc.jnotepad.common.constants.AppConstants.DEFAULT_PROPERTY; import static org.jcnc.jnotepad.common.constants.AppConstants.DEFAULT_PROPERTY;
import static org.jcnc.jnotepad.common.constants.AppConstants.PROGRAM_FILE_DIRECTORY;
/** /**
* 应用程序配置文件 * 应用程序配置文件
@ -14,12 +21,51 @@ public class AppConfig {
* 程序根路径 * 程序根路径
*/ */
private String rootPath; private String rootPath;
/**
* 排除的文件夹
*/
@JsonIgnore
private final Set<File> ignoreFolder;
/**
* 排除的文件
*/
@JsonIgnore
private final Set<File> ignoreFile;
/**
* 上次的程序根路径
*/
@JsonIgnore
private String lastRootPath;
public AppConfig() {
ignoreFolder = Set.of(
new File(Paths.get(System.getProperty(DEFAULT_PROPERTY), PROGRAM_FILE_DIRECTORY, "system").toString()),
new File(Paths.get(System.getProperty(DEFAULT_PROPERTY), PROGRAM_FILE_DIRECTORY, "logs").toString())
);
ignoreFile = Collections.emptySet();
}
public String getRootPath() { public String getRootPath() {
return Optional.of(rootPath).orElse(System.getProperty(DEFAULT_PROPERTY)); return Optional.ofNullable(rootPath).orElse(System.getProperty(DEFAULT_PROPERTY));
} }
public void setRootPath(String rootPath) { public void setRootPath(String rootPath) {
this.rootPath = rootPath; this.rootPath = rootPath;
} }
public String getLastRootPath() {
return lastRootPath;
}
public void setLastRootPath(String lastRootPath) {
this.lastRootPath = lastRootPath;
}
public Set<File> getIgnoreFolder() {
return ignoreFolder;
}
public Set<File> getIgnoreFile() {
return ignoreFile;
}
} }

View File

@ -8,24 +8,35 @@ import javafx.scene.layout.Pane;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.Window; import javafx.stage.Window;
import org.jcnc.jnotepad.LunchApp; import org.jcnc.jnotepad.LunchApp;
import org.jcnc.jnotepad.app.config.AppConfig;
import org.jcnc.jnotepad.app.i18n.UiResourceBundle; import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
import org.jcnc.jnotepad.common.constants.AppConstants; import org.jcnc.jnotepad.common.constants.AppConstants;
import org.jcnc.jnotepad.common.constants.TextConstants; import org.jcnc.jnotepad.common.constants.TextConstants;
import org.jcnc.jnotepad.common.manager.ThreadPoolManager; import org.jcnc.jnotepad.common.manager.ThreadPoolManager;
import org.jcnc.jnotepad.controller.ResourceController; import org.jcnc.jnotepad.controller.ResourceController;
import org.jcnc.jnotepad.controller.cache.CacheController; 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.config.PluginConfigController;
import org.jcnc.jnotepad.controller.exception.AppException;
import org.jcnc.jnotepad.controller.manager.Controller; import org.jcnc.jnotepad.controller.manager.Controller;
import org.jcnc.jnotepad.plugin.manager.PluginManager; import org.jcnc.jnotepad.plugin.manager.PluginManager;
import org.jcnc.jnotepad.util.FileUtil;
import org.jcnc.jnotepad.util.LogUtil; import org.jcnc.jnotepad.util.LogUtil;
import org.jcnc.jnotepad.util.UiUtil; import org.jcnc.jnotepad.util.UiUtil;
import org.jcnc.jnotepad.views.manager.*; import org.jcnc.jnotepad.views.manager.*;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import static org.jcnc.jnotepad.common.constants.AppConstants.DEFAULT_PROPERTY;
import static org.jcnc.jnotepad.common.constants.AppConstants.PROGRAM_FILE_DIRECTORY;
/** /**
* 应用程序管理类<br/> * 应用程序管理类<br/>
@ -130,11 +141,42 @@ public class ApplicationManager {
} }
/** /**
* 停止程序 * 迁移程序根文件夹
*/
public void migrateFileRootFolder() {
AppConfig config = AppConfigController.getInstance().getConfig();
String lastRootPath = config.getLastRootPath();
if (lastRootPath == null) {
return;
}
// 获取源文件夹
File sourceFolder = new File(lastRootPath, PROGRAM_FILE_DIRECTORY);
// 获取目标文件夹
File targetFolder = new File(config.getRootPath(), PROGRAM_FILE_DIRECTORY);
// 设置忽略文件夹
Set<File> ignoredFolders = config.getIgnoreFolder();
// 设置忽略文件
Set<File> ignoredFiles = config.getIgnoreFile();
// 移动文件夹
FileUtil.migrateFolder(sourceFolder, targetFolder, ignoredFolders, ignoredFiles);
// 删除.jnotepad
if (!sourceFolder.equals(new File(Paths.get(System.getProperty(DEFAULT_PROPERTY), PROGRAM_FILE_DIRECTORY).toString()))) {
try {
Files.delete(sourceFolder.toPath());
} catch (IOException e) {
throw new AppException(e);
}
}
// 保存新配置
AppConfigController.getInstance().writeConfig();
}
/**
* 停止前操作
* *
* @apiNote 在停止程序之前会执行此操作 * @apiNote 在停止程序之前会执行此操作
*/ */
public void stopApp() { public void operationBeforeStopping() {
PluginConfigController pluginConfigController = PluginConfigController.getInstance(); PluginConfigController pluginConfigController = PluginConfigController.getInstance();
// 刷新插件配置文件 // 刷新插件配置文件
pluginConfigController.getConfig().setPlugins(PluginManager.getInstance().getPluginDescriptors()); pluginConfigController.getConfig().setPlugins(PluginManager.getInstance().getPluginDescriptors());
@ -146,6 +188,8 @@ public class ApplicationManager {
CenterTabPaneManager.getInstance().saveOpenFileTabs(); CenterTabPaneManager.getInstance().saveOpenFileTabs();
// 将缓存写入本地 // 将缓存写入本地
CacheController.getInstance().writeCaches(); CacheController.getInstance().writeCaches();
// 迁移文件夹
migrateFileRootFolder();
// 关闭线程池 // 关闭线程池
threadPool.shutdownNow(); threadPool.shutdownNow();
} }
@ -205,12 +249,11 @@ public class ApplicationManager {
// 构建新进程来重新启动应用程序 // 构建新进程来重新启动应用程序
ProcessBuilder builder = new ProcessBuilder(javaCommand, "-cp", System.getProperty("java.class.path"), mainClass); ProcessBuilder builder = new ProcessBuilder(javaCommand, "-cp", System.getProperty("java.class.path"), mainClass);
builder.start(); builder.start();
// 关闭当前应用程序 // 关闭当前应用程序
System.exit(0); // fixme 使用这个System.exit(0);在开发环境点击重启程序停止前操作不生效
stop();
} catch (IOException e) { } catch (IOException e) {
LogUtil.getLogger("正在重启当前应用程序".getClass()); LogUtil.getLogger("正在重启当前应用程序".getClass());
} }
} }
@ -239,7 +282,7 @@ public class ApplicationManager {
this.primaryStage = primaryStage; this.primaryStage = primaryStage;
} }
public void stopApplication() { public void stop() {
Platform.exit(); Platform.exit();
} }
} }

View File

@ -44,6 +44,10 @@ public class AppConstants {
* 默认属性 * 默认属性
*/ */
public static final String DEFAULT_PROPERTY = "user.home"; public static final String DEFAULT_PROPERTY = "user.home";
/**
* 程序文件目录
*/
public static final String PROGRAM_FILE_DIRECTORY = ".jnotepad";
/** /**

View File

@ -1,7 +1,5 @@
package org.jcnc.jnotepad.component.module.interfaces; package org.jcnc.jnotepad.component.module.interfaces;
import java.util.List;
/** /**
* 控制器接口类 * 控制器接口类
* *
@ -9,14 +7,14 @@ import java.util.List;
* *
* @author 许轲 * @author 许轲
*/ */
public interface ControllerAble { public interface ControllerAble<T> {
/** /**
* 打开关联文件并创建 TextArea * 打开关联文件并创建 TextArea
* *
* @param rawParameters 原始参数列表 * @param rawParameters 原始参数列表
*/ */
void openAssociatedFileAndCreateTextArea(List<String> rawParameters); void openAssociatedFileAndCreateTextArea(T rawParameters);
/** /**
* 打开关联文件 * 打开关联文件

View File

@ -266,6 +266,9 @@ public class SetStage extends Stage {
cache.setCacheData(file.getParent()); cache.setCacheData(file.getParent());
cacheManager.addCache(cache); cacheManager.addCache(cache);
} }
// 设置上次的根路径
config.setLastRootPath(config.getRootPath());
// 设置当前根路径
config.setRootPath(file.getAbsolutePath()); config.setRootPath(file.getAbsolutePath());
PopUpUtil.questionAlert("更改", "设置程序文件根路径", "设置成功,请重启程序以应用路径更改!", appDialog -> { PopUpUtil.questionAlert("更改", "设置程序文件根路径", "设置成功,请重启程序以应用路径更改!", appDialog -> {
appDialog.close(); appDialog.close();

View File

@ -1,25 +1,15 @@
package org.jcnc.jnotepad.controller; package org.jcnc.jnotepad.controller;
import org.jcnc.jnotepad.controller.config.PluginConfigController;
import org.jcnc.jnotepad.controller.exception.AppException;
import org.jcnc.jnotepad.controller.i18n.LocalizationController; import org.jcnc.jnotepad.controller.i18n.LocalizationController;
import org.jcnc.jnotepad.plugin.PluginLoader; import org.jcnc.jnotepad.plugin.PluginLoader;
import org.jcnc.jnotepad.util.LogUtil;
import org.slf4j.Logger;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
/** /**
* 资源控制器用于加载程序所需的资源 * 资源控制器
* *
* @author gewuyou * @author gewuyou
*/ */
public class ResourceController { public class ResourceController {
private static final ResourceController INSTANCE = new ResourceController(); private static final ResourceController INSTANCE = new ResourceController();
Logger logger = LogUtil.getLogger(this.getClass());
private ResourceController() { private ResourceController() {
} }
@ -33,42 +23,6 @@ public class ResourceController {
// 1. 加载语言 // 1. 加载语言
LocalizationController.initLocal(); LocalizationController.initLocal();
// 2. 加载插件 // 2. 加载插件
loadPlugins(); PluginLoader.getInstance().loadPlugins();
}
/**
* 装载插件
*
* @since 2023/9/15 21:39
*/
public void loadPlugins() {
// 扫描并装载插件
scanLoadPlugins(PluginConfigController.getInstance().getPlungsPath());
}
/**
* 扫描插件
*
* @param pluginsPath 插件路径
* @apiNote 扫描所有插件更新配置文件中的插件信息
* @since 2023/9/16 0:21
*/
private void scanLoadPlugins(Path pluginsPath) {
if (!Files.isDirectory(pluginsPath)) {
try {
Files.createDirectory(pluginsPath);
} catch (IOException e) {
throw new AppException("这不是一个有效的路径!");
}
}
// 获取插件加载器
PluginLoader pluginLoader = PluginLoader.getInstance();
try (Stream<Path> pathStream = Files.walk(pluginsPath)) {
pathStream.filter(path -> path.toString().endsWith(".jar")).forEach(path -> pluginLoader.loadPluginByPath(path.toString()));
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
} }
} }

View File

@ -6,6 +6,7 @@ import org.jcnc.jnotepad.app.config.AppConfig;
import java.nio.file.Paths; import java.nio.file.Paths;
import static org.jcnc.jnotepad.common.constants.AppConstants.DEFAULT_PROPERTY; import static org.jcnc.jnotepad.common.constants.AppConstants.DEFAULT_PROPERTY;
import static org.jcnc.jnotepad.common.constants.AppConstants.PROGRAM_FILE_DIRECTORY;
/** /**
* 应用程序配置文件控制器 * 应用程序配置文件控制器
@ -23,12 +24,12 @@ public class AppConfigController extends BaseConfigController<AppConfig> {
/** /**
* 配置文件名 * 配置文件名
*/ */
public static final String CONFIG_NAME = "appConfig.json"; public static final String CONFIG_NAME = "JNotepadConfig.json";
private final String configDir; private final String configDir;
public AppConfigController() { public AppConfigController() {
configDir = Paths.get(System.getProperty(DEFAULT_PROPERTY), ".jnotepad", ROOT_CONFIG_DIR).toString(); configDir = Paths.get(System.getProperty(DEFAULT_PROPERTY), PROGRAM_FILE_DIRECTORY, systemConfigDir).toString();
loadConfig(); loadConfig();
} }

View File

@ -7,6 +7,8 @@ import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import static org.jcnc.jnotepad.common.constants.AppConstants.PROGRAM_FILE_DIRECTORY;
/** /**
* 插件控制器 * 插件控制器
* *
@ -24,8 +26,8 @@ public class PluginConfigController extends BaseConfigController<PluginConfig> {
private PluginConfigController() { private PluginConfigController() {
String rootPath = AppConfigController.getInstance().getConfig().getRootPath(); String rootPath = AppConfigController.getInstance().getConfig().getRootPath();
configDir = Paths.get(rootPath, ".jnotepad", ROOT_CONFIG_DIR).toString(); configDir = Paths.get(rootPath, PROGRAM_FILE_DIRECTORY, rootConfigDir).toString();
setPluginsDir(Paths.get(rootPath, ".jnotepad", "plugins").toString()); setPluginsDir(Paths.get(rootPath, PROGRAM_FILE_DIRECTORY, "plugins").toString());
loadConfig(); loadConfig();
} }

View File

@ -8,6 +8,7 @@ import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static org.jcnc.jnotepad.common.constants.AppConstants.PROGRAM_FILE_DIRECTORY;
import static org.jcnc.jnotepad.common.constants.TextConstants.CHINESE; import static org.jcnc.jnotepad.common.constants.TextConstants.CHINESE;
/** /**
@ -31,7 +32,7 @@ public class UserConfigController extends BaseConfigController<UserConfig> {
private String configDir; private String configDir;
private UserConfigController() { private UserConfigController() {
configDir = Paths.get(AppConfigController.getInstance().getConfig().getRootPath(), ".jnotepad", ROOT_CONFIG_DIR).toString(); configDir = Paths.get(AppConfigController.getInstance().getConfig().getRootPath(), PROGRAM_FILE_DIRECTORY, rootConfigDir).toString();
loadConfig(); loadConfig();
} }

View File

@ -15,7 +15,7 @@ import java.util.Optional;
* *
* @author 许轲 * @author 许轲
*/ */
public class Controller implements ControllerAble { public class Controller implements ControllerAble<List<String>> {
private static final ApplicationCacheManager CACHE_MANAGER = ApplicationCacheManager.getInstance(); private static final ApplicationCacheManager CACHE_MANAGER = ApplicationCacheManager.getInstance();
private static final Controller INSTANCE = new Controller(); private static final Controller INSTANCE = new Controller();

View File

@ -14,10 +14,13 @@ import java.io.*;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*; import java.util.*;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.jar.JarEntry; import java.util.jar.JarEntry;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.util.stream.Stream;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
/** /**
@ -244,4 +247,39 @@ public class PluginLoader {
logger.info("已加载插件:{}", pluginDescriptor.getName()); logger.info("已加载插件:{}", pluginDescriptor.getName());
return pluginClass; return pluginClass;
} }
/**
* 装载插件
*
* @since 2023/9/15 21:39
*/
public void loadPlugins() {
// 扫描并装载插件
scanLoadPlugins(PluginConfigController.getInstance().getPlungsPath());
}
/**
* 扫描插件
*
* @param pluginsPath 插件路径
* @apiNote 扫描所有插件更新配置文件中的插件信息
* @since 2023/9/16 0:21
*/
private void scanLoadPlugins(Path pluginsPath) {
if (!Files.isDirectory(pluginsPath)) {
try {
Files.createDirectory(pluginsPath);
} catch (IOException e) {
throw new AppException("这不是一个有效的路径!");
}
}
// 获取插件加载器
PluginLoader pluginLoader = PluginLoader.getInstance();
try (Stream<Path> pathStream = Files.walk(pluginsPath)) {
pathStream.filter(path -> path.toString().endsWith(".jar")).forEach(path -> pluginLoader.loadPluginByPath(path.toString()));
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
} }

View File

@ -15,6 +15,7 @@ import java.nio.file.StandardCopyOption;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Set;
import static org.kordamp.ikonli.antdesignicons.AntDesignIconsFilled.*; import static org.kordamp.ikonli.antdesignicons.AntDesignIconsFilled.*;
@ -170,7 +171,7 @@ public class FileUtil {
* @since 2023/10/5 12:18 * @since 2023/10/5 12:18
*/ */
private static void migrateFolder(File sourceFolder, File targetFolder) { public static void migrateFolder(File sourceFolder, File targetFolder) {
// 创建目标文件夹 // 创建目标文件夹
targetFolder.mkdirs(); targetFolder.mkdirs();
@ -197,4 +198,74 @@ public class FileUtil {
} }
} }
/**
* 迁移文件夹
*
* @param sourceFolder 源文件夹
* @param targetFolder 目标文件夹
* @param ignoredFolders 忽略的文件夹集合
* @param ignoredFiles 忽略的文件集合
* @since 2023/10/5 13:58
*/
public static void migrateFolder(File sourceFolder, File targetFolder, Set<File> ignoredFolders, Set<File> ignoredFiles) {
// 创建目标文件夹
targetFolder.mkdir();
// 获取源文件夹中的所有文件和文件夹
File[] files = sourceFolder.listFiles();
if (files != null) {
// 遍历源文件夹中的每个文件和文件夹
for (File file : files) {
// 如果是文件夹且不是忽略的文件夹递归调用自身进行迁移
if (file.isDirectory() && !ignoredFolders.contains(file)) {
migrateFolder(targetFolder, ignoredFolders, ignoredFiles, file);
continue;
} }
// 如果是文件且不是忽略的文件将文件复制到目标文件夹中
if (!file.isDirectory() && !ignoredFiles.contains(file)) {
migrateFile(targetFolder, file);
}
}
}
}
/**
* 迁移文件
*
* @param targetFolder 目标文件夹
* @param file 文件
*/
public static void migrateFile(File targetFolder, File file) {
Path sourceFilePath = file.toPath();
Path targetFilePath = new File(targetFolder, file.getName()).toPath();
try {
Files.copy(sourceFilePath, targetFilePath, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new AppException(e);
}
// 删除源文件
try {
Files.delete(file.toPath());
} catch (IOException e) {
throw new AppException(e);
}
}
/**
* 迁移文件夹
*
* @param targetFolder 目标文件夹
* @param ignoredFolders 忽略的文件夹集合
* @param ignoredFiles 忽略的文件集合
* @param file 文件
*/
private static void migrateFolder(File targetFolder, Set<File> ignoredFolders, Set<File> ignoredFiles, File file) {
migrateFolder(file, new File(targetFolder, file.getName()), ignoredFolders, ignoredFiles);
// 调用完毕删除当前目录
try {
Files.deleteIfExists(file.toPath());
} catch (IOException e) {
throw new AppException(e);
}
}
}