feat(box): 添加命令行文件解析功能并优化主题和语言管理- 新增 ArgsParser 类用于解析命令行参数中的文件路径

- 添加 OpenFileEvents 事件类用于处理打开文件请求
- 更新 AxisInnovatorsBox 类,支持命令行文件解析
- 重构 LanguageManager 类,优化语言合并和加载逻辑
- 更新 MainWindow 类,改进界面样式和滚动条UI
- 修改 PluginDescriptor 类,增加注册名字段
This commit is contained in:
tzdwindows 7
2025-02-21 20:55:10 +08:00
parent 97b071ece8
commit 701dfcfb47
20 changed files with 614 additions and 436 deletions

View File

@@ -1,6 +1,7 @@
package com.axis.innovators.box;
import com.axis.innovators.box.events.GlobalEventBus;
import com.axis.innovators.box.events.OpenFileEvents;
import com.axis.innovators.box.events.StartupEvent;
import com.axis.innovators.box.gui.*;
import com.axis.innovators.box.plugins.PluginDescriptor;
@@ -9,6 +10,7 @@ import com.axis.innovators.box.register.RegistrationSettingsItem;
import com.axis.innovators.box.register.RegistrationTool;
import com.axis.innovators.box.register.RegistrationTopic;
import com.axis.innovators.box.register.LanguageManager;
import com.axis.innovators.box.tools.ArgsParser;
import com.axis.innovators.box.tools.LibraryLoad;
import com.axis.innovators.box.tools.StateManager;
import com.axis.innovators.box.tools.SystemInfoUtil;
@@ -22,7 +24,9 @@ import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* 主类
@@ -52,13 +56,14 @@ public class AxisInnovatorsBox {
private final List<WindowsJDialog> windowsJDialogList = new ArrayList<>();
private final StateManager stateManager = new StateManager();
public AxisInnovatorsBox(String[] args){
public AxisInnovatorsBox(String[] args) {
this.args = args;
}
static {
try {
LibraryLoad.loadLibrary("FridaNative");
LibraryLoad.loadLibrary("ThrowSafely");
LM.loadLibrary(LM.CUDA);
} catch (Exception e) {
logger.error("Failed to load the 'FridaNative' library", e);
@@ -218,6 +223,9 @@ public class AxisInnovatorsBox {
dialog.setVisible(true);
}
/**
* 初始化Log4j2
*/
public void initLog4j2() {
Log4j2OutputStream.redirectSystemStreams();
@@ -235,9 +243,11 @@ public class AxisInnovatorsBox {
logger.info("ClassLoader.getSystemClassLoader(): {}", ClassLoader.getSystemClassLoader());
}
/**
* 设置主题
*/
private void setTopic() {
try {
main.registrationTopic.addTopic(UIManager.getSystemLookAndFeelClassName(),
LanguageManager.getLoadedLanguages().getText("default_theme.system.topicName"),
LanguageManager.getLoadedLanguages().getText("default_theme.default.tip"),
@@ -317,43 +327,59 @@ public class AxisInnovatorsBox {
isWindow = true;
}
public static void main(String[] args) {
public static void run(String[] args) {
main = new AxisInnovatorsBox(args);
main.initLog4j2();
main.setTopic();
try {
main.initLog4j2();
main.setTopic();
main.thread = new Thread(() -> {
try {
// 主任务1加载插件
logger.info("Loaded plugins Started");
main.progressBarManager.updateMainProgress(++main.completedTasks);
PluginLoader.loadPlugins();
logger.info("Loaded plugins End");
List<Map<String, String>> validFiles = ArgsParser.parseArgs(args);
main.progressBarManager.close();
SwingUtilities.invokeLater(() -> {
try {
main.ex = new MainWindow();
GlobalEventBus.EVENT_BUS.post(new StartupEvent(main));
main.runWindow();
} catch (Exception e) {
logger.error("There was a problem starting the main thread", e);
main.ex.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.organizingCrashReports(e);
throw new RuntimeException(e);
}
});
} catch (Exception e) {
logger.error("Failed to load plugins", e);
main.ex.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.organizingCrashReports(e);
throw new RuntimeException(e);
for (Map<String, String> fileInfo : validFiles) {
OpenFileEvents openFileEvents = new OpenFileEvents(fileInfo.get("path"), fileInfo.get("extension"));
GlobalEventBus.EVENT_BUS.post(openFileEvents);
if (!openFileEvents.isContinue()) {
return;
}
}
});
main.thread.setName("Main Thread");
main.thread.start();
main.thread = new Thread(() -> {
try {
// 主任务1加载插件
logger.info("Loaded plugins Started");
main.progressBarManager.updateMainProgress(++main.completedTasks);
PluginLoader.loadPlugins();
logger.info("Loaded plugins End");
main.progressBarManager.close();
SwingUtilities.invokeLater(() -> {
try {
main.ex = new MainWindow();
GlobalEventBus.EVENT_BUS.post(new StartupEvent(main));
main.runWindow();
} catch (Exception e) {
logger.error("There was a problem starting the main thread", e);
main.ex.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.organizingCrashReports(e);
throw new RuntimeException(e);
}
});
} catch (Exception e) {
logger.error("Failed to load plugins", e);
main.ex.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.organizingCrashReports(e);
throw new RuntimeException(e);
}
});
main.thread.setName("Main Thread");
main.thread.start();
} catch (Exception e) {
logger.error("In unexpected errors", e);
main.ex.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.organizingCrashReports(e);
throw new RuntimeException(e);
}
}
public void runWindow() {

View File

@@ -10,7 +10,12 @@ import com.axis.innovators.box.register.LanguageManager;
public class Main {
public static void main(String[] args) {
FolderCleaner.cleanFolder(FolderCreator.getLogsFolder(), 10);
LanguageManager.loadSavedLanguage();
AxisInnovatorsBox.main(args);
if (LanguageManager.getLoadedLanguages() == null){
LanguageManager.loadLanguage("system:zh_CN");
}
AxisInnovatorsBox.run(args);
}
}

View File

@@ -0,0 +1,53 @@
package com.axis.innovators.box.events;
import java.io.File;
/**
* 当程序接受到了文件时触发
* @author tzdwindows 7
*/
public class OpenFileEvents {
private final File filePath;
private final String extension;
private boolean isContinue;
/**
* 构造函数
* @param filePath 文件路径
* @param extension 文件后缀
*/
public OpenFileEvents(String filePath, String extension) {
this.filePath = new File(filePath);
this.extension = extension;
isContinue = true;
}
/**
* 获取文件路径
* @return 文件路径
*/
public File getFilePath() {
return filePath;
}
/**
* 获取文件后缀
* @return 文件后缀
*/
public String getExtension() {
return extension;
}
public boolean isContinue() {
return isContinue;
}
/**
* 希望程序继续执行后面的操作
* @param isContinue 是否继续
*/
public void setContinue(boolean isContinue) {
this.isContinue = isContinue;
}
}

View File

@@ -4,6 +4,8 @@ import com.axis.innovators.box.AxisInnovatorsBox;
import com.axis.innovators.box.events.*;
import com.axis.innovators.box.register.RegistrationSettingsItem;
import com.axis.innovators.box.register.LanguageManager;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -13,9 +15,7 @@ import javax.swing.plaf.PanelUI;
import javax.swing.plaf.basic.BasicScrollBarUI;
import javax.swing.plaf.basic.BasicTabbedPaneUI;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
@@ -30,16 +30,22 @@ public class MainWindow extends JFrame {
private static final Logger logger = LogManager.getLogger(MainWindow.class);
private final Map<JComponent, Float> cardScales = new HashMap<>();
private final Map<JComponent, Integer> cardElevations = new HashMap<>();
// 选项卡颜色
private final Color CARD_COLOR = Color.WHITE;
private final List<ToolCategory> categories = new ArrayList<>();
// 是否启用背景图片
private final boolean isBackground = true;
// 启动背景图片后是否启动背景模糊
private final boolean isBlur = true;
public MainWindow() {
setIconImage(LoadIcon.loadIcon("logo.png", 32).getImage());
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
for (JComponent card : cardScales.keySet()) {
cardScales.put(card, 1.0f);
card.repaint();
}
}
});
}
/**
@@ -52,18 +58,13 @@ public class MainWindow extends JFrame {
public void initUI() {
// 设置窗口属性
setTitle(LanguageManager.getLoadedLanguages().getText("mainWindow.title"));
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(1200, 800);
setLocationRelativeTo(null);
// 设置窗口和内容面板透明
//setBackground(new Color(0, 0, 0, 0));
getContentPane().setBackground(new Color(0, 0, 0, 0));
// 自定义面板
JPanel mainPanel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
@@ -96,24 +97,18 @@ public class MainWindow extends JFrame {
logger.error("Failed to load background image", e);
}
}
}
};
// 强制面板不透明
mainPanel.setOpaque(true);
mainPanel.putClientProperty("FlatLaf.style", "background: null;");
// 设置布局和边距
mainPanel.setLayout(new BorderLayout(20, 20));
mainPanel.setBorder(BorderFactory.createEmptyBorder(30, 30, 30, 30));
// 添加其他组件
mainPanel.add(createHeader(), BorderLayout.NORTH);
mainPanel.add(createCategoryTabs(), BorderLayout.CENTER);
// 添加主面板到窗口
add(mainPanel);
}
@@ -208,6 +203,10 @@ public class MainWindow extends JFrame {
private JComponent createCategoryTabs() {
JTabbedPane tabbedPane = new JTabbedPane();
//tabbedPane.putClientProperty(FlatClientProperties.TABBED_PANE_TAB_AREA_ALIGN, Component.LEFT_ALIGNMENT);
tabbedPane.putClientProperty(FlatClientProperties.TABBED_PANE_TAB_HEIGHT, 40);
tabbedPane.putClientProperty(FlatClientProperties.TABBED_PANE_TAB_ICON_PLACEMENT, SwingConstants.TOP);
tabbedPane.setOpaque(false);
tabbedPane.setBackground(new Color(0, 0, 0, 0));
tabbedPane.setBorder(null);
@@ -236,7 +235,7 @@ public class MainWindow extends JFrame {
}
tabbedPane.addTab(
category.getName(),
LoadIcon.loadIcon(category.getIcon(), 24),
LoadIcon.loadIcon(category.getIcon(), 12),
scrollPane
);
}
@@ -246,7 +245,7 @@ public class MainWindow extends JFrame {
private JPanel createToolsPanel(ToolCategory category) {
JPanel panel = new JPanel(new GridLayout(0, 3, 20, 20));
for (ToolItem tool : category.getTools()) {
for (ToolItem tool : category.getTools()) {
panel.add(createToolCard(tool));
}
panel.setOpaque(false);
@@ -264,16 +263,14 @@ public class MainWindow extends JFrame {
title.setFont(new Font("微软雅黑", Font.BOLD, 28));
title.setForeground(new Color(44, 62, 80));
//JLabel iconLabel = new JLabel(LoadIcon.loadIcon("logo.png", 28));
//iconLabel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));
JButton settings = new JButton(LoadIcon.loadIcon("settings.png", 32));
settings.putClientProperty(FlatClientProperties.BUTTON_TYPE, FlatClientProperties.BUTTON_TYPE_BORDERLESS);
settings.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
settings.setContentAreaFilled(false);
settings.addActionListener(e -> showSettings());
JPanel titlePanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
titlePanel.setOpaque(false);
//titlePanel.add(iconLabel);
titlePanel.add(title);
header.add(titlePanel, BorderLayout.WEST);
@@ -323,7 +320,6 @@ public class MainWindow extends JFrame {
JPanel card = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
// 毛玻璃效果
@@ -350,7 +346,8 @@ public class MainWindow extends JFrame {
g2d.dispose();
}
};
card.setPreferredSize(new Dimension(200, 150));
card.setMinimumSize(new Dimension(100, 75));
card.setLayout(new BorderLayout(15, 15));
card.setBackground(CARD_COLOR);
card.setBorder(BorderFactory.createCompoundBorder(
@@ -395,7 +392,6 @@ public class MainWindow extends JFrame {
card.add(iconLabel, BorderLayout.NORTH);
card.add(textPanel, BorderLayout.CENTER);
// 鼠标悬停动画
card.addMouseListener(new CardMouseAdapter(card, tool));
card.addMouseListener(new MouseAdapter() {
@Override
@@ -418,6 +414,19 @@ public class MainWindow extends JFrame {
super.update(g, c);
}
});
card.addMouseListener(new CardMouseAdapter(card, tool) {
@Override
public void mouseEntered(MouseEvent e) {
cardElevations.put(card, 8);
animateCardElevation(card, 8);
}
@Override
public void mouseExited(MouseEvent e) {
animateCardElevation(card, 2);
}
});
return card;
}
@@ -429,7 +438,25 @@ public class MainWindow extends JFrame {
"</body></html>";
}
// 工具类别内部类
private void animateCardElevation(JComponent card, int targetElevation) {
new Timer(10, new AbstractAction() {
private int currentElevation = cardElevations.getOrDefault(card, 2);
@Override
public void actionPerformed(ActionEvent e) {
if (currentElevation < targetElevation) currentElevation++;
else if (currentElevation > targetElevation) currentElevation--;
cardElevations.put(card, currentElevation);
card.repaint();
if (currentElevation == targetElevation) {
((Timer)e.getSource()).stop();
}
}
}).start();
}
public static class ToolCategory {
private final String name;
private final String icon;
@@ -687,52 +714,41 @@ public class MainWindow extends JFrame {
public static class CustomScrollBarUI extends BasicScrollBarUI {
@Override
protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
protected void configureScrollBarColors() {
this.thumbColor = new Color(90, 90, 120);
this.trackColor = new Color(50, 50, 70);
}
// 设置轨道背景颜色
Color trackColor = new Color(240, 240, 240);
g2d.setColor(trackColor);
g2d.fillRoundRect(
trackBounds.x,
trackBounds.y,
trackBounds.width - 1,
trackBounds.height - 1,
5, 5 // 圆角半径
);
@Override
protected JButton createDecreaseButton(int orientation) {
return createInvisibleButton();
}
@Override
protected JButton createIncreaseButton(int orientation) {
return createInvisibleButton();
}
private JButton createInvisibleButton() {
JButton btn = new JButton();
btn.setPreferredSize(new Dimension(0, 0));
btn.setMinimumSize(new Dimension(0, 0));
btn.setMaximumSize(new Dimension(0, 0));
return btn;
}
@Override
protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Color thumbColor = new Color(180, 180, 180);
g2d.setColor(thumbColor);
g2d.fillRoundRect(
thumbBounds.x,
thumbBounds.y,
thumbBounds.width - 1,
thumbBounds.height - 1,
5, 5
);
Color borderColor = new Color(160, 160, 160);
g2d.setColor(borderColor);
g2d.drawRoundRect(
thumbBounds.x,
thumbBounds.y,
thumbBounds.width - 1,
thumbBounds.height - 1,
5, 5
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(thumbColor);
g2.fillRoundRect(
thumbBounds.x + 2,
thumbBounds.y + 2,
thumbBounds.width - 4,
thumbBounds.height - 4,
8, 8
);
}
@Override
protected void paintDecreaseHighlight(Graphics g) {}
@Override
protected void paintIncreaseHighlight(Graphics g) {}
}
}

View File

@@ -13,6 +13,7 @@ public class PluginDescriptor {
private String description;
private Object instance;
private String transformers;
private String registrationName;
// Getters and Setters
public String getId() { return id; }
@@ -29,4 +30,6 @@ public class PluginDescriptor {
public void setInstance(Object instance) { this.instance = instance; }
public String getTransformers() {return transformers;}
public void setTransformers(String transformers) {this.transformers = transformers;}
public String getRegistrationName() {return registrationName;}
public void setRegistrationName(String registrationName) {this.registrationName = registrationName;}
}

View File

@@ -1,12 +1,16 @@
package com.axis.innovators.box.plugins;
import com.axis.innovators.box.AxisInnovatorsBox;
import com.axis.innovators.box.register.LanguageManager;
import com.axis.innovators.box.register.RegistrationTool;
import com.axis.innovators.box.tools.FolderCreator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.*;
import java.lang.reflect.Field;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.jar.*;
@@ -20,7 +24,8 @@ public class PluginLoader {
private static final List<PluginDescriptor> loadedPlugins = new ArrayList<>();
private static final List<IClassTransformer> transformers = new ArrayList<>();
private static final List<String> corePluginMainClass = new ArrayList<>();
public static void loadPlugins() throws IOException {
private static final List<String> pluginRegisteredName = new ArrayList<>();
public static void loadPlugins() throws IOException, PluginLoadingError {
logger = LogManager.getLogger(PluginLoader.class);
File pluginDir = null;
if (PLUGIN_PATH != null) {
@@ -43,7 +48,7 @@ public class PluginLoader {
}
}
private static void processJarFile(File jarFile, boolean isCorePlugin) throws IOException {
private static void processJarFile(File jarFile, boolean isCorePlugin) throws IOException, PluginLoadingError {
try (JarFile jar = new JarFile(jarFile)) {
// Check for CorePlugin in MANIFEST.MF
if (isCorePlugin) {
@@ -80,7 +85,11 @@ public class PluginLoader {
return;
}
for (File jar : jars) {
processJarFile(jar, true);
try {
processJarFile(jar, true);
} catch (PluginLoadingError e) {
throw new RuntimeException(e);
}
}
}
@@ -122,7 +131,8 @@ public class PluginLoader {
//}
}
private static void processWithManifest(JarFile jar, JarEntry entry, File jarFile) throws IOException {
private static void processWithManifest(JarFile jar, JarEntry entry, File jarFile)
throws IOException, PluginLoadingError {
Properties props = new Properties();
try (InputStream is = jar.getInputStream(entry)) {
props.load(is);
@@ -139,27 +149,92 @@ public class PluginLoader {
descriptor.setSupportedVersions(
Arrays.asList(props.getProperty("supportedVersions").split(","))
);
String registrationName = props.getProperty("registrationName");
verifyRegisteredNameValid(descriptor, registrationName);
logger.info("Loaded plugin: {}", descriptor.getName());
loadMainClass(props.getProperty("mainClass"), jarFile, descriptor);
Attributes attributes = jar.getManifest().getMainAttributes();
String corePluginClass = attributes.getValue("CorePlugin");
descriptor.setTransformers(corePluginClass);
loadPluginLanguages(jarFile, descriptor);
}
private static void processWithAnnotations(JarFile jar, File jarFile) {
private static void verifyRegisteredNameValid(PluginDescriptor descriptor, String registrationName) throws PluginLoadingError {
if (registrationName != null && !registrationName.isEmpty()
&& !pluginRegisteredName.contains(registrationName)) {
pluginRegisteredName.add(registrationName);
} else {
if (registrationName == null || registrationName.isEmpty()) {
throw new PluginLoadingError("Invalid registration name");
}
throw new PluginLoadingError("When the \" "
+ descriptor.getName()
+ "\" plugin is loaded, this plugin contains the same registered name as the previously loaded plugin");
}
descriptor.setRegistrationName(registrationName);
}
private static void processWithAnnotations(JarFile jar, File jarFile) throws PluginLoadingError {
URLClassLoader classLoader = createClassLoader(jarFile);
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (entry.getName().endsWith(".class")) {
if (classLoader != null) {
processClassEntry(entry, jar,classLoader);
processClassEntry(entry, jar,classLoader,jarFile);
}
}
}
}
private static void loadPluginLanguages(File jarFile, PluginDescriptor plugin) {
try (JarFile jar = new JarFile(jarFile)) {
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (entry.getName().startsWith("lang/") &&
entry.getName().endsWith(".properties")) {
processLanguageFile(jar, entry, plugin);
}
}
} catch (IOException e) {
logger.error("Failed to load language files for plugin: {}", plugin.getName(), e);
}
}
private static void processLanguageFile(JarFile jar, JarEntry entry, PluginDescriptor plugin) {
String fileName = entry.getName().substring(entry.getName().lastIndexOf("/") + 1);
String[] parts = fileName.split("[_.]");
if (parts.length < 3) {
return;
}
String langCode = parts[parts.length-1].replace(".properties", "");
String langName = plugin.getName() + " " + langCode.toUpperCase();
String registeredName = plugin.getRegistrationName() + "_" + langCode;
try (InputStream is = jar.getInputStream(entry)) {
Properties properties2 = new Properties();
properties2.load(new InputStreamReader(is, StandardCharsets.UTF_8));
LanguageManager.Language language = new LanguageManager.Language(
langName,
registeredName,
null
) {
@Override
public void loadLanguageFile(String languageFile) {
this.properties.putAll(properties2);
}
};
LanguageManager.addLanguage(language);
logger.info("Loaded plugin language: {} ({})", langName, registeredName);
} catch (IOException e) {
logger.error("Failed to load language file: {}", entry.getName(), e);
}
}
private static URLClassLoader createClassLoader(File jarFile) {
try {
return new URLClassLoader(
@@ -172,7 +247,9 @@ public class PluginLoader {
return null;
}
private static void processClassEntry(JarEntry entry,JarFile jar, URLClassLoader classLoader) {
private static void processClassEntry(JarEntry entry,JarFile jar,
URLClassLoader classLoader,
File jarFile) throws PluginLoadingError {
String className = entry.getName()
.replace("/", ".")
.replace(".class", "");
@@ -188,14 +265,27 @@ public class PluginLoader {
descriptor.setIcon(meta.icon());
descriptor.setSupportedVersions(Arrays.asList(meta.supportedVersions()));
String registrationName = meta.registeredName();
verifyRegisteredNameValid(descriptor, registrationName);
try {
Object instance = clazz.getDeclaredConstructor().newInstance();
descriptor.setInstance(instance);
loadedPlugins.add(descriptor);
try {
Field pluginInstance = instance.getClass().getDeclaredField("INSTANCE");
pluginInstance.setAccessible(true);
pluginInstance.set(null, descriptor);
} catch (NoSuchFieldException | IllegalArgumentException
| SecurityException | IllegalAccessException e) {
logger.warn("Failed to set plugin instance: {}", instance.getClass(), e);
}
loadedPlugins.add(descriptor);
Attributes attributes = jar.getManifest().getMainAttributes();
String corePluginClass = attributes.getValue("CorePlugin");
descriptor.setTransformers(corePluginClass);
loadPluginLanguages(jarFile, descriptor);
logger.info("Loaded plugin: {}", descriptor.getName());
} catch (Exception e) {
logger.error("Failed to instantiate plugin class: {}", className, e);
@@ -208,6 +298,7 @@ public class PluginLoader {
private static void loadMainClass(String mainClassName, File jarFile, PluginDescriptor descriptor) {
if (mainClassName == null || mainClassName.isEmpty()) {
logger.error("Invalid main class name: {}", mainClassName);
return;
}
@@ -218,6 +309,15 @@ public class PluginLoader {
Class<?> mainClass = classLoader.loadClass(mainClassName);
Object instance = mainClass.getDeclaredConstructor().newInstance();
descriptor.setInstance(instance);
try {
Field pluginInstance = mainClass.getDeclaredField("INSTANCE");
pluginInstance.setAccessible(true);
pluginInstance.set(null, descriptor);
} catch (NoSuchFieldException | IllegalArgumentException
| SecurityException | IllegalAccessException e) {
logger.warn("Failed to set plugin instance: {}", mainClassName, e);
}
} catch (Exception e) {
logger.error("Failed to load main class: {}", mainClassName, e);
}

View File

@@ -0,0 +1,17 @@
package com.axis.innovators.box.plugins;
/**
* 当加载插件时发生的错误
* @author tzdwindows 7
*/
public class PluginLoadingError extends Exception{
public PluginLoadingError(String message)
{
super(message);
}
public PluginLoadingError(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@@ -6,15 +6,34 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* 这是创建基础参数的注解
* @author tzdwindows 7
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface PluginMeta {
/**
* 插件ID
*/
String id();
/**
* 创建显示名称
*/
String name();
/**
* 支持的版本
*/
String[] supportedVersions();
/**
* 插件描述
*/
String description();
/**
* 插件图标
*/
String icon() default "";
/**
* 插件注册名称(确保其唯一性)
*/
String registeredName() default "no_registration";
}

View File

@@ -1,13 +1,14 @@
package com.axis.innovators.box.register;
import com.axis.innovators.box.plugins.PluginLoader;
import com.axis.innovators.box.tools.FolderCreator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.*;
/**
* 语言管理器
@@ -18,27 +19,106 @@ public class LanguageManager {
private static final String LANGUAGE_PATH = FolderCreator.getLanguageFolder();
private static final List<Language> LANGUAGES = new ArrayList<>();
private static final String SAVED_LANGUAGE_FILE = LANGUAGE_PATH + "\\saved_language.properties";
private static final Logger logger = LogManager.getLogger(PluginLoader.class);
static {
LANGUAGES.add(new Language("简体中文", "Zh","SimplifiedChineseLanguage"));
LANGUAGES.add(new Language("繁體中文", "TC","TraditionalChineseLanguage"));
LANGUAGES.add(new Language("English", "En","EnglishLanguage"));
LANGUAGES.add(new Language("简体中文", "system:zh_CN", "sys_zh_CN"));
LANGUAGES.add(new Language("繁體中文(台灣)", "system:zh_TW", "sys_zh_TW"));
LANGUAGES.add(new Language("English (International)", "system:en_US", "sys_en_US"));
LANGUAGES.add(new Language("日本語", "system:ja_JP", "sys_ja_JP"));
}
/**
* 添加语言
* @param language 语言
* 添加/合并语言资源
* @param language 要添加的语言对象
* 处理规则:
* 1. 注册名相同时保留原有基础信息
* 2. 相同键值的新内容覆盖旧内容
* 3. 详细记录新增、更新的键值数量
* 4. 提供关键示例用于调试
*/
public static void addLanguage(Language language) {
for (int i = 0; i < LANGUAGES.size(); i++) {
Language language1 = LANGUAGES.get(i);
if (Objects.equals(language1.getRegisteredName(), language.getRegisteredName())){
LANGUAGES.set(i, language);
for (Language existing : LANGUAGES) {
if (existing.getRegisteredName().equals(language.getRegisteredName())) {
try {
int added = 0;
int updated = 0;
Set<String> sampleAddedKeys = new LinkedHashSet<>();
Set<String> sampleUpdatedKeys = new LinkedHashSet<>();
for (String key : language.properties.stringPropertyNames()) {
String newValue = language.properties.getProperty(key);
if (existing.properties.containsKey(key)) {
updated++;
if (sampleUpdatedKeys.size() < 5) {
sampleUpdatedKeys.add(key);
}
} else {
added++;
if (sampleAddedKeys.size() < 5) {
sampleAddedKeys.add(key);
}
}
existing.properties.setProperty(key, newValue);
}
String logDetail = buildMergeLogDetails(added, updated, sampleAddedKeys, sampleUpdatedKeys);
logger.info("【语言合并报告】\n" +
"▌合并目标:{} ({})\n" +
"▌变更统计:新增 {} 条 / 更新 {} 条\n" +
"▌当前总量:{} 条\n" +
"▌关键示例:\n{}",
existing.getLanguageName(),
existing.getRegisteredName(),
added,
updated,
existing.properties.size(),
logDetail);
return;
} catch (Exception e) {
logger.error("语言合并异常!注册名:{} - {}",
existing.getRegisteredName(),
e.getClass().getSimpleName(),
e);
}
return;
}
}
LANGUAGES.add(language);
logger.info("【新增语言】{} ({}) 初始加载 {} 条",
language.getLanguageName(),
language.getRegisteredName(),
language.properties.size());
}
private static String buildMergeLogDetails(int added, int updated,
Set<String> sampleAdded, Set<String> sampleUpdated) {
StringBuilder sb = new StringBuilder();
if (added > 0) {
sb.append("✦ 新增条目:\n");
sampleAdded.forEach(k -> sb.append("").append(k).append("\n"));
if (added > 5) {
sb.append(" ...(共").append(added).append("条)\n");
}
}
if (updated > 0) {
sb.append("✦ 更新条目:\n");
sampleUpdated.forEach(k -> sb.append("").append(k).append("\n"));
if (updated > 5) {
sb.append(" ...(共").append(updated).append("条)\n");
}
}
return sb.toString().isEmpty() ? "无内容变更" : sb.toString();
}
/**
* 加载语言
* @param languageName 语言注册名
@@ -120,7 +200,7 @@ public class LanguageManager {
private final String languageName;
private final String registeredName;
private final String languageFile;
private final Properties properties;
protected final Properties properties;
public Language(String languageName,
String registeredName,
@@ -133,14 +213,14 @@ public class LanguageManager {
this.languageFile = LANGUAGE_PATH + "\\" + languageFileName + ".properties";
}
this.properties = new Properties();
loadLanguageFile();
loadLanguageFile(languageFile);
}
/**
* 加载语言文件
*/
private void loadLanguageFile() {
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(this.languageFile),
public void loadLanguageFile(String languageFile) {
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(languageFile),
StandardCharsets.UTF_8)) {
properties.load(reader);
} catch (IOException e) {
@@ -161,6 +241,13 @@ public class LanguageManager {
return properties.getProperty(key);
}
/**
* 添加文本
*/
public void addText(String key, String value) {
properties.setProperty(key, value);
}
public String getLanguageName() {
return languageName;
}

View File

@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* 用于注册设置项的类
@@ -563,7 +564,7 @@ public class RegistrationSettingsItem extends WindowsJDialog {
* @param tip 描述
* @param registeredName 注册名(必须是唯一的)
*/
public void addSettings(JPanel tabbedPanesSettings,
private void addSettings(JPanel tabbedPanesSettings,
String title,
Icon icon,
String tip,
@@ -579,6 +580,49 @@ public class RegistrationSettingsItem extends WindowsJDialog {
}
}
/**
* 注册设置项
* @param tabbedPanesSettings 设置页面
* @param title 标题
* @param icon 显示图标可为null
* @param tip 描述
* @param plugin 插件
* @param registeredName 注册名(必须是唯一的)
*/
public void addSettings(JPanel tabbedPanesSettings,
String title,
Icon icon,
String tip,
PluginDescriptor plugin,
String registeredName) {
if (mainWindow != null) {
if (!mainWindow.isWindow()) {
registrationItem(tabbedPanesSettings, title, icon, tip,plugin.getRegistrationName()
+ ":" +
registeredName);
} else {
logger.warn("Wrong time to add tools");
}
} else {
registrationItem(tabbedPanesSettings, title, icon, tip, registeredName);
}
}
/**
* 通过 PluginDescriptor 查询整个插件装载的注册项
* @param plugin 插件描述符
* @return List<RegistrationSettingsItem> 与指定插件相关的注册设置项列表
*/
public static List<RegistrationSettingsItem> getRegistrationsByPlugin(PluginDescriptor plugin) {
return registrationSettingsItemList.stream()
.filter(item ->
item.getRegisteredNameList().stream()
.anyMatch(name ->
name.startsWith(plugin.getRegistrationName() + ":"))
)
.collect(Collectors.toList());
}
private void registrationItem(JPanel tabbedPanesSettings, String title, Icon icon, String tip, String registeredName) {
if (registeredNameList.contains(registeredName)) {
throw new RegistrationError(registeredName + " duplicate registered names");

View File

@@ -4,6 +4,7 @@ import com.axis.innovators.box.AxisInnovatorsBox;
import com.axis.innovators.box.gui.FridaWindow;
import com.axis.innovators.box.gui.LocalWindow;
import com.axis.innovators.box.gui.MainWindow;
import com.axis.innovators.box.plugins.PluginDescriptor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -24,6 +25,7 @@ public class RegistrationTool {
private final AxisInnovatorsBox main;
private final List<UUID> uuidList = new ArrayList<>();
private final List<String> registeredNameList = new ArrayList<>();
private final List<PluginDescriptor> pluginDescriptors = new ArrayList<>();
public RegistrationTool(AxisInnovatorsBox main) {
this.main = main;
@@ -66,7 +68,7 @@ public class RegistrationTool {
* 注册ToolCategory
* @param toolCategory ToolCategory
*/
public void addToolCategory(MainWindow.ToolCategory toolCategory,
private boolean addToolCategory(MainWindow.ToolCategory toolCategory,
String registeredName) {
if (!main.isWindow()) {
if (registeredNameList.contains(registeredName)) {
@@ -75,8 +77,24 @@ public class RegistrationTool {
uuidList.add(toolCategory.getId());
registeredNameList.add(registeredName);
toolCategories.add(toolCategory);
return true;
} else {
logger.warn("Wrong time to add tools");
return false;
}
}
/**
* 注册ToolCategory
* @param toolCategory ToolCategory
*/
public void addToolCategory(MainWindow.ToolCategory toolCategory,
PluginDescriptor pluginDescriptor,
String registeredName) {
if (addToolCategory(toolCategory,
pluginDescriptor.getRegistrationName() + ":" +
registeredName)) {
pluginDescriptors.add(pluginDescriptor);
}
}

View File

@@ -0,0 +1,83 @@
package com.axis.innovators.box.tools;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* ArgsParser 类用于解析命令行参数,并返回包含合法文件信息的列表。
* @author tzdwindows 7
*/
public class ArgsParser {
/**
* 判断路径是否合法(存在且是文件)
*
* @param path 文件路径
* @return 是否合法
*/
private static boolean isValidPath(String path) {
File file = new File(path);
return file.exists() && file.isFile();
}
/**
* 获取文件的后缀名
*
* @param path 文件路径
* @return 文件后缀名(如 ".txt"
*/
private static String getFileExtension(String path) {
int lastDotIndex = path.lastIndexOf('.');
if (lastDotIndex == -1) {
return ""; // 没有后缀名
}
return path.substring(lastDotIndex);
}
/**
* 解析 args 参数并保存合法的文件路径
*
* @param args main 方法的参数
* @return 包含合法文件信息的列表,每个元素是一个 Map包含 "extension" 和 "path"
*/
public static List<Map<String, String>> parseArgs(String[] args) {
List<Map<String, String>> validFiles = new ArrayList<>();
for (String arg : args) {
if (isValidPath(arg)) {
String extension = getFileExtension(arg);
Map<String, String> fileInfo = new HashMap<>();
fileInfo.put("extension", extension);
fileInfo.put("path", arg);
validFiles.add(fileInfo);
}
}
return validFiles;
}
public static void main(String[] args) {
// 模拟 main 方法的 args 参数
String[] testArgs = {
"C:\\Program Files\\test.txt", // 合法文件
"C:\\invalid_file.exe", // 不存在的文件
"D:\\Documents\\report.pdf", // 合法文件
"not_a_path", // 无效路径
"C:\\Windows\\system32" // 目录,不是文件
};
// 解析 args 参数
List<Map<String, String>> validFiles = parseArgs(testArgs);
// 输出结果
System.out.println("Valid files:");
for (Map<String, String> fileInfo : validFiles) {
System.out.println("Extension: " + fileInfo.get("extension") + ", Path: " + fileInfo.get("path"));
}
}
}

View File

@@ -22,7 +22,7 @@ public class StateManager {
* @param statusName 状态文件名
*/
public StateManager(String statusName) {
statusFile = FolderCreator.getConfigurationFolder() + statusName + ".properties";
statusFile = FolderCreator.getConfigurationFolder() + "\\" + statusName + ".properties";
configMap = new HashMap<>();
properties = new Properties();
loadConfiguration();
@@ -32,7 +32,7 @@ public class StateManager {
* 默认构造函数
*/
public StateManager() {
statusFile = FolderCreator.getConfigurationFolder() + "state_management.properties";
statusFile = FolderCreator.getConfigurationFolder() + "\\toolbox.properties";
configMap = new HashMap<>();
properties = new Properties();
loadConfiguration();

View File

@@ -10,7 +10,7 @@ import org.apache.logging.log4j.Logger;
* @author tzdwindows 7
*/
public class LM {
public static boolean CUDA = true;
public static boolean CUDA = false;
public final static String DEEP_SEEK = FolderCreator.getModelFolder() + "\\DeepSeek-R1-Distill-Qwen-1.5B-Q8_0.gguf";
private static final Logger logger = LogManager.getLogger(LM.class);