feat(box): 现代化用户界面并添加 jar 文件预览功能

- 使用 FlatDarculaLaf 样式库替换默认样式
- 添加 jar 文件预览功能,使用 CFR 进行反编译
- 更新 build.gradle 文件,添加新依赖项
- 新增 CFROutputSinkFactory 和 JarClassFileSource 类
- 修改主程序启动逻辑,支持 jar 文件预览
This commit is contained in:
tzdwindows 7
2025-02-23 13:31:14 +08:00
parent ce996b73be
commit e422d31b85
12 changed files with 1225 additions and 11 deletions

View File

@@ -2,6 +2,7 @@ plugins {
id 'java'
id 'application'
id 'edu.sc.seis.launch4j' version '2.5.4'
id 'org.openjfx.javafxplugin' version '0.1.0'
}
// JDK 版本检查
@@ -58,7 +59,23 @@ dependencies {
implementation 'org.python:jython-standalone:2.7.3'
implementation 'org.fxmisc.richtext:richtextfx:0.11.0' // 更新后的richtextfx
implementation 'org.bitbucket.mstrobel:procyon-core:0.5.36' // 使用JitPack版本
implementation 'org.bitbucket.mstrobel:procyon-compilertools:0.5.36'
implementation 'com.fifesoft:rsyntaxtextarea:3.3.0'
implementation 'org.apache.commons:commons-compress:1.23.0'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'
implementation 'org.controlsfx:controlsfx:11.1.2' // 现代化UI组件
implementation 'com.dlsc.formsfx:formsfx-core:11.6.0' // 表单组件
implementation 'net.sourceforge.plantuml:plantuml:8059' // UML支持可选)
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'org.openjfx:javafx-controls:21'
implementation 'org.benf:cfr:0.152'
implementation 'com.github.javaparser:javaparser-core:3.25.1'
}
// 分离依赖项到 libs 目录
@@ -108,6 +125,11 @@ tasks.withType(JavaExec).configureEach {
]
}
javafx {
version = "21"
modules = [ 'javafx.controls', 'javafx.fxml' ]
}
// 单独打包文档
task packageOpenSourceDocs(type: Jar) {
archiveClassifier = 'docs'
@@ -122,7 +144,8 @@ application {
// 确保运行时参数生效
applicationDefaultJvmArgs = [
"-Djava.system.class.loader=com.axis.innovators.box.plugins.BoxClassLoader",
"-Dloader.library.path=$buildDir/libs/libs"
"-Dloader.library.path=$buildDir/libs/libs",
'-Dfile.encoding=UTF-8'
]
}

Binary file not shown.

View File

@@ -5,13 +5,41 @@
版本1.1
"""
from com.axis.innovators.box.python import PyLocalSide
from javax.swing import AbstractAction
from javax.swing import AbstractAction, JFrame,JDialog, JLabel, JButton, JPanel, JOptionPane
from java.awt import BorderLayout, Dimension
from java.awt.event import ActionListener
class MyAction(AbstractAction):
def actionPerformed(self, event):
"""工具项点击事件处理"""
print("[DEBUG] Tool item clicked! Event source:", event.getSource())
# 创建 JDialog 作为子窗口
parent_frame = event.getSource().getTopLevelAncestor() # 获取父窗口
dialog = JDialog(parent_frame, u"工具面板", True) # True 表示模态对话框
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE) # 关闭时释放资源
dialog.setSize(300, 200)
dialog.setLocationRelativeTo(parent_frame) # 居中于父窗口
# 创建面板并设置布局
panel = JPanel()
panel.layout = BorderLayout() # 使用边界布局
# 添加标签
label = JLabel(u"这是工具项的子面板")
panel.add(label, BorderLayout.CENTER)
# 添加关闭按钮
close_btn = JButton(u"关闭")
close_btn.addActionListener(lambda e: dialog.dispose()) # 点击关闭窗口
panel.add(close_btn, BorderLayout.SOUTH)
# 将面板添加到窗口
dialog.add(panel)
dialog.visible = True # 显示窗口
def onStartup():
"""
系统启动时自动执行的初始化逻辑

View File

@@ -1,5 +1,6 @@
package com.axis.innovators.box;
import com.axis.innovators.box.decompilation.gui.ModernJarViewer;
import com.axis.innovators.box.events.GlobalEventBus;
import com.axis.innovators.box.events.OpenFileEvents;
import com.axis.innovators.box.events.StartupEvent;
@@ -26,6 +27,7 @@ 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;
@@ -334,11 +336,24 @@ public class AxisInnovatorsBox {
try {
main.initLog4j2();
main.setTopic();
List<Map<String, String>> validFiles = ArgsParser.parseArgs(args);
for (Map<String, String> fileInfo : validFiles) {
OpenFileEvents openFileEvents = new OpenFileEvents(fileInfo.get("path"), fileInfo.get("extension"));
String extension = fileInfo.get("extension");
String path = fileInfo.get("path");
if (".jar".equals(extension)){
SwingUtilities.invokeLater(() -> {
try {
UIManager.setLookAndFeel(new com.formdev.flatlaf.FlatDarculaLaf());
} catch (Exception ex) {
ex.printStackTrace();
}
ModernJarViewer viewer = new ModernJarViewer(null, path);
main.popupWindow(viewer);
});
main.progressBarManager.close();
return;
}
OpenFileEvents openFileEvents = new OpenFileEvents(path, extension);
GlobalEventBus.EVENT_BUS.post(openFileEvents);
if (!openFileEvents.isContinue()) {
return;

View File

@@ -4,6 +4,8 @@ import com.axis.innovators.box.tools.FolderCleaner;
import com.axis.innovators.box.tools.FolderCreator;
import com.axis.innovators.box.register.LanguageManager;
import java.util.Arrays;
/**
* @author tzdwindows 7
*/
@@ -16,6 +18,7 @@ public class Main {
LanguageManager.loadLanguage("system:zh_CN");
}
System.out.println(Arrays.toString(args));
AxisInnovatorsBox.run(args);
}
}

View File

@@ -0,0 +1,51 @@
package com.axis.innovators.box.decompilation.gui;
import org.benf.cfr.reader.api.OutputSinkFactory;
import org.benf.cfr.reader.api.SinkReturns.Decompiled;
import org.benf.cfr.reader.api.SinkReturns.ExceptionMessage;
import org.benf.cfr.reader.api.SinkReturns;
import javax.swing.*;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class CFROutputSinkFactory implements OutputSinkFactory {
private JTextArea codeArea;
private StringBuilder output = new StringBuilder();
public CFROutputSinkFactory(JTextArea codeArea) {
this.codeArea = codeArea;
}
public CFROutputSinkFactory() {
}
@Override
public List<SinkClass> getSupportedSinks(SinkType sgetOutputinkType, Collection<SinkClass> collection) {
return Collections.singletonList(SinkClass.DECOMPILED);
}
public String getOutput() {
return output.toString();
}
@Override
public <T> Sink<T> getSink(SinkType sinkType, SinkClass sinkClass) {
if (sinkClass == SinkClass.DECOMPILED) {
return (Sink<T>) new Sink<SinkReturns.Decompiled>() {
@Override
public void write(Decompiled decompiled) {
if (codeArea != null) {
SwingUtilities.invokeLater(() ->
codeArea.setText(decompiled.getJava())
);
}
output.append(decompiled.getJava()).append("\n");
}
};
}
return null;
}
}

View File

@@ -0,0 +1,47 @@
package com.axis.innovators.box.decompilation.gui;
import org.benf.cfr.reader.api.ClassFileSource;
import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class JarClassFileSource implements ClassFileSource {
private final JarFile jarFile;
public JarClassFileSource(JarFile jarFile) {
this.jarFile = jarFile;
}
@Override
public void informAnalysisRelativePathDetail(String usePath, String classFilePath) {
}
@Override
public Collection<String> addJar(String jarPath) {
return Collections.emptyList();
}
@Override
public String getPossiblyRenamedPath(String path) {
return path;
}
@Override
public Pair<byte[], String> getClassFileContent(String path) throws IOException {
JarEntry entry = jarFile.getJarEntry(path);
if (entry == null) {
return null;
}
try (InputStream is = jarFile.getInputStream(entry)) {
byte[] bytes = new byte[(int) entry.getSize()];
is.read(bytes);
return Pair.make(bytes, path);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -25,7 +25,7 @@ public class LoadIcon {
* @param size 图片大小
* @return ImageIcon对象
*/
static ImageIcon loadIcon(String filename, int size) {
public static ImageIcon loadIcon(String filename, int size) {
return loadIcon(LoadIcon.class, filename, size);
}

View File

@@ -26,6 +26,7 @@ public class BoxClassLoader extends URLClassLoader {
"java.", "javax.", "sun.", "com.sun.", "jdk.",
"org.xml.", "org.w3c.", "org.apache.",
"javax.management.", "javax.swing."
, "javafx."
);
}

View File

@@ -64,11 +64,12 @@ public class ArgsParser {
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" // 目录,不是文件
"C:\\Program Files\\test.txt",
"C:\\invalid_file.exe",
"D:\\Documents\\report.pdf",
"not_a_path",
"C:\\Windows\\system32" ,
"C:\\Users\\Administrator\\MCreatorWorkspaces\\AxisInnovatorsBox\\build.gradle"
};
// 解析 args 参数

View File

@@ -0,0 +1,45 @@
.root {
-fx-base: #2D2D2D;
-fx-background: #1E1E1E;
-fx-control-inner-background: derive(-fx-base, 20%);
-fx-accent: #45A1FF;
}
.menu-bar {
-fx-background-color: linear-gradient(to bottom, #3C3C3C, #2D2D2D);
}
.tree-view {
-fx-background-color: -fx-base;
-fx-border-color: derive(-fx-base, -10%);
}
.tree-cell {
-fx-text-fill: #DCDCDC;
-fx-font-size: 14px;
}
.tree-cell:selected {
-fx-background-color: #45A1FF;
-fx-text-fill: white;
}
.code-area {
-fx-font-family: "JetBrains Mono";
-fx-font-size: 14px;
-fx-highlight-fill: #264F78;
}
.tab-pane {
-fx-background-color: derive(-fx-base, 10%);
}
.tab {
-fx-background-color: linear-gradient(to bottom, #3C3C3C, #2D2D2D);
-fx-text-fill: #DCDCDC;
}
.tab:selected {
-fx-background-color: #45A1FF;
-fx-text-fill: white;
}