哈哈哈哈哈哈哈哈哈哈哈哈哈哈
This commit is contained in:
2
.idea/gradle.xml
generated
2
.idea/gradle.xml
generated
@@ -5,7 +5,7 @@
|
|||||||
<option name="linkedExternalProjectsSettings">
|
<option name="linkedExternalProjectsSettings">
|
||||||
<GradleProjectSettings>
|
<GradleProjectSettings>
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
<option name="gradleHome" value="" />
|
<option name="gradleJvm" value="corretto-20" />
|
||||||
<option name="modules">
|
<option name="modules">
|
||||||
<set>
|
<set>
|
||||||
<option value="$PROJECT_DIR$" />
|
<option value="$PROJECT_DIR$" />
|
||||||
|
|||||||
634
README.md
Normal file
634
README.md
Normal file
@@ -0,0 +1,634 @@
|
|||||||
|
# AxisInnovatorsBoxWindowApi
|
||||||
|
|
||||||
|
[项目链接](http://103.97.57.30:3000/tzdwindows7/AxisInnovatorsBoxWindowApi) | 简体中文
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 项目概述
|
||||||
|
|
||||||
|
`AxisInnovatorsBoxWindowApi` 是一个为 **AxisInnovatorsBox** 平台设计的管理API接口库,开发者可通过此API创建自定义插件,实现窗口管理、事件交互等核心功能。该仓库提供了接口定义、类说明文档及插件开发示例代码,帮助开发者快速接入AxisInnovatorsBox生态系统。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
- 🖥️ **窗口生命周期管理** - 创建/销毁窗口、调整窗口状态(最小化/最大化)
|
||||||
|
- 🎮 **事件驱动交互** - 支持窗口事件监听与自定义事件触发
|
||||||
|
- 📦 **跨语言插件支持** - 基于 Java 平台无缝加载 Python 插件,提供标准插件基类(Java/Python)实现快速扩展
|
||||||
|
- 📄 **动态配置管理** - 通过 properties 配置文件灵活加载多语言插件(支持 Java/Python 插件声明)
|
||||||
|
- 📊 **统一日志追踪** - 集成 Java 平台日志系统,同步记录 Python 插件的运行状态与异常信息
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 插件加载系统说明
|
||||||
|
- 插件加载系统核心组件。
|
||||||
|
- 插件加载系统由 **程序内部** 完成
|
||||||
|
|
||||||
|
### 注册Jar插件
|
||||||
|
- Jar插件在/plug-in中添加
|
||||||
|
```java
|
||||||
|
@PluginMeta(id = "test", name = "测试插件",
|
||||||
|
supportedVersions = {"0.0.2"},
|
||||||
|
description = "测试插件",
|
||||||
|
icon = "",
|
||||||
|
registeredName = "test")
|
||||||
|
public class Template {
|
||||||
|
public static PluginDescriptor INSTANCE = null;
|
||||||
|
|
||||||
|
public Template() {
|
||||||
|
GlobalEventBus.EVENT_BUS.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onStartup(StartupEvent event) {
|
||||||
|
MainWindow.ToolCategory category = new MainWindow.ToolCategory("测试插件", "test", "测试插件");
|
||||||
|
event.main().getRegistrationTool().addToolCategory(
|
||||||
|
category,
|
||||||
|
INSTANCE,
|
||||||
|
"templatePlugin"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 插件加载系统会自动填充 **INSTANCE** 内容
|
||||||
|
- 使用PluginMeta注册插件信息
|
||||||
|
|
||||||
|
### Python插件注册
|
||||||
|
- Python插件在/plug-in/python中添加
|
||||||
|
- Python可以直接调用Java类实现对插件系统的控制
|
||||||
|
- 插件还需要单独的放在一个子文件夹中,如/plug-in/python/Examples
|
||||||
|
- Python插件需要声明一个metadata.json文件,如:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "testing",
|
||||||
|
"name": "测试",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "测试插件",
|
||||||
|
"author": "tzdwindows 7",
|
||||||
|
"dependencies": [],
|
||||||
|
"_comment": {
|
||||||
|
"warning": "本文件为插件元数据配置,修改后需重启应用生效",
|
||||||
|
"path": "插件资源应放置在plugins/{id}/目录下"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Python插件需要声明一个main.py文件做为插件的主脚本,如:
|
||||||
|
```python
|
||||||
|
"""
|
||||||
|
工具模块初始化脚本
|
||||||
|
功能:向Axis Innovators Box注册自定义工具类别和工具项
|
||||||
|
作者:tzdwindows 7
|
||||||
|
版本:1.1
|
||||||
|
"""
|
||||||
|
from com.axis.innovators.box.python import PyLocalSide
|
||||||
|
from javax.swing import AbstractAction
|
||||||
|
|
||||||
|
class MyAction(AbstractAction):
|
||||||
|
def actionPerformed(self, event):
|
||||||
|
"""工具项点击事件处理"""
|
||||||
|
print("[DEBUG] Tool item clicked! Event source:", event.getSource())
|
||||||
|
|
||||||
|
def onStartup():
|
||||||
|
"""
|
||||||
|
系统启动时自动执行的初始化逻辑
|
||||||
|
功能:
|
||||||
|
1. 创建工具类别
|
||||||
|
2. 创建工具项并绑定动作
|
||||||
|
3. 注册到系统全局工具集
|
||||||
|
"""
|
||||||
|
print('[INFO] 正在初始化自定义工具...')
|
||||||
|
|
||||||
|
# --------------------------
|
||||||
|
# 创建工具类别(参数顺序:显示名称,图标资源名,描述)
|
||||||
|
# --------------------------
|
||||||
|
tool_category = PyLocalSide.getToolCategory(
|
||||||
|
u"数据分析工具", # 显示名称(GUI可见)
|
||||||
|
u"analytics_icon.png", # 图标文件名(需存在于资源目录)
|
||||||
|
u"高级数据分析功能集合" # 悬停提示描述
|
||||||
|
)
|
||||||
|
|
||||||
|
# --------------------------
|
||||||
|
# 创建工具项(参数顺序:显示名称,图标,描述,ID,动作对象)
|
||||||
|
# --------------------------
|
||||||
|
tool_action = MyAction()
|
||||||
|
tool_item = PyLocalSide.getToolItem(
|
||||||
|
u"数据可视化", # 工具项显示名称
|
||||||
|
u"chart_icon.png", # 工具项图标
|
||||||
|
u"生成交互式数据图表", # 工具项描述
|
||||||
|
1001, # 工具项唯一ID(需在配置中统一管理)
|
||||||
|
tool_action # 点击触发的动作
|
||||||
|
)
|
||||||
|
tool_category.addTool(tool_item)
|
||||||
|
|
||||||
|
# --------------------------
|
||||||
|
# 注册工具类别到系统(参数:类别对象,全局唯一注册名称)
|
||||||
|
# --------------------------
|
||||||
|
PyLocalSide.addToolCategory(
|
||||||
|
tool_category,
|
||||||
|
u"custom_module::data_analysis_tools" # 推荐命名规则:模块名::功能名
|
||||||
|
)
|
||||||
|
print('[SUCCESS] 工具类别注册成功')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
result = 0
|
||||||
|
errorResult = ""
|
||||||
|
|
||||||
|
# 确保Jython运行时可以访问onStartup函数
|
||||||
|
# 原理:将函数显式绑定到全局字典
|
||||||
|
globals()['onStartup'] = onStartup
|
||||||
|
```
|
||||||
|
|
||||||
|
### 声明CorePlugins
|
||||||
|
* CorePlugins核心组件可以修改部分模块的字节码。
|
||||||
|
* CorePlugins需要在jar的属性中添加 **CorePlugins: CorePlugins类位置**
|
||||||
|
* 自动化构建,在build.gradle中添加如下代码:
|
||||||
|
```groovy
|
||||||
|
jar {
|
||||||
|
manifest {
|
||||||
|
attributes 'CorePlugin': 'com.axis.core.template.TemplateLoadingCorePlugin'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
* CorePlugins核心组件需要实现 **CorePlugins** 接口,如:
|
||||||
|
```java
|
||||||
|
package com.axis.core.template;
|
||||||
|
|
||||||
|
import com.axis.innovators.box.plugins.LoadingCorePlugin;
|
||||||
|
import com.axis.innovators.template.Template;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册core插件
|
||||||
|
*/
|
||||||
|
public class TemplateLoadingCorePlugin implements LoadingCorePlugin {
|
||||||
|
@Override
|
||||||
|
public String getMainClass() {
|
||||||
|
// 返回主类名
|
||||||
|
return Template.class.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getASMTransformerClass() {
|
||||||
|
// 返回字节码转换器类名
|
||||||
|
return new String[]{TemplateTransformer.class.getName()};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
* IClassTransformer的实现,如:
|
||||||
|
```java
|
||||||
|
package com.axis.core.template;
|
||||||
|
|
||||||
|
import com.axis.innovators.box.plugins.IClassTransformer;
|
||||||
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* core plugin transformer
|
||||||
|
* @author tzdwindows 7
|
||||||
|
*/
|
||||||
|
public class TemplateTransformer implements IClassTransformer {
|
||||||
|
@Override
|
||||||
|
public byte[] transform(String s, String s1, byte[] bytes) {
|
||||||
|
ClassReader classReader = new ClassReader(bytes);
|
||||||
|
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||||
|
|
||||||
|
ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM5, classWriter) {
|
||||||
|
@Override
|
||||||
|
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
|
||||||
|
if ((access & Opcodes.ACC_PRIVATE) != 0) {
|
||||||
|
access = (access & ~Opcodes.ACC_PRIVATE) | Opcodes.ACC_PUBLIC;
|
||||||
|
System.out.println("Changing field access to public: " + name);
|
||||||
|
}
|
||||||
|
return super.visitField(access, name, descriptor, signature, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
||||||
|
System.out.println(name + " , descriptor:" + descriptor);
|
||||||
|
if ((access & Opcodes.ACC_PRIVATE) != 0) {
|
||||||
|
access = (access & ~Opcodes.ACC_PRIVATE) | Opcodes.ACC_PUBLIC;
|
||||||
|
System.out.println("Changing method access to public: " + name);
|
||||||
|
}
|
||||||
|
return super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
classReader.accept(classVisitor, 0);
|
||||||
|
return classWriter.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 事件系统说明
|
||||||
|
- 事件驱动架构核心组件。
|
||||||
|
- 事件总线系统,支持跨模块通信。
|
||||||
|
- 事件总线由 **EventBus & GlobalEventBus** 实现
|
||||||
|
|
||||||
|
### 1.. EventBus & GlobalEventBus 说明
|
||||||
|
应用程序内的事件驱动架构核心组件:
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.axis.innovators.box.events;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 事件总线系统(支持多总线实例隔离)
|
||||||
|
*/
|
||||||
|
public class EventBus {
|
||||||
|
// 核心方法
|
||||||
|
public void register(Object listener); // 注册监听器
|
||||||
|
public void unregister(Object target); // 注销监听器
|
||||||
|
public boolean post(Object event); // 发布事件
|
||||||
|
public void shutdown(); // 关闭总线
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GlobalEventBus {
|
||||||
|
public static final EventBus EVENT_BUS = new EventBus(); // 全局单例总线
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- **EventBus**:用于处理应用程序内各个模块之间的事件通信。
|
||||||
|
- **GlobalEventBus**:用于处理应用程序内各个模块之间的事件通信,支持多总线实例隔离。
|
||||||
|
|
||||||
|
### 2. EventBus & GlobalEventBus 使用示例
|
||||||
|
|
||||||
|
#### 示例1:基础事件处理
|
||||||
|
```java
|
||||||
|
// 1. 定义事件类型
|
||||||
|
public class UserLoginEvent {
|
||||||
|
private final String username;
|
||||||
|
private boolean cancelled;
|
||||||
|
|
||||||
|
public UserLoginEvent(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getter/Setter...
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 创建监听器类
|
||||||
|
public class SecurityLogger {
|
||||||
|
@SubscribeEvent
|
||||||
|
public void logLoginAttempt(UserLoginEvent event) {
|
||||||
|
System.out.println("[安全审计] 登录尝试: " + event.getUsername());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 使用全局总线
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// 注册监听器
|
||||||
|
GlobalEventBus.EVENT_BUS.register(new SecurityLogger());
|
||||||
|
|
||||||
|
// 模拟用户登录
|
||||||
|
UserLoginEvent loginEvent = new UserLoginEvent("admin");
|
||||||
|
GlobalEventBus.EVENT_BUS.post(loginEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 示例2:事件取消机制
|
||||||
|
```java
|
||||||
|
// 1. 定义可取消事件
|
||||||
|
public class FileDeleteEvent {
|
||||||
|
private final Path filePath;
|
||||||
|
private boolean cancelled;
|
||||||
|
|
||||||
|
// 构造方法/getters/setters...
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 创建权限校验监听器
|
||||||
|
public class PermissionValidator {
|
||||||
|
@SubscribeEvent
|
||||||
|
public void validateDeletePermission(FileDeleteEvent event) {
|
||||||
|
if (!checkAdminAccess()) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
System.out.println("文件删除被拒绝:权限不足");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkAdminAccess() {
|
||||||
|
// 权限校验逻辑
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 主业务流程
|
||||||
|
public class FileManager {
|
||||||
|
public void deleteFile(Path path) {
|
||||||
|
FileDeleteEvent event = new FileDeleteEvent(path);
|
||||||
|
GlobalEventBus.EVENT_BUS.post(event);
|
||||||
|
|
||||||
|
if (!event.isCancelled()) {
|
||||||
|
// 执行删除操作
|
||||||
|
System.out.println("正在删除文件: " + path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.所有系统所支持的事件
|
||||||
|
- `com.axis.innovators.box.events.CategoryRenderingEvent`: 分类栏的渲染事件
|
||||||
|
- `com.axis.innovators.box.events.MainWindowEvents`: 主窗口事件
|
||||||
|
- `com.axis.innovators.box.events.OpenFileEvents`: 接收文件事件
|
||||||
|
- `com.axis.innovators.box.events.SettingsLoadEvents`: 程序初始化事件
|
||||||
|
- `com.axis.innovators.box.events.StartupEvent`: 程序启动事件
|
||||||
|
- `com.axis.innovators.box.events.TABUIEvents`: 选项卡Ui属性事件
|
||||||
|
|
||||||
|
## HTML窗口集成指南
|
||||||
|
|
||||||
|
我们实现了一套高性能的HTML渲染系统,通过Java Chromium Embedded Framework (JCEF) 将HTML内容无缝集成到Java桌面应用中,底层基于[jcefmaven](https://github.com/jcefmaven/jcefmaven)项目。
|
||||||
|
|
||||||
|
### 核心实现步骤
|
||||||
|
|
||||||
|
#### 1. 创建HTML窗口
|
||||||
|
```java
|
||||||
|
// 创建窗口引用
|
||||||
|
AtomicReference<BrowserWindowJDialog> htmlWindow = new AtomicReference<>();
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
// 通过窗口注册表创建子窗口
|
||||||
|
WindowRegistry.getInstance().createNewChildWindow("main", builder -> {
|
||||||
|
htmlWindow.set(builder
|
||||||
|
.title("Axis Innovators Box AI 工具箱") // 窗口标题
|
||||||
|
.parentFrame(parentFrame) // 父级窗口
|
||||||
|
.icon(getApplicationIcon()) // 应用图标
|
||||||
|
.size(1280, 720) // 初始尺寸
|
||||||
|
.htmlPath(getHtmlResourcePath()) // HTML文件路径
|
||||||
|
.operationHandler(createOperationHandler()) // 自定义操作处理器
|
||||||
|
.build());
|
||||||
|
});
|
||||||
|
|
||||||
|
// 配置消息路由
|
||||||
|
configureMessageRouter(htmlWindow.get());
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. 辅助方法
|
||||||
|
```java
|
||||||
|
// 获取应用图标
|
||||||
|
private Image getApplicationIcon() {
|
||||||
|
return new ImageIcon(Objects.requireNonNull(
|
||||||
|
MainApplication.class.getClassLoader()
|
||||||
|
.getResource("icons/logo.png")
|
||||||
|
)).getImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取HTML资源路径
|
||||||
|
private String getHtmlResourcePath() {
|
||||||
|
return FolderCreator.getJavaScriptFolder() + "/AIaToolbox_dark.html";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. 配置消息路由器
|
||||||
|
```java
|
||||||
|
private void configureMessageRouter(BrowserWindowJDialog window) {
|
||||||
|
CefMessageRouter msgRouter = window.getMsgRouter();
|
||||||
|
if (msgRouter == null) return;
|
||||||
|
|
||||||
|
msgRouter.addHandler(new CefMessageRouterHandlerAdapter() {
|
||||||
|
@Override
|
||||||
|
public boolean onQuery(CefBrowser browser, CefFrame frame, long queryId,
|
||||||
|
String request, boolean persistent, CefQueryCallback callback) {
|
||||||
|
// 处理来自HTML的请求
|
||||||
|
handleBrowserRequest(request, callback);
|
||||||
|
return true; // 表示已处理该请求
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onQueryCanceled(CefBrowser browser, CefFrame frame, long queryId) {
|
||||||
|
// 处理请求取消逻辑
|
||||||
|
System.out.println("请求被取消: " + queryId);
|
||||||
|
}
|
||||||
|
}, true); // true表示优先处理
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 窗口管理系统说明
|
||||||
|
|
||||||
|
通过`WindowRegistry`统一管理应用窗口:
|
||||||
|
|
||||||
|
| 方法 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `createNewWindow(String id, Consumer<Builder> config)` | 创建主窗口 |
|
||||||
|
| `createNewChildWindow(String id, Consumer<Builder> config)` | 创建模态子窗口 |
|
||||||
|
| `getWindow(String id)` | 获取已注册窗口 |
|
||||||
|
| `unregisterWindow(String id)` | 关闭指定窗口 |
|
||||||
|
|
||||||
|
### CefMessageRouter 使用指南
|
||||||
|
|
||||||
|
实现Java与JavaScript双向通信的核心组件:
|
||||||
|
|
||||||
|
1. **消息处理流程**:
|
||||||
|
- JavaScript → Java: 通过`window.cefQuery()`发送请求
|
||||||
|
- Java → JavaScript: 使用`CefFrame.executeJavaScript()`执行脚本
|
||||||
|
|
||||||
|
2. **核心方法**:
|
||||||
|
```java
|
||||||
|
// JavaScript调用示例
|
||||||
|
function callJavaMethod(data) {
|
||||||
|
window.cefQuery({
|
||||||
|
request: JSON.stringify(data),
|
||||||
|
onSuccess: response => console.log("Success:", response),
|
||||||
|
onFailure: (err, msg) => console.error("Error:", msg)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **最佳实践**:
|
||||||
|
- 使用JSON格式进行数据交换
|
||||||
|
- 为不同功能模块使用独立的路由处理器
|
||||||
|
- 在窗口关闭前移除所有路由处理器
|
||||||
|
|
||||||
|
### 生命周期管理
|
||||||
|
```java
|
||||||
|
// 关闭窗口时清理资源
|
||||||
|
htmlWindow.get().addWindowListener(new WindowAdapter() {
|
||||||
|
@Override
|
||||||
|
public void windowClosing(WindowEvent e) {
|
||||||
|
window.getMsgRouter().dispose();
|
||||||
|
CefApp.getInstance().dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## 核心类说明
|
||||||
|
|
||||||
|
### 1. AxisInnovatorsBox
|
||||||
|
窗口实例的核心操作类,提供以下功能:
|
||||||
|
- `getMain()`: 获取当前AxisInnovatorsBox实例
|
||||||
|
- `getMainWindow()`: 获取主窗口实例
|
||||||
|
- `quit()`: 退出程序
|
||||||
|
- `organizingCrashReports(Exception)`: 组织崩溃报告,用于在应用程序发生异常时生成崩溃报告。
|
||||||
|
- `popupWindow(WindowsJDialog)`: 弹出新的窗口,并将其添加到窗口列表中。
|
||||||
|
- `isWindowStartup(WindowsJDialog)`: 判断指定的窗口是否已经启动。
|
||||||
|
- `clearWindow(WindowsJDialog)`: 清除指定的窗口,并将其从窗口列表中移除。
|
||||||
|
- `reloadAllWindow()`: 重新加载窗口。
|
||||||
|
- `getRegistrationTool()`: 获取注册工具实例。
|
||||||
|
- `getArgs()`: 获取命令行参数。
|
||||||
|
- `isWindow()`: 判断窗口是否已经启动。
|
||||||
|
- `getVersion()`: 获取应用程序的版本号。
|
||||||
|
- `getRegistrationTopic()`: 获取注册主题实例。
|
||||||
|
- `getAuthor()`: 获取应用程序的作者信息。
|
||||||
|
- `getStateManager()`: 获取状态管理器实例。
|
||||||
|
|
||||||
|
### 2. RegistrationTool
|
||||||
|
负责在 **应用程序启动阶段** 注册和管理工具分类的核心组件,具备插件系统集成能力:
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.axis.innovators.box.register;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工具分类注册中心(窗口启动前必须完成注册)
|
||||||
|
*/
|
||||||
|
public class RegistrationTool {
|
||||||
|
// 构造方法关联主程序实例
|
||||||
|
public RegistrationTool(AxisInnovatorsBox main) { ... }
|
||||||
|
|
||||||
|
// 核心功能方法
|
||||||
|
public boolean addToolCategory(ToolCategory category, String regName);
|
||||||
|
public void addToolCategory(ToolCategory category, PluginDescriptor descriptor, String regName);
|
||||||
|
public ToolCategory getToolCategory(UUID id);
|
||||||
|
public UUID getUUID(String registeredName);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- `addToolCategory(ToolCategory category, String regName)`: 向工具分类注册中心添加一个新的工具分类。
|
||||||
|
- `addToolCategory(ToolCategory category, PluginDescriptor descriptor, String regName)`: 向工具分类注册中心添加一个新的工具分类,同时关联插件描述符。
|
||||||
|
- `getToolCategory(UUID id)`: 通过UUID获取工具分类。
|
||||||
|
- `getUUID(String registeredName)`: 通过注册名称获取UUID。
|
||||||
|
|
||||||
|
#### 注册示例
|
||||||
|
```java
|
||||||
|
// 创建调试工具分类
|
||||||
|
MainWindow.ToolCategory debugCategory = new MainWindow.ToolCategory(
|
||||||
|
"逆向分析工具",
|
||||||
|
"icons/debugger.png",
|
||||||
|
"二进制逆向分析工具集"
|
||||||
|
);
|
||||||
|
|
||||||
|
// 添加工具项(带点击事件)
|
||||||
|
debugCategory.addTool(new MainWindow.ToolItem(
|
||||||
|
"内存分析器",
|
||||||
|
"icons/memory.png",
|
||||||
|
"实时查看进程内存映射",
|
||||||
|
1,
|
||||||
|
new AbstractAction() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
JOptionPane.showMessageDialog(null, "启动内存分析模块...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
// 注册到系统(必须在窗口初始化前完成)
|
||||||
|
try {
|
||||||
|
registrationTool.addToolCategory(debugCategory, "system:reverseEngineering");
|
||||||
|
} catch (RegistrationError ex) {
|
||||||
|
System.err.println("注册失败: " + ex.getMessage());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### 3. RegistrationTopic
|
||||||
|
负责在 **应用程序初始化阶段** 统一管理UI主题注册的核心组件,支持类名/LookAndFeel双模式主题注入:
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.axis.innovators.box.register;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主题注册中心(窗口初始化前必须完成注册)
|
||||||
|
*/
|
||||||
|
public class RegistrationTopic {
|
||||||
|
// 核心注册方法
|
||||||
|
public void addTopic(String topicClass, String name, String tip, Icon icon, String regName);
|
||||||
|
public void addTopic(LookAndFeel laf, String name, String tip, Icon icon, String regName);
|
||||||
|
|
||||||
|
// 状态管理方法
|
||||||
|
public boolean isLoading(String themeName);
|
||||||
|
public void setLoading(String themeName);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- `addTopic(String topicClass, String name, String tip, Icon icon, String regName)`: 向主题注册中心添加一个新的主题。
|
||||||
|
- `addTopic(LookAndFeel laf, String name, String tip, Icon icon, String regName)`: 向主题注册中心添加一个新的主题,同时关联LookAndFeel。
|
||||||
|
- `isLoading(String themeName)`: 判断指定主题是否正在加载。
|
||||||
|
- `setLoading(String themeName)`: 设置指定主题为正在加载状态。
|
||||||
|
#### 注册示例
|
||||||
|
```java
|
||||||
|
try {
|
||||||
|
// 重复注册相同名称
|
||||||
|
topicRegistry.addTopic("com.axis.light.MaterialTheme",
|
||||||
|
"质感浅色",
|
||||||
|
"Material Design风格",
|
||||||
|
materialIcon,
|
||||||
|
"theme:light"); // 已存在同名注册
|
||||||
|
} catch (RegistrationError ex) {
|
||||||
|
// 捕获异常并提示:theme:light duplicate registered names
|
||||||
|
JOptionPane.showMessageDialog(null, ex.getMessage());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. StateManager
|
||||||
|
应用程序状态管理工具类,提供跨会话的配置持久化能力:
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.axis.innovators.box.tools;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态持久化管理器(线程安全)
|
||||||
|
*/
|
||||||
|
public class StateManager {
|
||||||
|
// 构造方法
|
||||||
|
public StateManager(); // 默认使用toolbox.properties
|
||||||
|
public StateManager(String customFileName); // 自定义状态文件名
|
||||||
|
|
||||||
|
// 核心操作方法
|
||||||
|
public void saveState(String key, [int|long|boolean...] value);
|
||||||
|
public [String|int|boolean...] getStateAs[Type](String key);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- `saveState(String key, [int|long|boolean...] value)`: 保存状态到配置文件。
|
||||||
|
- `getStateAs[Type](String key)`: 从配置文件获取状态。
|
||||||
|
- `[String|int|boolean...]`: 支持多种数据类型保存到配置文件,并支持多种数据类型从配置文件获取。
|
||||||
|
|
||||||
|
### 5. RegistrationSettingsItem
|
||||||
|
负责管理系统 **设置中心** 的配置面板注册,支持插件化扩展设置项的核心组件:
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.axis.innovators.box.register;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置项注册中心(集成插件配置扩展能力)
|
||||||
|
*/
|
||||||
|
public class RegistrationSettingsItem extends WindowsJDialog {
|
||||||
|
// 核心注册方法
|
||||||
|
public void addSettings(JPanel panel, String title, Icon icon, String tip, String regName);
|
||||||
|
public void addSettings(JPanel panel, String title, Icon icon, String tip,
|
||||||
|
PluginDescriptor plugin, String regName);
|
||||||
|
|
||||||
|
// 查询方法
|
||||||
|
public static List<RegistrationSettingsItem> getRegistrationsByPlugin(PluginDescriptor plugin);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- `addSettings(JPanel panel, String title, Icon icon, String tip, String regName)`: 向设置项注册中心添加一个新的设置项。
|
||||||
|
- `addSettings(JPanel panel, String title, Icon icon, String tip, PluginDescriptor plugin, String regName)`: 向设置项注册中心添加一个新的设置项,同时关联插件描述符。
|
||||||
|
- `getRegistrationsByPlugin(PluginDescriptor plugin)`: 通过插件描述符获取关联的设置项列表。
|
||||||
|
|
||||||
|
### 6. LanguageManager
|
||||||
|
应用程序多语言管理核心组件,支持动态加载与合并多语言资源:
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.axis.innovators.box.register;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 国际化语言管理中心(支持插件扩展语言包)
|
||||||
|
*/
|
||||||
|
public class LanguageManager {
|
||||||
|
// 核心操作方法
|
||||||
|
public static void addLanguage(Language lang);
|
||||||
|
public static void loadLanguage(String regName);
|
||||||
|
public static Language getLoadedLanguages();
|
||||||
|
public static Language getLanguage(String identifier);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- `addLanguage(Language lang)`: 向语言管理中心添加一个新的语言包。
|
||||||
|
- `loadLanguage(String regName)`: 加载指定语言包。
|
||||||
|
- `getLoadedLanguages()`: 获取当前系统加载的语言包。
|
||||||
|
- `getLanguage(String identifier)`: 通过标识符获取语言包。
|
||||||
|
|
||||||
@@ -56,6 +56,9 @@ public class CefAppManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化Cef
|
||||||
|
*/
|
||||||
private static void initializeDefaultSettings() {
|
private static void initializeDefaultSettings() {
|
||||||
initLock.lock();
|
initLock.lock();
|
||||||
try {
|
try {
|
||||||
@@ -112,6 +115,10 @@ public class CefAppManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断地区主题是否为黑色主题
|
||||||
|
* @return 是否
|
||||||
|
*/
|
||||||
private static boolean isDarkTheme() {
|
private static boolean isDarkTheme() {
|
||||||
if (AxisInnovatorsBox.getMain() == null){
|
if (AxisInnovatorsBox.getMain() == null){
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ public class MainApplication {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void popupCodeEditorWindow() {
|
public static void popupCodeEditorWindow() {
|
||||||
AtomicReference<BrowserWindow> window = new AtomicReference<>();
|
AtomicReference<BrowserWindow> window = new AtomicReference<>();
|
||||||
SwingUtilities.invokeLater(() -> {
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
|||||||
@@ -21,6 +21,13 @@ public class CodeExecutor {
|
|||||||
void onOutput(String newOutput);
|
void onOutput(String newOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行代码
|
||||||
|
* @param code 代码字符串
|
||||||
|
* @param language 代码类型
|
||||||
|
* @param listener 回调,代码的输出回调
|
||||||
|
* @return 返回i执行结果
|
||||||
|
*/
|
||||||
public static String executeCode(String code, String language, OutputListener listener) {
|
public static String executeCode(String code, String language, OutputListener listener) {
|
||||||
switch (language.toLowerCase()) {
|
switch (language.toLowerCase()) {
|
||||||
case "python":
|
case "python":
|
||||||
@@ -35,6 +42,10 @@ public class CodeExecutor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行Java代码
|
||||||
|
* @return 返回执行结果
|
||||||
|
*/
|
||||||
public static String executeJavaCode(String code, OutputListener listener) {
|
public static String executeJavaCode(String code, OutputListener listener) {
|
||||||
Path tempDir = null;
|
Path tempDir = null;
|
||||||
try {
|
try {
|
||||||
@@ -176,6 +187,9 @@ public class CodeExecutor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行C代码
|
||||||
|
*/
|
||||||
private static String executeC(String code, OutputListener listener) {
|
private static String executeC(String code, OutputListener listener) {
|
||||||
Path tempDir = null;
|
Path tempDir = null;
|
||||||
Path cFile = null;
|
Path cFile = null;
|
||||||
@@ -316,63 +330,6 @@ public class CodeExecutor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String captureProcessOutput(Process process, OutputListener listener)
|
|
||||||
throws IOException {
|
|
||||||
StringBuilder totalOutput = new StringBuilder();
|
|
||||||
try (BufferedReader reader = new BufferedReader(
|
|
||||||
new InputStreamReader(process.getInputStream()))) {
|
|
||||||
|
|
||||||
String line;
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
totalOutput.append(line).append("\n");
|
|
||||||
if (listener != null) {
|
|
||||||
listener.onOutput(line + "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return totalOutput.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 输出监控线程
|
|
||||||
private static class OutputMonitor implements Runnable {
|
|
||||||
private final BufferedReader reader;
|
|
||||||
private final OutputListener listener;
|
|
||||||
private volatile boolean running = true;
|
|
||||||
private final StringBuilder totalOutput = new StringBuilder();
|
|
||||||
|
|
||||||
public OutputMonitor(BufferedReader reader, OutputListener listener) {
|
|
||||||
this.reader = reader;
|
|
||||||
this.listener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
while (running) {
|
|
||||||
if (reader.ready()) {
|
|
||||||
String line = reader.readLine();
|
|
||||||
if (line != null) {
|
|
||||||
totalOutput.append(line).append("\n");
|
|
||||||
if (listener != null) {
|
|
||||||
listener.onOutput(line + "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Thread.sleep(50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTotalOutput() {
|
|
||||||
return totalOutput.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用方法
|
// 使用方法
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@@ -108,6 +108,25 @@ public class RegistrationTool {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
MainWindow.ToolCategory hahahah = new MainWindow.ToolCategory(
|
||||||
|
"good工具",
|
||||||
|
"haha/ok.png",
|
||||||
|
"good "
|
||||||
|
);
|
||||||
|
hahahah.addTool(new MainWindow.ToolItem("123", "ai/local/local_main.png",
|
||||||
|
"456789" +
|
||||||
|
"\n作者:Vinfya", ++id, new AbstractAction() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
// 在这里写
|
||||||
|
// 这个就是弹窗Ok
|
||||||
|
JOptionPane.showMessageDialog(null, "你好...");
|
||||||
|
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MainWindow.ToolCategory systemCategory = new MainWindow.ToolCategory("系统工具",
|
MainWindow.ToolCategory systemCategory = new MainWindow.ToolCategory("系统工具",
|
||||||
"windows/windows.png",
|
"windows/windows.png",
|
||||||
"系统工具");
|
"系统工具");
|
||||||
@@ -125,6 +144,8 @@ public class RegistrationTool {
|
|||||||
addToolCategory(aICategory,"system:fridaTools");
|
addToolCategory(aICategory,"system:fridaTools");
|
||||||
addToolCategory(programmingToolsCategory, "system:programmingTools");
|
addToolCategory(programmingToolsCategory, "system:programmingTools");
|
||||||
addToolCategory(systemCategory, "system:systemTools");
|
addToolCategory(systemCategory, "system:systemTools");
|
||||||
|
addToolCategory(hahahah, "system:mc");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1463,12 +1463,24 @@ public class MainWindow extends JFrame {
|
|||||||
private final String description;
|
private final String description;
|
||||||
private final UUID id = UUID.randomUUID();
|
private final UUID id = UUID.randomUUID();
|
||||||
private final List<ToolItem> tools = new ArrayList<>();
|
private final List<ToolItem> tools = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类
|
||||||
|
* @param name 分类名称
|
||||||
|
* @param icon 分类的图标
|
||||||
|
* @param description 分类的描述
|
||||||
|
*/
|
||||||
public ToolCategory(String name, String icon, String description) {
|
public ToolCategory(String name, String icon, String description) {
|
||||||
this.name = name; this.icon = icon; this.description = description; this.iconImage = null;
|
this.name = name; this.icon = icon; this.description = description; this.iconImage = null;
|
||||||
}
|
}
|
||||||
public ToolCategory(String name, ImageIcon icon, String description) {
|
public ToolCategory(String name, ImageIcon icon, String description) {
|
||||||
this.name = name; this.iconImage = icon; this.description = description; this.icon = null;
|
this.name = name; this.iconImage = icon; this.description = description; this.icon = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在当前分类中创建一个新的工具卡片
|
||||||
|
* @param tool 工具卡片
|
||||||
|
*/
|
||||||
public void addTool(ToolItem tool) { tools.add(tool); }
|
public void addTool(ToolItem tool) { tools.add(tool); }
|
||||||
public String getDescription() { return description; }
|
public String getDescription() { return description; }
|
||||||
public String getIcon() {
|
public String getIcon() {
|
||||||
@@ -1490,6 +1502,15 @@ public class MainWindow extends JFrame {
|
|||||||
private final String description;
|
private final String description;
|
||||||
private final int id;
|
private final int id;
|
||||||
private final Action action;
|
private final Action action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个新的工具
|
||||||
|
* @param title 工具的标题
|
||||||
|
* @param icon 工具的图标
|
||||||
|
* @param description 工具的介绍
|
||||||
|
* @param id 工具的id(不要重复即可)
|
||||||
|
* @param action 点击工具卡片后触发的事件
|
||||||
|
*/
|
||||||
public ToolItem(String title, String icon, String description, int id, Action action) {
|
public ToolItem(String title, String icon, String description, int id, Action action) {
|
||||||
this.title = title; this.icon = icon; this.description = description; this.id = id; this.action = action; this.imageIcon = null;
|
this.title = title; this.icon = icon; this.description = description; this.id = id; this.action = action; this.imageIcon = null;
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
src/main/resources/icons/haha/ok.png
Normal file
BIN
src/main/resources/icons/haha/ok.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 114 KiB |
Reference in New Issue
Block a user