diff --git a/README.md b/README.md index c251191..e36b697 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # JavaOctetEditor -![](https://user-images.githubusercontent.com/32991121/179437944-92726f48-5fe9-44c1-a65d-38b4091e8a84.png) +![](https://s1.ax1x.com/2022/07/30/vi7Lp8.png) diff --git a/build.gradle b/build.gradle index f85207d..f773473 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { } group 'cn.enaium' -version '0.5.0' +version '0.6.0' sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8 diff --git a/src/main/java/cn/enaium/joe/dialog/SearchDialog.java b/src/main/java/cn/enaium/joe/dialog/SearchDialog.java index 6e769aa..08b2904 100644 --- a/src/main/java/cn/enaium/joe/dialog/SearchDialog.java +++ b/src/main/java/cn/enaium/joe/dialog/SearchDialog.java @@ -16,9 +16,20 @@ package cn.enaium.joe.dialog; +import cn.enaium.joe.JavaOctetEditor; +import cn.enaium.joe.gui.panel.search.ResultNode; import cn.enaium.joe.gui.panel.search.ResultPanel; +import cn.enaium.joe.jar.Jar; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodNode; +import javax.swing.*; import java.awt.*; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Consumer; /** * @author Enaium @@ -32,4 +43,25 @@ public SearchDialog() { setSize(700, 400); add(resultPanel, BorderLayout.CENTER); } + + public void searchInstruction(BiConsumer consumer) { + Jar jar = JavaOctetEditor.getInstance().jar; + float loaded = 0; + float total = 0; + for (Map.Entry stringClassNodeEntry : jar.classes.entrySet()) { + for (MethodNode method : stringClassNodeEntry.getValue().methods) { + total += method.instructions.size(); + } + } + + for (Map.Entry stringClassNodeEntry : jar.classes.entrySet()) { + for (MethodNode method : stringClassNodeEntry.getValue().methods) { + for (AbstractInsnNode instruction : method.instructions) { + consumer.accept(stringClassNodeEntry.getValue(), instruction); + JavaOctetEditor.getInstance().bottomPanel.setProcess((int) ((loaded++ / total) * 100f)); + } + } + } + JavaOctetEditor.getInstance().bottomPanel.setProcess(0); + } } diff --git a/src/main/java/cn/enaium/joe/dialog/search/SearchFieldDialog.java b/src/main/java/cn/enaium/joe/dialog/search/SearchFieldDialog.java index aba4d90..cbfee28 100644 --- a/src/main/java/cn/enaium/joe/dialog/search/SearchFieldDialog.java +++ b/src/main/java/cn/enaium/joe/dialog/search/SearchFieldDialog.java @@ -51,32 +51,17 @@ public SearchFieldDialog() { add(new JButton("Search") {{ addActionListener(e -> { ASyncUtil.execute(() -> { - float loaded = 0; - float total = 0; - Jar jar = JavaOctetEditor.getInstance().jar; - for (Map.Entry stringClassNodeEntry : jar.classes.entrySet()) { - for (MethodNode method : stringClassNodeEntry.getValue().methods) { - total += method.instructions.size(); - } - } - - for (Map.Entry stringClassNodeEntry : jar.classes.entrySet()) { - for (MethodNode method : stringClassNodeEntry.getValue().methods) { - for (AbstractInsnNode instruction : method.instructions) { - if (instruction instanceof FieldInsnNode) { - FieldInsnNode fieldInsnNode = (FieldInsnNode) instruction; - if ((fieldInsnNode.owner.contains(owner.getText()) || StringUtil.isBlank(owner.getText())) && - (fieldInsnNode.name.contains(name.getText()) || StringUtil.isBlank(name.getText())) && - (fieldInsnNode.desc.contains(description.getText()) || StringUtil.isBlank(description.getText())) - ) { - ((DefaultListModel) resultPanel.getList().getModel()).addElement(new ResultNode(stringClassNodeEntry.getValue(), fieldInsnNode.name + ":" + fieldInsnNode.desc)); - } - } - JavaOctetEditor.getInstance().bottomPanel.setProcess((int) ((loaded++ / total) * 100f)); + searchInstruction((classNode, instruction) -> { + if (instruction instanceof FieldInsnNode) { + FieldInsnNode fieldInsnNode = (FieldInsnNode) instruction; + if ((fieldInsnNode.owner.contains(owner.getText()) || StringUtil.isBlank(owner.getText())) && + (fieldInsnNode.name.contains(name.getText()) || StringUtil.isBlank(name.getText())) && + (fieldInsnNode.desc.contains(description.getText()) || StringUtil.isBlank(description.getText())) + ) { + ((DefaultListModel) resultPanel.getList().getModel()).addElement(new ResultNode(classNode, fieldInsnNode.name + ":" + fieldInsnNode.desc)); } } - } - JavaOctetEditor.getInstance().bottomPanel.setProcess(0); + }); }); }); }}); diff --git a/src/main/java/cn/enaium/joe/dialog/search/SearchLdcDialog.java b/src/main/java/cn/enaium/joe/dialog/search/SearchLdcDialog.java index cb62961..8047538 100644 --- a/src/main/java/cn/enaium/joe/dialog/search/SearchLdcDialog.java +++ b/src/main/java/cn/enaium/joe/dialog/search/SearchLdcDialog.java @@ -42,30 +42,15 @@ public SearchLdcDialog() { add(new JButton("Search") {{ addActionListener(e -> { if (!text.getText().replace(" ", "").isEmpty()) { - Jar jar = JavaOctetEditor.getInstance().jar; ASyncUtil.execute(() -> { - float loaded = 0; - float total = 0; - for (Map.Entry stringClassNodeEntry : jar.classes.entrySet()) { - for (MethodNode method : stringClassNodeEntry.getValue().methods) { - total += method.instructions.size(); - } - } - - for (Map.Entry stringClassNodeEntry : jar.classes.entrySet()) { - for (MethodNode method : stringClassNodeEntry.getValue().methods) { - for (AbstractInsnNode instruction : method.instructions) { - if (instruction instanceof LdcInsnNode) { - String ldc = ((LdcInsnNode) instruction).cst.toString(); - if (ldc.contains(text.getText())) { - ((DefaultListModel) resultPanel.getList().getModel()).addElement(new ResultNode(stringClassNodeEntry.getValue(), ldc)); - } - } - JavaOctetEditor.getInstance().bottomPanel.setProcess((int) ((loaded++ / total) * 100f)); + searchInstruction((classNode, instruction) -> { + if (instruction instanceof LdcInsnNode) { + String ldc = ((LdcInsnNode) instruction).cst.toString(); + if (ldc.contains(text.getText())) { + ((DefaultListModel) resultPanel.getList().getModel()).addElement(new ResultNode(classNode, ldc)); } } - } - JavaOctetEditor.getInstance().bottomPanel.setProcess(0); + }); }); } }); diff --git a/src/main/java/cn/enaium/joe/dialog/search/SearchMethodDialog.java b/src/main/java/cn/enaium/joe/dialog/search/SearchMethodDialog.java index 481f15b..ea78d40 100644 --- a/src/main/java/cn/enaium/joe/dialog/search/SearchMethodDialog.java +++ b/src/main/java/cn/enaium/joe/dialog/search/SearchMethodDialog.java @@ -50,33 +50,18 @@ public SearchMethodDialog() { add(new JButton("Search") {{ addActionListener(e -> { ASyncUtil.execute(() -> { - float loaded = 0; - float total = 0; - Jar jar = JavaOctetEditor.getInstance().jar; - for (Map.Entry stringClassNodeEntry : jar.classes.entrySet()) { - for (MethodNode method : stringClassNodeEntry.getValue().methods) { - total += method.instructions.size(); - } - } - - for (Map.Entry stringClassNodeEntry : jar.classes.entrySet()) { - for (MethodNode method : stringClassNodeEntry.getValue().methods) { - for (AbstractInsnNode instruction : method.instructions) { - if (instruction instanceof MethodInsnNode) { - MethodInsnNode methodInsnNode = (MethodInsnNode) instruction; - if ((methodInsnNode.owner.contains(owner.getText()) || StringUtil.isBlank(owner.getText())) && - (methodInsnNode.name.contains(name.getText()) || StringUtil.isBlank(name.getText())) && - (methodInsnNode.desc.contains(description.getText()) || StringUtil.isBlank(description.getText())) && - (methodInsnNode.itf && anInterface.isSelected() || !anInterface.isSelected()) - ) { - ((DefaultListModel) resultPanel.getList().getModel()).addElement(new ResultNode(stringClassNodeEntry.getValue(), methodInsnNode.name + "#" + methodInsnNode.desc)); - } - } - JavaOctetEditor.getInstance().bottomPanel.setProcess((int) ((loaded++ / total) * 100f)); + searchInstruction((classNode, instruction) -> { + if (instruction instanceof MethodInsnNode) { + MethodInsnNode methodInsnNode = (MethodInsnNode) instruction; + if ((methodInsnNode.owner.contains(owner.getText()) || StringUtil.isBlank(owner.getText())) && + (methodInsnNode.name.contains(name.getText()) || StringUtil.isBlank(name.getText())) && + (methodInsnNode.desc.contains(description.getText()) || StringUtil.isBlank(description.getText())) && + (methodInsnNode.itf && anInterface.isSelected() || !anInterface.isSelected()) + ) { + ((DefaultListModel) resultPanel.getList().getModel()).addElement(new ResultNode(classNode, methodInsnNode.name + "#" + methodInsnNode.desc)); } } - } - JavaOctetEditor.getInstance().bottomPanel.setProcess(0); + }); }); }); }}); diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/ClassInfoTabPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/ClassInfoTabPanel.java new file mode 100644 index 0000000..50d5d46 --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/ClassInfoTabPanel.java @@ -0,0 +1,135 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.file.tabbed.tab; + + +import cn.enaium.joe.util.StringUtil; +import org.benf.cfr.reader.util.StringUtils; +import org.objectweb.asm.tree.ClassNode; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; + +/** + * @author Enaium + * @since 0.6.0 + */ +public class ClassInfoTabPanel extends ClassNodeTabPanel { + public ClassInfoTabPanel(ClassNode classNode) { + super(classNode); + setLayout(new BorderLayout()); + JPanel labels = new JPanel(new GridLayout(0, 1)); + JPanel rights = new JPanel(new GridLayout(0, 1)); + add(labels, BorderLayout.WEST); + add(rights, BorderLayout.CENTER); + labels.add(new JLabel("Name:")); + JTextField name = new JTextField(classNode.name); + rights.add(name); + labels.add(new JLabel("SourceFile:")); + JTextField sourceFile = new JTextField(classNode.sourceFile); + rights.add(sourceFile); + labels.add(new JLabel("DebugFile:")); + JTextField sourceDebug = new JTextField(classNode.sourceDebug); + rights.add(sourceDebug); + labels.add(new JLabel("Access:")); + JTextField access = new JTextField(String.valueOf(classNode.access)); + rights.add(access); + labels.add(new JLabel("Version:")); + JTextField version = new JTextField(String.valueOf(classNode.version)); + rights.add(version); + labels.add(new JLabel("Signature:")); + JTextField signature = new JTextField(classNode.signature); + rights.add(signature); + labels.add(new JLabel("Super Name:")); + JTextField superName = new JTextField(classNode.superName); + rights.add(superName); + labels.add(new JLabel("Interfaces:")); + JTextField interfaces = new JTextField(StringUtils.join(classNode.interfaces, ";")); + rights.add(interfaces); + labels.add(new JLabel("Outer Class:")); + JTextField outerClass = new JTextField(classNode.outerClass); + rights.add(outerClass); + labels.add(new JLabel("Outer Method:")); + JTextField outerMethod = new JTextField(classNode.outerMethod); + rights.add(outerMethod); + labels.add(new JLabel("Outer Method Description:")); + JTextField outerMethodDesc = new JTextField(classNode.outerMethodDesc); + rights.add(outerMethodDesc); + add(new JButton("Save") {{ + addActionListener(e -> { + + if (!StringUtil.isBlank(name.getText())) { + classNode.name = name.getText(); + } + + if (!StringUtil.isBlank(sourceFile.getText())) { + classNode.sourceFile = sourceFile.getText(); + } else { + classNode.sourceFile = null; + } + + if (!StringUtil.isBlank(sourceDebug.getText())) { + classNode.sourceDebug = sourceDebug.getText(); + } else { + classNode.sourceDebug = null; + } + + if (!StringUtil.isBlank(access.getText())) { + classNode.access = Integer.parseInt(access.getText()); + } + + if (!StringUtil.isBlank(version.getText())) { + classNode.version = Integer.parseInt(version.getText()); + } + + if (!StringUtil.isBlank(signature.getText())) { + classNode.signature = signature.getName(); + } else { + classNode.signature = null; + } + + if (!StringUtil.isBlank(interfaces.getText())) { + classNode.interfaces = Arrays.asList(superName.getText().split(";")); + } else { + classNode.interfaces = new ArrayList<>(); + } + + if (!StringUtil.isBlank(outerClass.getText())) { + classNode.outerClass = outerClass.getText(); + } else { + classNode.outerClass = null; + } + + if (!StringUtil.isBlank(outerMethod.getText())) { + classNode.outerMethod = outerMethod.getText(); + } else { + classNode.outerClass = null; + } + + if (!StringUtil.isBlank(outerMethodDesc.getText())) { + classNode.outerMethodDesc = outerMethodDesc.getText(); + } else { + classNode.outerClass = null; + } + + JOptionPane.showMessageDialog(ClassInfoTabPanel.this, "Save success"); + }); + }}, BorderLayout.SOUTH); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/FileTabPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/ClassTabPanel.java similarity index 77% rename from src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/FileTabPanel.java rename to src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/ClassTabPanel.java index 3cbeb22..b8a47a2 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/FileTabPanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/ClassTabPanel.java @@ -8,14 +8,15 @@ /** * @author Enaium */ -public class FileTabPanel extends JPanel { - public FileTabPanel(ClassNode classNode) { +public class ClassTabPanel extends JPanel { + public ClassTabPanel(ClassNode classNode) { super(new BorderLayout()); JTabbedPane jTabbedPane = new JTabbedPane(); jTabbedPane.setTabPlacement(JTabbedPane.BOTTOM); jTabbedPane.addTab("BytecodeView", new TraceBytecodeTabPanel(classNode)); jTabbedPane.addTab("DecompileView", new DecompileTabPanel(classNode)); jTabbedPane.addTab("VisitorEdit", new ASMifierTablePanel(classNode)); + jTabbedPane.addTab("InfoEdit", new ClassInfoTabPanel(classNode)); add(jTabbedPane); } } diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/FieldInfoPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/FieldInfoPanel.java new file mode 100644 index 0000000..01b369b --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/FieldInfoPanel.java @@ -0,0 +1,76 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.file.tabbed.tab; + +import cn.enaium.joe.util.StringUtil; +import org.objectweb.asm.tree.FieldNode; + +import javax.swing.*; +import java.awt.*; + +/** + * @author Enaium + * @since 0.6.0 + */ +public class FieldInfoPanel extends JPanel { + public FieldInfoPanel(FieldNode fieldNode) { + setLayout(new BorderLayout()); + JPanel labels = new JPanel(new GridLayout(0, 1)); + JPanel rights = new JPanel(new GridLayout(0, 1)); + add(labels, BorderLayout.WEST); + add(rights, BorderLayout.CENTER); + labels.add(new JLabel("Name:")); + JTextField name = new JTextField(fieldNode.name); + rights.add(name); + labels.add(new JLabel("Description:")); + JTextField description = new JTextField(fieldNode.desc); + rights.add(description); + labels.add(new JLabel("Access:")); + JTextField access = new JTextField(String.valueOf(fieldNode.access)); + rights.add(access); + labels.add(new JLabel("Signature:")); + JTextField signature = new JTextField(fieldNode.signature); + rights.add(signature); + add(new JButton("Save") {{ + addActionListener(e -> { + + if (!StringUtil.isBlank(name.getText())) { + fieldNode.name = name.getText(); + } + + + if (!StringUtil.isBlank(description.getText())) { + fieldNode.desc = description.getText(); + } else { + fieldNode.desc = null; + } + + if (!StringUtil.isBlank(access.getText())) { + fieldNode.access = Integer.parseInt(access.getText()); + } + + if (!StringUtil.isBlank(signature.getText())) { + fieldNode.signature = signature.getName(); + } else { + fieldNode.signature = null; + } + + JOptionPane.showMessageDialog(FieldInfoPanel.this, "Save success"); + }); + }}, BorderLayout.SOUTH); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/MethodInfoTabPanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/MethodInfoTabPanel.java new file mode 100644 index 0000000..6aadffc --- /dev/null +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tabbed/tab/MethodInfoTabPanel.java @@ -0,0 +1,88 @@ +/* + * Copyright 2022 Enaium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.enaium.joe.gui.panel.file.tabbed.tab; + +import cn.enaium.joe.util.StringUtil; +import org.benf.cfr.reader.util.StringUtils; +import org.objectweb.asm.tree.MethodNode; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; + +/** + * @author Enaium + * @since 0.6.0 + */ +public class MethodInfoTabPanel extends JPanel { + public MethodInfoTabPanel(MethodNode methodNode) { + setLayout(new BorderLayout()); + JPanel labels = new JPanel(new GridLayout(0, 1)); + JPanel rights = new JPanel(new GridLayout(0, 1)); + add(labels, BorderLayout.WEST); + add(rights, BorderLayout.CENTER); + labels.add(new JLabel("Name:")); + JTextField name = new JTextField(methodNode.name); + rights.add(name); + labels.add(new JLabel("Description:")); + JTextField description = new JTextField(methodNode.desc); + rights.add(description); + labels.add(new JLabel("Access:")); + JTextField access = new JTextField(String.valueOf(methodNode.access)); + rights.add(access); + labels.add(new JLabel("Signature:")); + JTextField signature = new JTextField(methodNode.signature); + rights.add(signature); + labels.add(new JLabel("Exceptions:")); + JTextField exceptions = new JTextField(StringUtils.join(methodNode.exceptions, ";")); + rights.add(exceptions); + add(new JButton("Save") {{ + addActionListener(e -> { + + if (!StringUtil.isBlank(name.getText())) { + methodNode.name = name.getText(); + } + + + if (!StringUtil.isBlank(description.getText())) { + methodNode.desc = description.getText(); + } else { + methodNode.desc = null; + } + + if (!StringUtil.isBlank(access.getText())) { + methodNode.access = Integer.parseInt(access.getText()); + } + + if (!StringUtil.isBlank(signature.getText())) { + methodNode.signature = signature.getName(); + } else { + methodNode.signature = null; + } + + if (!StringUtil.isBlank(signature.getText())) { + methodNode.exceptions = Arrays.asList(signature.getText().split(";")); + } else { + methodNode.exceptions = new ArrayList<>(); + } + + JOptionPane.showMessageDialog(MethodInfoTabPanel.this, "Save success"); + }); + }}, BorderLayout.SOUTH); + } +} diff --git a/src/main/java/cn/enaium/joe/gui/panel/file/tree/FileTreePanel.java b/src/main/java/cn/enaium/joe/gui/panel/file/tree/FileTreePanel.java index cdcdeb7..af810cc 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/file/tree/FileTreePanel.java +++ b/src/main/java/cn/enaium/joe/gui/panel/file/tree/FileTreePanel.java @@ -18,20 +18,24 @@ import cn.enaium.joe.JavaOctetEditor; import cn.enaium.joe.gui.panel.file.FileDropTarget; -import cn.enaium.joe.gui.panel.file.tabbed.tab.FileTabPanel; +import cn.enaium.joe.gui.panel.file.tabbed.tab.ClassTabPanel; +import cn.enaium.joe.gui.panel.file.tabbed.tab.FieldInfoPanel; +import cn.enaium.joe.gui.panel.file.tabbed.tab.MethodInfoTabPanel; import cn.enaium.joe.gui.panel.file.tree.node.*; import cn.enaium.joe.jar.Jar; import cn.enaium.joe.util.ASyncUtil; +import cn.enaium.joe.util.JTreeUtil; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.MethodNode; import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreeNode; -import javax.swing.tree.TreePath; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.io.File; import java.util.*; @@ -55,10 +59,21 @@ public FileTreePanel() { addTreeSelectionListener(e -> { DefaultTreeNode lastPathComponent = (DefaultTreeNode) e.getPath().getLastPathComponent(); - if (lastPathComponent instanceof ClassTreeNode) { - JavaOctetEditor.getInstance().fileTabbedPanel.addTab(lastPathComponent.toString(), new FileTabPanel(((ClassTreeNode) lastPathComponent).classNode)); + SwingUtilities.invokeLater(() -> { + if (lastPathComponent instanceof ClassTreeNode) { + ClassNode classNode = ((ClassTreeNode) lastPathComponent).classNode; + JavaOctetEditor.getInstance().fileTabbedPanel.addTab(classNode.name.substring(classNode.name.lastIndexOf("/") + 1), new ClassTabPanel(classNode)); + } else if (lastPathComponent instanceof MethodTreeNode) { + MethodTreeNode methodTreeNode = (MethodTreeNode) lastPathComponent; + MethodNode methodNode = methodTreeNode.methodNode; + JavaOctetEditor.getInstance().fileTabbedPanel.addTab(methodTreeNode.classNode.name.substring(methodTreeNode.classNode.name.lastIndexOf("/") + 1) + "#" + methodNode.name, new MethodInfoTabPanel(methodNode)); + } else if (lastPathComponent instanceof FieldTreeNode) { + FieldTreeNode fieldTreeNode = (FieldTreeNode) lastPathComponent; + FieldNode fieldNode = fieldTreeNode.fieldNode; + JavaOctetEditor.getInstance().fileTabbedPanel.addTab(fieldTreeNode.classNode.name.substring(fieldTreeNode.classNode.name.lastIndexOf("/") + 1) + "#" + fieldNode.name, new FieldInfoPanel(fieldNode)); + } JavaOctetEditor.getInstance().fileTabbedPanel.setSelectedIndex(JavaOctetEditor.getInstance().fileTabbedPanel.getTabCount() - 1); - } + }); }); new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, new FileDropTarget(".jar", files -> { @@ -71,6 +86,25 @@ public FileTreePanel() { }); } }), true); + + JPopupMenu jPopupMenu = new JPopupMenu(); + + + jPopupMenu.add(new JMenuItem("Expand all") {{ + addActionListener(e -> { + JTreeUtil.setNodeExpandedState(FileTreePanel.this, ((DefaultMutableTreeNode) Objects.requireNonNull(getSelectionPath()).getLastPathComponent()), true); + }); + }}); + + addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + if (SwingUtilities.isRightMouseButton(e) && getSelectionPath() != null) { + jPopupMenu.show(FileTreePanel.this, e.getX(), e.getY()); + } + } + }); + } public void refresh(Jar jar) { @@ -79,6 +113,8 @@ public void refresh(Jar jar) { classesRoot.removeAllChildren(); resourceRoot.removeAllChildren(); + JavaOctetEditor.getInstance().fileTabbedPanel.removeAll(); + Map hasMap = new HashMap<>(); diff --git a/src/main/java/cn/enaium/joe/gui/panel/menu/file/SaveMenuItem.java b/src/main/java/cn/enaium/joe/gui/panel/menu/file/SaveMenuItem.java index 6f0232a..0886ff3 100644 --- a/src/main/java/cn/enaium/joe/gui/panel/menu/file/SaveMenuItem.java +++ b/src/main/java/cn/enaium/joe/gui/panel/menu/file/SaveMenuItem.java @@ -51,7 +51,7 @@ public SaveMenuItem() { try { ZipOutputStream zipOutputStream = new ZipOutputStream(Files.newOutputStream(show.toPath())); for (Map.Entry stringClassNodeEntry : jar.classes.entrySet()) { - zipOutputStream.putNextEntry(new JarEntry(stringClassNodeEntry.getKey())); + zipOutputStream.putNextEntry(new JarEntry(stringClassNodeEntry.getValue().name + ".class")); ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); stringClassNodeEntry.getValue().accept(classWriter); zipOutputStream.write(classWriter.toByteArray()); diff --git a/src/main/java/cn/enaium/joe/util/JTreeUtil.java b/src/main/java/cn/enaium/joe/util/JTreeUtil.java index 740e47a..c8b52ed 100644 --- a/src/main/java/cn/enaium/joe/util/JTreeUtil.java +++ b/src/main/java/cn/enaium/joe/util/JTreeUtil.java @@ -34,7 +34,7 @@ public static void setTreeExpandedState(JTree tree, boolean expanded) { setNodeExpandedState(tree, node, expanded); } - private static void setNodeExpandedState(JTree tree, DefaultMutableTreeNode node, boolean expanded) { + public static void setNodeExpandedState(JTree tree, DefaultMutableTreeNode node, boolean expanded) { Enumeration children = node.children(); while (children.hasMoreElements()) { setNodeExpandedState(tree, (DefaultMutableTreeNode) children.nextElement(), expanded); diff --git a/src/main/java/cn/enaium/joe/util/StringUtil.java b/src/main/java/cn/enaium/joe/util/StringUtil.java index 88db8fc..0fdedd9 100644 --- a/src/main/java/cn/enaium/joe/util/StringUtil.java +++ b/src/main/java/cn/enaium/joe/util/StringUtil.java @@ -22,6 +22,9 @@ */ public class StringUtil { public static boolean isBlank(String string) { + if (string == null) { + return true; + } return string.replace(" ", "").isEmpty(); } }