refactor(jar): 重构 ModernJarViewer 并优化文件打开逻辑
- 将 ModernJarViewer从 JDialog 改为 JFrame,独立运行 - 优化文件打开逻辑,支持从命令行参数直接打开 jar 文件 - 改进搜索功能,支持增量搜索和循环搜索 - 调整 UI 样式,支持中文菜单- 移除冗余代码,提高代码可维护性
This commit is contained in:
@@ -340,19 +340,6 @@ public class AxisInnovatorsBox {
|
||||
for (Map<String, String> fileInfo : validFiles) {
|
||||
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()) {
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
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.tools.ArgsParser;
|
||||
import com.axis.innovators.box.tools.FolderCleaner;
|
||||
import com.axis.innovators.box.tools.FolderCreator;
|
||||
import com.axis.innovators.box.register.LanguageManager;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author tzdwindows 7
|
||||
@@ -18,7 +25,23 @@ public class Main {
|
||||
LanguageManager.loadLanguage("system:zh_CN");
|
||||
}
|
||||
|
||||
System.out.println(Arrays.toString(args));
|
||||
List<Map<String, String>> validFiles = ArgsParser.parseArgs(args);
|
||||
for (Map<String, String> fileInfo : validFiles) {
|
||||
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);
|
||||
viewer.setVisible(true);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
AxisInnovatorsBox.run(args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.axis.innovators.box.decompilation.gui;
|
||||
|
||||
import com.axis.innovators.box.gui.LoadIcon;
|
||||
import com.axis.innovators.box.gui.WindowsJDialog;
|
||||
import com.axis.innovators.box.register.LanguageManager;
|
||||
import com.github.javaparser.JavaParser;
|
||||
import com.github.javaparser.ParseResult;
|
||||
import com.github.javaparser.Position;
|
||||
@@ -18,6 +19,7 @@ import java.awt.event.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.Timer;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import javax.swing.event.TreeSelectionEvent;
|
||||
import javax.swing.event.TreeSelectionListener;
|
||||
@@ -39,7 +41,7 @@ import java.util.regex.Pattern;
|
||||
/**
|
||||
* @author tzdwindows 7
|
||||
*/
|
||||
public class ModernJarViewer extends WindowsJDialog {
|
||||
public class ModernJarViewer extends JFrame {
|
||||
private final DefaultListModel<SearchResult> globalSearchResults = new DefaultListModel<>();
|
||||
private JTree fileTree;
|
||||
private JTabbedPane contentPane;
|
||||
@@ -52,40 +54,40 @@ public class ModernJarViewer extends WindowsJDialog {
|
||||
private DefaultMutableTreeNode root;
|
||||
|
||||
public ModernJarViewer(Frame owner) {
|
||||
super(owner, "Jar反编译工具", true);
|
||||
setTitle("Jar反编译工具");
|
||||
setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
initComponents();
|
||||
}
|
||||
|
||||
/****/
|
||||
public ModernJarViewer(Frame owner, String jarFile) {
|
||||
super(owner, "Jar反编译工具", true);
|
||||
setTitle("Jar反编译工具");
|
||||
setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
initComponents();
|
||||
loadJar(new File(jarFile));
|
||||
}
|
||||
|
||||
/****/
|
||||
private void initComponents() {
|
||||
setSize(1280, 800);
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
setLocationRelativeTo(null);
|
||||
|
||||
setIconImage(LoadIcon.loadIcon("logo.png", 32).getImage());
|
||||
|
||||
// 初始化菜单
|
||||
JMenuBar menuBar = new JMenuBar();
|
||||
JMenu fileMenu = new JMenu("File");
|
||||
JMenuItem openItem = new JMenuItem("Open");
|
||||
JMenu fileMenu = new JMenu("文件");
|
||||
JMenuItem openItem = new JMenuItem("打开");
|
||||
openItem.addActionListener(e -> openJarFile());
|
||||
fileMenu.add(openItem);
|
||||
menuBar.add(fileMenu);
|
||||
setJMenuBar(menuBar);
|
||||
|
||||
// 初始化文件树
|
||||
root = new DefaultMutableTreeNode("Root");
|
||||
root = new DefaultMutableTreeNode("根目录");
|
||||
fileTree = new JTree(new DefaultTreeModel(root));
|
||||
fileTree.addTreeSelectionListener(new TreeSelectionHandler());
|
||||
JScrollPane treeScroll = new JScrollPane(fileTree);
|
||||
|
||||
// 初始化代码编辑器
|
||||
codeArea = new RSyntaxTextArea();
|
||||
codeArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
|
||||
codeArea.setCodeFoldingEnabled(true);
|
||||
@@ -104,13 +106,11 @@ public class ModernJarViewer extends WindowsJDialog {
|
||||
});
|
||||
|
||||
codeArea.setToolTipSupplier((textArea, mouseEvent) -> {
|
||||
// 优先检查方法链接
|
||||
currentHoveredMethod = findMethodUnderCursor(mouseEvent.getPoint());
|
||||
if (currentHoveredMethod != null) {
|
||||
return buildMethodTooltip(currentHoveredMethod);
|
||||
}
|
||||
|
||||
// 回退到Javadoc检查
|
||||
String javadoc = getJavadocAtCursor();
|
||||
return javadoc != null ? formatJavadoc(javadoc) : null;
|
||||
});
|
||||
@@ -141,18 +141,16 @@ public class ModernJarViewer extends WindowsJDialog {
|
||||
codeArea.setCurrentLineHighlightColor(new Color(0x323232));
|
||||
|
||||
|
||||
// 使用 RTextScrollPane 支持代码折叠
|
||||
RTextScrollPane codeScrollPane = new RTextScrollPane(codeArea);
|
||||
codeScrollPane.setLineNumbersEnabled(true);
|
||||
codeScrollPane.setFoldIndicatorEnabled(true);
|
||||
|
||||
// 初始化图片预览
|
||||
imageLabel = new JLabel();
|
||||
JScrollPane imageScrollPane = new JScrollPane(imageLabel);
|
||||
|
||||
contentPane = new JTabbedPane();
|
||||
contentPane.addTab("Code", codeScrollPane);
|
||||
contentPane.addTab("Image", imageScrollPane);
|
||||
contentPane.addTab("代码", codeScrollPane);
|
||||
contentPane.addTab("图片", imageScrollPane);
|
||||
codeArea.setCodeFoldingEnabled(true);
|
||||
|
||||
Font ideaFont = new Font("JetBrains Mono", Font.PLAIN, 13);
|
||||
@@ -224,6 +222,8 @@ public class ModernJarViewer extends WindowsJDialog {
|
||||
}
|
||||
}
|
||||
|
||||
private JDialog currentSearchDialog = null;
|
||||
private JDialog currentGlobalSearchDialog = null;
|
||||
private void setupKeyBindings() {
|
||||
// 本地文件搜索
|
||||
KeyStroke ctrlF = KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_DOWN_MASK);
|
||||
@@ -245,11 +245,25 @@ public class ModernJarViewer extends WindowsJDialog {
|
||||
}
|
||||
|
||||
private void showLocalSearchDialog() {
|
||||
JDialog searchDialog = new JDialog(this, "查找", false);
|
||||
if (currentSearchDialog != null && currentSearchDialog.isVisible()) {
|
||||
currentSearchDialog.setVisible(true);
|
||||
return;
|
||||
}
|
||||
|
||||
currentSearchDialog = new JDialog(this, "查找", false);
|
||||
JTextField searchField = new JTextField(20);
|
||||
JButton nextButton = new JButton("下一个");
|
||||
JButton prevButton = new JButton("上一个");
|
||||
|
||||
searchField.addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
||||
searchInText(searchField.getText(), true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
nextButton.addActionListener(e -> searchInText(searchField.getText(), true));
|
||||
prevButton.addActionListener(e -> searchInText(searchField.getText(), false));
|
||||
|
||||
@@ -258,10 +272,32 @@ public class ModernJarViewer extends WindowsJDialog {
|
||||
panel.add(prevButton);
|
||||
panel.add(nextButton);
|
||||
|
||||
searchDialog.add(panel);
|
||||
searchDialog.pack();
|
||||
searchDialog.setLocationRelativeTo(this);
|
||||
searchDialog.setVisible(true);
|
||||
currentSearchDialog.add(panel);
|
||||
currentSearchDialog.pack();
|
||||
currentSearchDialog.setLocationRelativeTo(this);
|
||||
|
||||
Point editorLocation = codeArea.getLocationOnScreen();
|
||||
int editorWidth = codeArea.getWidth();
|
||||
int dialogWidth = currentSearchDialog.getWidth();
|
||||
|
||||
int offsetX = -5;
|
||||
int offsetY = 0;
|
||||
|
||||
currentSearchDialog.setLocation(editorLocation.x + editorWidth - dialogWidth - offsetX, editorLocation.y + offsetY);
|
||||
currentSearchDialog.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
closeSearchDialog();
|
||||
}
|
||||
});
|
||||
currentSearchDialog.setVisible(true);
|
||||
}
|
||||
|
||||
private void closeSearchDialog() {
|
||||
if (currentSearchDialog != null) {
|
||||
currentSearchDialog.dispose();
|
||||
currentSearchDialog = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void searchInText(String pattern, boolean forward) {
|
||||
@@ -272,60 +308,82 @@ public class ModernJarViewer extends WindowsJDialog {
|
||||
int index = text.indexOf(pattern, caret);
|
||||
if (index != -1) {
|
||||
codeArea.select(index, index + pattern.length());
|
||||
} else {
|
||||
int reverseIndex = text.lastIndexOf(pattern, caret - pattern.length());
|
||||
if (reverseIndex != -1) {
|
||||
codeArea.select(reverseIndex, reverseIndex + pattern.length());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int index = text.lastIndexOf(pattern, caret - pattern.length());
|
||||
if (index != -1) {
|
||||
codeArea.select(index, index + pattern.length());
|
||||
} else {
|
||||
int forwardIndex = text.indexOf(pattern, caret);
|
||||
if (forwardIndex != -1) {
|
||||
codeArea.select(forwardIndex, forwardIndex + pattern.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showGlobalSearchDialog() {
|
||||
JDialog globalDialog = new JDialog(this, "全局搜索", false);
|
||||
if (currentGlobalSearchDialog != null && currentGlobalSearchDialog.isVisible()) {
|
||||
currentGlobalSearchDialog.setVisible(true);
|
||||
return;
|
||||
}
|
||||
currentGlobalSearchDialog = new JDialog(this, "全局搜索", false);
|
||||
JTextField searchField = new JTextField(30);
|
||||
JButton searchButton = new JButton("搜索");
|
||||
DefaultListModel<SearchResult> listModel = new DefaultListModel<>();
|
||||
JList<SearchResult> resultList = new JList<>(listModel);
|
||||
|
||||
// 添加搜索按钮的监听器
|
||||
searchButton.addActionListener(e -> {
|
||||
// 在后台线程中执行搜索操作
|
||||
new SwingWorker<Void, SearchResult>() {
|
||||
@Override
|
||||
protected Void doInBackground() throws Exception {
|
||||
searchInJar(searchField.getText(), listModel); // 耗时的搜索操作
|
||||
searchInJar(searchField.getText(), listModel);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
// 搜索完成后更新 UI
|
||||
JOptionPane.showMessageDialog(globalDialog, "搜索完成!");
|
||||
JOptionPane.showMessageDialog(currentGlobalSearchDialog, "搜索完成!");
|
||||
}
|
||||
}.execute();
|
||||
});
|
||||
|
||||
// 添加结果列表的监听器
|
||||
resultList.addListSelectionListener(e -> {
|
||||
SearchResult result = resultList.getSelectedValue();
|
||||
if (result != null) {
|
||||
navigateToSearchResult(result); // 跳转到搜索结果
|
||||
navigateToSearchResult(result);
|
||||
}
|
||||
});
|
||||
|
||||
// 设置布局
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.add(searchField, BorderLayout.NORTH);
|
||||
panel.add(new JScrollPane(resultList), BorderLayout.CENTER);
|
||||
panel.add(searchButton, BorderLayout.SOUTH);
|
||||
|
||||
globalDialog.add(panel);
|
||||
globalDialog.setSize(500, 400);
|
||||
globalDialog.setLocationRelativeTo(this);
|
||||
globalDialog.setVisible(true); // 显示对话框
|
||||
currentGlobalSearchDialog.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
closeGlobalSearchDialog();
|
||||
}
|
||||
});
|
||||
|
||||
currentGlobalSearchDialog.add(panel);
|
||||
currentGlobalSearchDialog.setSize(500, 400);
|
||||
currentGlobalSearchDialog.setLocationRelativeTo(this);
|
||||
currentGlobalSearchDialog.setVisible(true);
|
||||
}
|
||||
|
||||
private void closeGlobalSearchDialog() {
|
||||
if (currentGlobalSearchDialog != null) {
|
||||
currentGlobalSearchDialog.dispose();
|
||||
currentGlobalSearchDialog = null;
|
||||
}
|
||||
}
|
||||
private void navigateToSearchResult(SearchResult result) {
|
||||
expandTreeToClass(result.filePath);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user