commit
850e5b509f
@ -10,8 +10,11 @@ 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.controller.ResourceController;
|
||||
import org.jcnc.jnotepad.controller.config.AppConfigController;
|
||||
import org.jcnc.jnotepad.controller.i18n.LocalizationController;
|
||||
import org.jcnc.jnotepad.controller.manager.Controller;
|
||||
import org.jcnc.jnotepad.plugin.PluginManager;
|
||||
import org.jcnc.jnotepad.util.UiUtil;
|
||||
import org.jcnc.jnotepad.views.manager.ViewManager;
|
||||
|
||||
@ -64,6 +67,7 @@ public class LunchApp extends Application {
|
||||
@Override
|
||||
public void start(Stage primaryStage) {
|
||||
SCENE.getStylesheets().add(Objects.requireNonNull(getClass().getResource("/css/styles.css")).toExternalForm());
|
||||
// 初始化UI组件
|
||||
initUiComponents();
|
||||
UiResourceBundle.bindStringProperty(primaryStage.titleProperty(), TextConstants.TITLE);
|
||||
|
||||
@ -83,7 +87,8 @@ public class LunchApp extends Application {
|
||||
// 2. 加载组件
|
||||
ViewManager viewManager = ViewManager.getInstance(SCENE);
|
||||
viewManager.initScreen(SCENE);
|
||||
|
||||
// 3. 加载资源
|
||||
ResourceController.getInstance().loadResources();
|
||||
// 使用线程池加载关联文件并创建文本区域
|
||||
List<String> rawParameters = getParameters().getRaw();
|
||||
Controller.getInstance().openAssociatedFileAndCreateTextArea(rawParameters);
|
||||
@ -91,6 +96,10 @@ public class LunchApp extends Application {
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
AppConfigController instance = AppConfigController.getInstance();
|
||||
// 刷新插件配置文件
|
||||
instance.getAppConfig().setPlugins(PluginManager.getInstance().getPluginInfos());
|
||||
instance.writeAppConfig();
|
||||
// 关闭线程池
|
||||
threadPool.shutdownNow();
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package org.jcnc.jnotepad.app.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.jcnc.jnotepad.model.entity.PluginInfo;
|
||||
import org.jcnc.jnotepad.model.entity.ShortcutKey;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -24,6 +25,8 @@ public class AppConfig {
|
||||
private boolean textWrap;
|
||||
private List<ShortcutKey> shortcutKey;
|
||||
|
||||
private List<PluginInfo> plugins;
|
||||
|
||||
/**
|
||||
* 生成默认应用配置对象。
|
||||
*
|
||||
@ -43,11 +46,19 @@ public class AppConfig {
|
||||
shortcutKeys.add(createShortcutKey("openConfigItem", ALT_S));
|
||||
shortcutKeys.add(createShortcutKey("addItem", ""));
|
||||
shortcutKeys.add(createShortcutKey("countItem", ""));
|
||||
|
||||
myData.setShortcutKey(shortcutKeys);
|
||||
myData.setPlugins(new ArrayList<>());
|
||||
return myData;
|
||||
}
|
||||
|
||||
public List<PluginInfo> getPlugins() {
|
||||
return plugins;
|
||||
}
|
||||
|
||||
public void setPlugins(List<PluginInfo> plugins) {
|
||||
this.plugins = plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 ShortcutKey 对象。
|
||||
*
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
package org.jcnc.jnotepad.controller;
|
||||
|
||||
import org.jcnc.jnotepad.controller.config.AppConfigController;
|
||||
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;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 资源控制器:用于加载程序所需的资源
|
||||
*
|
||||
* @author gewuyou
|
||||
*/
|
||||
public class ResourceController {
|
||||
private static final ResourceController INSTANCE = new ResourceController();
|
||||
Logger logger = LogUtil.getLogger(this.getClass());
|
||||
|
||||
private ResourceController() {
|
||||
}
|
||||
|
||||
|
||||
public static ResourceController getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public void loadResources() {
|
||||
loadPlugins();
|
||||
}
|
||||
|
||||
/**
|
||||
* 装载插件
|
||||
*
|
||||
* @since 2023/9/15 21:39
|
||||
*/
|
||||
public void loadPlugins() {
|
||||
// 扫描并装载插件
|
||||
scanLoadPlugins(AppConfigController.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -32,10 +32,13 @@ public class AppConfigController {
|
||||
private static final Logger logger = LogUtil.getLogger(AppConfigController.class);
|
||||
private static final AppConfigController INSTANCE = new AppConfigController();
|
||||
private AppConfig appConfig;
|
||||
private String dir;
|
||||
private static final String DEFAULT_PROPERTY = "user.home";
|
||||
private String appConfigDir;
|
||||
private String pluginsDir;
|
||||
|
||||
private AppConfigController() {
|
||||
setDir(Paths.get(System.getProperty("user.home"), ".jnotepad").toString());
|
||||
setAppConfigDir(Paths.get(System.getProperty(DEFAULT_PROPERTY), ".jnotepad").toString());
|
||||
setPluginsDir(Paths.get(System.getProperty(DEFAULT_PROPERTY), ".jnotepad", "plugins").toString());
|
||||
loadConfig();
|
||||
}
|
||||
|
||||
@ -54,7 +57,6 @@ public class AppConfigController {
|
||||
public void loadConfig() {
|
||||
createConfigIfNotExists();
|
||||
Path configPath = getConfigPath();
|
||||
|
||||
try {
|
||||
logger.info("正在加载配置文件...");
|
||||
// 存在则加载
|
||||
@ -82,7 +84,7 @@ public class AppConfigController {
|
||||
private void writeAppConfig(AppConfig appConfig) {
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(getConfigPath().toString()))) {
|
||||
if (appConfig == null) {
|
||||
appConfig = createShortcutKeyJson();
|
||||
appConfig = createConfigJson();
|
||||
}
|
||||
writer.write(JsonUtil.toJsonString(appConfig));
|
||||
} catch (Exception e) {
|
||||
@ -99,7 +101,7 @@ public class AppConfigController {
|
||||
if (configPath.toFile().exists()) {
|
||||
return;
|
||||
}
|
||||
File directory = new File(dir);
|
||||
File directory = new File(appConfigDir);
|
||||
if (!directory.exists()) {
|
||||
directory.mkdirs();
|
||||
}
|
||||
@ -112,10 +114,14 @@ public class AppConfigController {
|
||||
* @return 配置文件的路径
|
||||
*/
|
||||
public Path getConfigPath() {
|
||||
return Paths.get(getDir(), CONFIG_NAME);
|
||||
return Paths.get(getAppConfigDir(), CONFIG_NAME);
|
||||
}
|
||||
|
||||
private AppConfig createShortcutKeyJson() {
|
||||
public Path getPlungsPath() {
|
||||
return Paths.get(getPluginsDir());
|
||||
}
|
||||
|
||||
private AppConfig createConfigJson() {
|
||||
return AppConfig.generateDefaultAppConfig();
|
||||
}
|
||||
|
||||
@ -169,15 +175,23 @@ public class AppConfigController {
|
||||
*
|
||||
* @return 所在目录
|
||||
*/
|
||||
public String getDir() {
|
||||
return dir;
|
||||
public String getAppConfigDir() {
|
||||
return appConfigDir;
|
||||
}
|
||||
|
||||
public void setDir(String dir) {
|
||||
this.dir = dir;
|
||||
public void setAppConfigDir(String appConfigDir) {
|
||||
this.appConfigDir = appConfigDir;
|
||||
}
|
||||
|
||||
private AppConfig getAppConfig() {
|
||||
public String getPluginsDir() {
|
||||
return pluginsDir;
|
||||
}
|
||||
|
||||
public void setPluginsDir(String pluginsDir) {
|
||||
this.pluginsDir = pluginsDir;
|
||||
}
|
||||
|
||||
public AppConfig getAppConfig() {
|
||||
return appConfig;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
package org.jcnc.jnotepad.model.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.jcnc.jnotepad.plugin.interfaces.Plugin;
|
||||
|
||||
/**
|
||||
* 插件信息
|
||||
*
|
||||
@ -18,11 +21,24 @@ public class PluginInfo {
|
||||
* 启用状态
|
||||
*/
|
||||
private boolean enabled;
|
||||
/**
|
||||
* 作者名称
|
||||
*/
|
||||
private String author;
|
||||
/**
|
||||
* 类别
|
||||
*/
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 主类名称
|
||||
*/
|
||||
private String mainClass;
|
||||
/**
|
||||
* 插件类
|
||||
*/
|
||||
@JsonIgnore
|
||||
private Plugin plugin;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
@ -55,4 +71,28 @@ public class PluginInfo {
|
||||
public void setMainClass(String mainClass) {
|
||||
this.mainClass = mainClass;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public String getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public void setCategory(String category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public Plugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public void setPlugin(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package org.jcnc.jnotepad.plugin;
|
||||
|
||||
import org.jcnc.jnotepad.controller.config.AppConfigController;
|
||||
import org.jcnc.jnotepad.exception.AppException;
|
||||
import org.jcnc.jnotepad.model.entity.PluginInfo;
|
||||
import org.jcnc.jnotepad.plugin.interfaces.Plugin;
|
||||
@ -12,6 +13,7 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarFile;
|
||||
@ -31,7 +33,7 @@ public class PluginLoader {
|
||||
*
|
||||
* @param pluginJar jar 包
|
||||
*/
|
||||
private static PluginInfo readPlugin(File pluginJar) throws IOException {
|
||||
public static PluginInfo readPlugin(File pluginJar) throws IOException {
|
||||
InputStream is;
|
||||
StringBuilder sb;
|
||||
try (JarFile jarFile = new JarFile(pluginJar)) {
|
||||
@ -53,24 +55,103 @@ public class PluginLoader {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查插件
|
||||
*
|
||||
* @param configPluginInfos 配置文件插件信息
|
||||
* @param pluginInfo 插件信息类
|
||||
* @param pluginInfos 插件信息集合
|
||||
* @return boolean 是否检查通过
|
||||
* @apiNote
|
||||
* @since 2023/9/16 14:04
|
||||
*/
|
||||
private static boolean checkPlugin(List<PluginInfo> configPluginInfos, PluginInfo pluginInfo, List<PluginInfo> pluginInfos) {
|
||||
// 如果应用程序配置文件为空则默认插件被禁用
|
||||
if (configPluginInfos.isEmpty()) {
|
||||
return disabledByDefault(configPluginInfos, pluginInfo, pluginInfos);
|
||||
}
|
||||
// 如果应用程序配置文件中该插件禁用则不加载
|
||||
for (PluginInfo configPluginInfo : configPluginInfos) {
|
||||
if (disableDoNotLoad(pluginInfo, pluginInfos, configPluginInfo)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// 判断该插件是否已经加载
|
||||
return loaded(pluginInfo, pluginInfos);
|
||||
}
|
||||
|
||||
private static boolean loaded(PluginInfo pluginInfo, List<PluginInfo> pluginInfos) {
|
||||
Iterator<PluginInfo> iterator = pluginInfos.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
PluginInfo plugin = iterator.next();
|
||||
if ((plugin.getName() + plugin.getAuthor()).equals(pluginInfo.getName() + pluginInfo.getAuthor())) {
|
||||
if (plugin.getVersion().equals(pluginInfo.getVersion())) {
|
||||
return true;
|
||||
}
|
||||
// 如果当前插件版本更低则更新
|
||||
if (plugin.getVersion().compareTo(pluginInfo.getVersion()) < 0) {
|
||||
// 删除当前的插件
|
||||
iterator.remove();
|
||||
} else {
|
||||
throw new AppException("当前加载的插件版本低于本地版本!");
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean disableDoNotLoad(PluginInfo pluginInfo, List<PluginInfo> pluginInfos, PluginInfo configPluginInfo) {
|
||||
if ((configPluginInfo.getName() + configPluginInfo.getAuthor()).equals(pluginInfo.getName() + pluginInfo.getAuthor()) && !configPluginInfo.isEnabled()) {
|
||||
pluginInfo.setEnabled(false);
|
||||
pluginInfos.add(pluginInfo);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean disabledByDefault(List<PluginInfo> configPluginInfos, PluginInfo pluginInfo, List<PluginInfo> pluginInfos) {
|
||||
pluginInfo.setEnabled(false);
|
||||
pluginInfos.add(pluginInfo);
|
||||
configPluginInfos.add(pluginInfo);
|
||||
AppConfigController.getInstance().writeAppConfig();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载插件
|
||||
*
|
||||
* @param pluginFilePath 插件文件的路径
|
||||
*/
|
||||
public void loadPlugins(String pluginFilePath) {
|
||||
PluginManager pluginManager = PluginManager.getInstance();
|
||||
List<Plugin> plugins = pluginManager.getPlugins();
|
||||
Map<String, List<String>> categories = pluginManager.getLoadedPluginsByCategory();
|
||||
Map<String, PluginInfo> pluginInfos = pluginManager.getPluginInfos();
|
||||
public void loadPluginByPath(String pluginFilePath) {
|
||||
File file = new File(pluginFilePath);
|
||||
if (file.exists() && file.isFile()) {
|
||||
loadPluginByFile(file, AppConfigController.getInstance().getAppConfig().getPlugins());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件加载插件
|
||||
*
|
||||
* @param pluginJar 插件jar包
|
||||
* @param configPluginInfos 配置文件插件信息集合
|
||||
* @apiNote
|
||||
* @since 2023/9/16 14:05
|
||||
*/
|
||||
public void loadPluginByFile(File pluginJar, List<PluginInfo> configPluginInfos) {
|
||||
PluginManager pluginManager = PluginManager.getInstance();
|
||||
Map<String, List<String>> categories = pluginManager.getLoadedPluginsByCategory();
|
||||
List<PluginInfo> pluginInfos = pluginManager.getPluginInfos();
|
||||
if (pluginJar.exists() && pluginJar.isFile()) {
|
||||
try {
|
||||
PluginInfo pluginInfo = readPlugin(file);
|
||||
pluginInfos.put(pluginInfo.getName(), pluginInfo);
|
||||
PluginInfo pluginInfo = readPlugin(pluginJar);
|
||||
// 检查插件状态
|
||||
if (checkPlugin(configPluginInfos, pluginInfo, pluginInfos)) {
|
||||
return;
|
||||
}
|
||||
pluginInfo.setEnabled(true);
|
||||
pluginInfos.add(pluginInfo);
|
||||
// 创建URLClassLoader以加载Jar文件中的类
|
||||
Class<?> pluginClass;
|
||||
try (URLClassLoader classLoader = new URLClassLoader(new URL[]{file.toURI().toURL()})) {
|
||||
try (URLClassLoader classLoader = new URLClassLoader(new URL[]{pluginJar.toURI().toURL()})) {
|
||||
logger.info("{}", pluginInfo.getMainClass());
|
||||
pluginClass = classLoader.loadClass(pluginInfo.getMainClass());
|
||||
}
|
||||
if (pluginClass == null) {
|
||||
@ -78,11 +159,8 @@ public class PluginLoader {
|
||||
}
|
||||
Plugin plugin;
|
||||
plugin = (Plugin) pluginClass.getDeclaredConstructor().newInstance();
|
||||
plugins.add(plugin);
|
||||
// 添加插件到类别中
|
||||
String categoryName = plugin.getCategoryName();
|
||||
String displayName = plugin.getDisplayName();
|
||||
categories.computeIfAbsent(categoryName, k -> new ArrayList<>()).add(displayName);
|
||||
pluginInfo.setPlugin(plugin);
|
||||
categories.computeIfAbsent(pluginInfo.getCategory(), k -> new ArrayList<>()).add(pluginInfo.getName());
|
||||
} catch (IOException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
|
||||
throw new AppException(e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
@ -92,7 +170,7 @@ public class PluginLoader {
|
||||
}
|
||||
|
||||
} else {
|
||||
LogUtil.getLogger(this.getClass()).info("PluginInfo file not found: {}", pluginFilePath);
|
||||
LogUtil.getLogger(this.getClass()).info("PluginInfo file not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,14 +1,22 @@
|
||||
package org.jcnc.jnotepad.plugin;
|
||||
|
||||
import org.jcnc.jnotepad.common.manager.ThreadPoolManager;
|
||||
import org.jcnc.jnotepad.controller.config.AppConfigController;
|
||||
import org.jcnc.jnotepad.model.entity.PluginInfo;
|
||||
import org.jcnc.jnotepad.plugin.interfaces.Plugin;
|
||||
import org.jcnc.jnotepad.util.LogUtil;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.jcnc.jnotepad.plugin.PluginLoader.readPlugin;
|
||||
|
||||
/**
|
||||
* 插件管理器
|
||||
@ -21,10 +29,6 @@ import java.util.Map;
|
||||
public class PluginManager {
|
||||
private static final PluginManager INSTANCE = new PluginManager();
|
||||
Logger logger = LogUtil.getLogger(this.getClass());
|
||||
/**
|
||||
* 插件集合
|
||||
*/
|
||||
private final List<Plugin> plugins = new ArrayList<>();
|
||||
/**
|
||||
* 插件类别
|
||||
*/
|
||||
@ -32,8 +36,7 @@ public class PluginManager {
|
||||
/**
|
||||
* 插件信息
|
||||
*/
|
||||
|
||||
private final Map<String, PluginInfo> pluginInfos = new HashMap<>();
|
||||
private final List<PluginInfo> pluginInfos = new ArrayList<>();
|
||||
|
||||
private PluginManager() {
|
||||
|
||||
@ -47,30 +50,89 @@ public class PluginManager {
|
||||
/**
|
||||
* 卸载插件
|
||||
*
|
||||
* @param pluginClassName 插件类名
|
||||
* @param pluginInfo 插件信息类
|
||||
* @since 2023/9/11 12:28
|
||||
*/
|
||||
public void unloadPlugin(String pluginClassName) {
|
||||
//todo Unload the plugin and remove it from the list
|
||||
public void unloadPlugin(PluginInfo pluginInfo) {
|
||||
// 删除集合中的插件信息
|
||||
pluginInfos.remove(pluginInfo);
|
||||
AppConfigController instance = AppConfigController.getInstance();
|
||||
instance.getAppConfig().getPlugins().remove(pluginInfo);
|
||||
// 刷新配置
|
||||
instance.writeAppConfig();
|
||||
// 删除本地插件jar包
|
||||
Path plungsPath = instance.getPlungsPath();
|
||||
try (Stream<Path> pathStream = Files.walk(plungsPath)) {
|
||||
pathStream.filter(path -> path.toString().endsWith(".jar")).forEach(path -> {
|
||||
try {
|
||||
File pluginJar = new File(path.toString());
|
||||
PluginInfo temp = readPlugin(pluginJar);
|
||||
if ((temp.getName() + temp.getAuthor()).equals(pluginInfo.getName() + pluginInfo.getAuthor())) {
|
||||
Files.delete(pluginJar.toPath());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
ThreadPoolManager.threadContSelfSubtracting();
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用插件
|
||||
*
|
||||
* @param pluginClassName 禁用某个插件
|
||||
* @param pluginInfo 需要禁用的某个插件的插件类
|
||||
* @apiNote
|
||||
* @since 2023/9/11 12:34
|
||||
*/
|
||||
public void disablePlugIn(String pluginClassName) {
|
||||
//todo Disable the plugin
|
||||
public void disablePlugIn(PluginInfo pluginInfo) {
|
||||
pluginInfo.setEnabled(false);
|
||||
pluginInfo.setPlugin(null);
|
||||
ThreadPoolManager.getThreadPool().submit(() -> {
|
||||
AppConfigController instance = AppConfigController.getInstance();
|
||||
instance.getAppConfig().getPlugins().forEach(plugin -> {
|
||||
if ((pluginInfo.getName() + pluginInfo.getAuthor()).equals(plugin.getName() + plugin.getAuthor())) {
|
||||
plugin.setEnabled(false);
|
||||
}
|
||||
});
|
||||
instance.writeAppConfig();
|
||||
ThreadPoolManager.threadContSelfSubtracting();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化所有启用的插件
|
||||
*/
|
||||
public void initializePlugins() {
|
||||
for (PluginInfo pluginInfo : pluginInfos) {
|
||||
if (pluginInfo.isEnabled()) {
|
||||
pluginInfo.getPlugin().initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行插件
|
||||
*
|
||||
* @param pluginInfo 需要执行的插件的信息类
|
||||
* @apiNote
|
||||
* @since 2023/9/16 14:58
|
||||
*/
|
||||
public void executePlugin(PluginInfo pluginInfo) {
|
||||
pluginInfo.getPlugin().execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行加载的插件
|
||||
* todo 待移除
|
||||
*/
|
||||
public void executePlugins() {
|
||||
for (Plugin plugin : plugins) {
|
||||
plugin.execute();
|
||||
for (PluginInfo pluginInfo : pluginInfos) {
|
||||
if (pluginInfo.isEnabled()) {
|
||||
pluginInfo.getPlugin().execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,11 +145,7 @@ public class PluginManager {
|
||||
return categories;
|
||||
}
|
||||
|
||||
public List<Plugin> getPlugins() {
|
||||
return plugins;
|
||||
}
|
||||
|
||||
public Map<String, PluginInfo> getPluginInfos() {
|
||||
public List<PluginInfo> getPluginInfos() {
|
||||
return pluginInfos;
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,13 +17,14 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 插件演示类
|
||||
* 插件管理界面
|
||||
* <p>
|
||||
* 用于演示插件加载和执行的界面。
|
||||
*
|
||||
* @author luke
|
||||
* @author luke gewuyou
|
||||
*/
|
||||
public class PluginDemo {
|
||||
public class PluginManagerInterface {
|
||||
private static final PluginManagerInterface INSTANCE = new PluginManagerInterface();
|
||||
Logger logger = LogUtil.getLogger(this.getClass());
|
||||
|
||||
/**
|
||||
@ -53,34 +54,8 @@ public class PluginDemo {
|
||||
primaryStage.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建加载插件的按钮
|
||||
*
|
||||
* @param primaryStage JavaFX的主舞台
|
||||
* @param fileChooser 文件选择器
|
||||
* @param pluginManager 插件管理器
|
||||
* @return 加载插件的按钮
|
||||
*/
|
||||
private Button createLoadButton(Stage primaryStage, FileChooser fileChooser, PluginManager pluginManager) {
|
||||
Button loadButton = new Button("加载插件");
|
||||
loadButton.setOnAction(event -> {
|
||||
try {
|
||||
File selectedFile = fileChooser.showOpenDialog(primaryStage);
|
||||
if (selectedFile != null) {
|
||||
String pluginFilePath = selectedFile.getAbsolutePath();
|
||||
PluginLoader.getInstance().loadPlugins(pluginFilePath);
|
||||
|
||||
// 更新插件信息显示
|
||||
displayPluginInfo(primaryStage, pluginManager);
|
||||
} else {
|
||||
PopUpUtil.infoAlert(null, null, "未找到插件!", null, null);
|
||||
logger.info("未找到插件!");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("加载插件失败!", e);
|
||||
}
|
||||
});
|
||||
return loadButton;
|
||||
public static PluginManagerInterface getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,4 +84,34 @@ public class PluginDemo {
|
||||
infoStage.initOwner(primaryStage);
|
||||
infoStage.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建加载插件的按钮
|
||||
*
|
||||
* @param primaryStage JavaFX的主舞台
|
||||
* @param fileChooser 文件选择器
|
||||
* @param pluginManager 插件管理器
|
||||
* @return 加载插件的按钮
|
||||
*/
|
||||
private Button createLoadButton(Stage primaryStage, FileChooser fileChooser, PluginManager pluginManager) {
|
||||
Button loadButton = new Button("加载插件");
|
||||
loadButton.setOnAction(event -> {
|
||||
try {
|
||||
File selectedFile = fileChooser.showOpenDialog(primaryStage);
|
||||
if (selectedFile != null) {
|
||||
String pluginFilePath = selectedFile.getAbsolutePath();
|
||||
PluginLoader.getInstance().loadPluginByPath(pluginFilePath);
|
||||
|
||||
// 更新插件信息显示
|
||||
displayPluginInfo(primaryStage, pluginManager);
|
||||
} else {
|
||||
PopUpUtil.infoAlert(null, null, "未找到插件!", null, null);
|
||||
logger.info("未找到插件!");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("加载插件失败!", e);
|
||||
}
|
||||
});
|
||||
return loadButton;
|
||||
}
|
||||
}
|
||||
@ -8,18 +8,9 @@ import java.util.Map;
|
||||
* <p>
|
||||
* 描述插件的基本功能。
|
||||
*
|
||||
* @author luke
|
||||
* @author luke gewuyou
|
||||
*/
|
||||
public interface Plugin extends PluginCategory {
|
||||
|
||||
/**
|
||||
* 获取插件的显示名称
|
||||
*
|
||||
* @return 插件的显示名称
|
||||
*/
|
||||
String getDisplayName();
|
||||
|
||||
|
||||
public interface Plugin {
|
||||
/**
|
||||
* 初始化插件
|
||||
*/
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
package org.jcnc.jnotepad.plugin.interfaces;
|
||||
|
||||
/**
|
||||
* 插件类别接口
|
||||
* <p>
|
||||
* 描述插件的类别信息。
|
||||
*
|
||||
* @author luke
|
||||
*/
|
||||
public interface PluginCategory {
|
||||
|
||||
/**
|
||||
* 获取插件类别的名称
|
||||
*
|
||||
* @return 插件类别的名称
|
||||
*/
|
||||
String getCategoryName();
|
||||
}
|
||||
@ -12,6 +12,7 @@ import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.stage.Stage;
|
||||
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;
|
||||
@ -31,6 +32,7 @@ public class SetStage extends Stage {
|
||||
public static final String GENERAL_SETTING_2 = "常规设置项2";
|
||||
public static final String APPEARANCE_SETTING_1 = "外观设置项1";
|
||||
public static final String APPEARANCE_SETTING_2 = "外观设置项2";
|
||||
public static final String PLUGINS = "插件";
|
||||
public static final String SECURITY_SETTING_1 = "安全设置项1";
|
||||
public static final String SECURITY_SETTING_2 = "安全设置项2";
|
||||
|
||||
@ -92,7 +94,6 @@ public class SetStage extends Stage {
|
||||
applicationButton.getStyleClass().addAll(Styles.SMALL);
|
||||
bottomBox.getChildren().addAll(confirmButton, cancelButton, applicationButton);
|
||||
|
||||
|
||||
BorderPane root = new BorderPane();
|
||||
root.setCenter(splitPane);
|
||||
root.setBottom(bottomBox);
|
||||
@ -136,6 +137,9 @@ public class SetStage extends Stage {
|
||||
|
||||
TreeItem<String> securityItem1 = new TreeItem<>("安全设置项1");
|
||||
TreeItem<String> securityItem2 = new TreeItem<>("安全设置项2");
|
||||
|
||||
TreeItem<String> pluginsItem = new TreeItem<>(PLUGINS);
|
||||
|
||||
securityItem.getChildren().add(securityItem1);
|
||||
securityItem.getChildren().add(securityItem2);
|
||||
|
||||
@ -147,6 +151,7 @@ public class SetStage extends Stage {
|
||||
root.getChildren().add(appearanceItem);
|
||||
root.getChildren().add(securityItem);
|
||||
root.getChildren().add(developerItem);
|
||||
root.getChildren().add(pluginsItem);
|
||||
TreeView<String> treeView = new TreeView<>(root);
|
||||
treeView.setShowRoot(false);
|
||||
|
||||
@ -170,10 +175,21 @@ public class SetStage extends Stage {
|
||||
case SECURITY_SETTING_1 -> createSecuritySettingsLayout1();
|
||||
case SECURITY_SETTING_2 -> createSecuritySettingsLayout2();
|
||||
case DEVELOPER_DEBUG_PAGE -> createDevelopersDebugPageLayouts();
|
||||
case PLUGINS -> createPluginsLayout();
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private Node createPluginsLayout() {
|
||||
VBox generalLayout = new VBox(10);
|
||||
generalLayout.setPadding(new Insets(25));
|
||||
PluginManagerInterface pluginManagerInterface = new PluginManagerInterface();
|
||||
Stage stage = new Stage();
|
||||
stage.getIcons().add(UiUtil.getAppIcon());
|
||||
pluginManagerInterface.start(stage);
|
||||
return generalLayout;
|
||||
}
|
||||
|
||||
private Node createDevelopersDebugPageLayouts() {
|
||||
VBox generalLayout = new VBox(10);
|
||||
generalLayout.setPadding(new Insets(25));
|
||||
|
||||
@ -10,8 +10,9 @@ import org.jcnc.jnotepad.controller.event.handler.menubar.*;
|
||||
import org.jcnc.jnotepad.controller.event.handler.util.SetBtn;
|
||||
import org.jcnc.jnotepad.controller.i18n.LocalizationController;
|
||||
import org.jcnc.jnotepad.model.entity.ShortcutKey;
|
||||
import org.jcnc.jnotepad.plugin.PluginDemo;
|
||||
import org.jcnc.jnotepad.plugin.PluginManagerInterface;
|
||||
import org.jcnc.jnotepad.util.LogUtil;
|
||||
import org.jcnc.jnotepad.util.UiUtil;
|
||||
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.left.sidebar.tools.SidebarToolBar;
|
||||
@ -267,8 +268,10 @@ public class TopMenuBar extends MenuBar {
|
||||
|
||||
addItem = new MenuItem();
|
||||
addItem.setOnAction(event -> {
|
||||
PluginDemo pluginDemo = new PluginDemo();
|
||||
pluginDemo.start(new Stage());
|
||||
PluginManagerInterface pluginManagerInterface = PluginManagerInterface.getInstance();
|
||||
Stage stage = new Stage();
|
||||
stage.getIcons().add(UiUtil.getAppIcon());
|
||||
pluginManagerInterface.start(stage);
|
||||
});
|
||||
UiResourceBundle.bindStringProperty(addItem.textProperty(), ADD_PLUGIN);
|
||||
itemMap.put("addItem", addItem);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user