add feature: context menu (remove|expand|collapse) support

fixbug:files are hidden when select and click "-" button
This commit is contained in:
hupan 2019-11-20 21:17:36 +08:00
parent 9f3302f7a9
commit 43e775653f
3 changed files with 183 additions and 57 deletions

1
.gitignore vendored
View file

@ -6,3 +6,4 @@
.project
.DS_Store
*.iml
/out/

View file

@ -1,50 +1,25 @@
package the.bytecode.club.bytecodeviewer.gui;
import java.awt.BorderLayout;
import java.awt.font.FontRenderContext;
import java.awt.geom.*;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map.Entry;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import com.sun.java.swing.plaf.windows.WindowsTreeUI;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.*;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.Resources;
import the.bytecode.club.bytecodeviewer.util.FileChangeNotifier;
import the.bytecode.club.bytecodeviewer.util.FileContainer;
import the.bytecode.club.bytecodeviewer.util.FileDrop;
import the.bytecode.club.bytecodeviewer.util.LazyNameUtil;
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.util.*;
import java.util.Map.Entry;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@ -195,6 +170,60 @@ public class FileNavigationPane extends VisibleComponent implements
}
};
private void showPopMenu(MyTree tree, TreePath selPath, int x, int y) {
if (selPath == null) {
return;
}
final JPopupMenu pop = new JPopupMenu();
pop.add(new AbstractAction("Remove") {
@Override
public void actionPerformed(ActionEvent e) {
TreePath selPath = FileNavigationPane.this.tree.getPathForLocation(x, y);
DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) selPath.getLastPathComponent();
Enumeration enumeration = treeRoot.children();
while (enumeration.hasMoreElements()) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) enumeration.nextElement();
if (node.isNodeAncestor(selectNode)) {
DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
root.remove(node);
for (FileContainer fileContainer : BytecodeViewer.files) {
if (fileContainer.name.equals(selectNode.toString())) {
removeFile(fileContainer);
break;
}
}
updateTree();
return;
}
}
}
});
pop.add(new AbstractAction("Expand", WindowsTreeUI.ExpandedIcon.createExpandedIcon()) {
@Override
public void actionPerformed(ActionEvent e) {
TreePath selPath = FileNavigationPane.this.tree.getPathForLocation(x, y);
expandAll(tree, selPath, true);
}
});
pop.add(new AbstractAction("Collapse", WindowsTreeUI.CollapsedIcon.createCollapsedIcon()) {
@Override
public void actionPerformed(ActionEvent e) {
TreePath selPath = FileNavigationPane.this.tree.getPathForLocation(x, y);
expandAll(tree, selPath, false);
}
});
pop.show(this.tree, x, y);
}
private void removeFile(FileContainer fileContainer) {
BytecodeViewer.files.remove(fileContainer);
LazyNameUtil.removeName(fileContainer.name);
}
public FileNavigationPane(final FileChangeNotifier fcn) {
super("ClassNavigation");
this.fcn = fcn;
@ -203,6 +232,30 @@ public class FileNavigationPane extends VisibleComponent implements
quickSearch.setForeground(Color.gray);
setTitle("Files");
tree.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if (e.isMetaDown()) {
MyTree tree = (MyTree) e.getSource();
TreePath selPath = FileNavigationPane.this.tree.getPathForLocation(e.getX(), e.getY());
if (selPath == null) {
return;
}
DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) selPath.getLastPathComponent();
Enumeration enumeration = treeRoot.children();
while (enumeration.hasMoreElements()) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) enumeration.nextElement();
if (node.isNodeAncestor(selectNode)) {
// pop.show(tree, e.getX(), e.getY());
showPopMenu(tree, selPath, e.getX(), e.getY());
break;
}
}
}
}
});
this.open.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@ -513,6 +566,7 @@ public class FileNavigationPane extends VisibleComponent implements
return hash;
}
};
}
/**
@ -556,8 +610,9 @@ public class FileNavigationPane extends VisibleComponent implements
public void openPath(TreePath path)
{
if (path == null)
if (path == null || path.getPathCount() == 1) {
return;
}
final StringBuilder nameBuffer = new StringBuilder();
for (int i = 2; i < path.getPathCount(); i++) {

View file

@ -19,6 +19,7 @@ package the.bytecode.club.bytecodeviewer.util;
***************************************************************************/
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
@ -29,31 +30,100 @@ public class LazyNameUtil
{
public static boolean SAME_NAME_JAR_WORKSPACE = false;
private static final HashMap<String, Integer> nameMap = new HashMap<>();
private static final HashMap<String, SeqAndCount> nameMap = new HashMap<>();
public static void reset()
{
nameMap.clear();
}
public static String applyNameChanges(String name)
{
if(nameMap.containsKey(name))
{
if(!SAME_NAME_JAR_WORKSPACE)
public static String applyNameChanges(String name) {
if (nameMap.containsKey(name)) {
if (!SAME_NAME_JAR_WORKSPACE) {
SAME_NAME_JAR_WORKSPACE = true;
}
int counter = nameMap.get(name)+1;
nameMap.put(name, counter);
return FilenameUtils.removeExtension(name)+"#"+counter+"."+FilenameUtils.getExtension(name);
}
else
{
nameMap.put(name, 1);
SeqAndCount seqAndCount = nameMap.get(name);
nameMap.put(name, seqAndCount.incrSeqAndCount());
return FilenameUtils.removeExtension(name) + "#" + seqAndCount.getSeq() + "." + FilenameUtils.getExtension(name);
} else {
nameMap.put(name, SeqAndCount.init());
}
return name;
}
public static void removeName(String name) {
if (StringUtils.isBlank(name)) {
return;
}
if (name.contains("#")) {
name = name.substring(0, name.indexOf("#")) + name.substring(name.indexOf("."));
}
SeqAndCount seqAndCount = nameMap.get(name);
if (seqAndCount == null) {
return;
}
// sequence remain the same and decrease the count
// still the count become 1
if (seqAndCount.getCount() == 1) {
nameMap.remove(name);
} else {
nameMap.put(name, seqAndCount.decrCount());
}
}
}
class SeqAndCount {
Integer seq;
Integer count;
public static SeqAndCount init() {
SeqAndCount seqAndCount = new SeqAndCount();
seqAndCount.setSeq(1);
seqAndCount.setCount(1);
return seqAndCount;
}
public SeqAndCount incrSeq() {
seq = seq + 1;
return this;
}
public SeqAndCount incrCount() {
count = count + 1;
return this;
}
public SeqAndCount decrCount() {
count = count - 1;
return this;
}
public SeqAndCount incrSeqAndCount() {
seq = seq + 1;
count = count + 1;
return this;
}
public Integer getSeq() {
return seq;
}
public void setSeq(Integer seq) {
this.seq = seq;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}