add feature: context menu (remove|expand|collapse) support
fixbug:files are hidden when select and click "-" button
This commit is contained in:
parent
9f3302f7a9
commit
43e775653f
3 changed files with 183 additions and 57 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -6,3 +6,4 @@
|
||||||
.project
|
.project
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.iml
|
*.iml
|
||||||
|
/out/
|
||||||
|
|
|
@ -1,50 +1,25 @@
|
||||||
package the.bytecode.club.bytecodeviewer.gui;
|
package the.bytecode.club.bytecodeviewer.gui;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import com.sun.java.swing.plaf.windows.WindowsTreeUI;
|
||||||
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 org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
import the.bytecode.club.bytecodeviewer.*;
|
import the.bytecode.club.bytecodeviewer.Resources;
|
||||||
import the.bytecode.club.bytecodeviewer.util.FileChangeNotifier;
|
import the.bytecode.club.bytecodeviewer.util.FileChangeNotifier;
|
||||||
import the.bytecode.club.bytecodeviewer.util.FileContainer;
|
import the.bytecode.club.bytecodeviewer.util.FileContainer;
|
||||||
import the.bytecode.club.bytecodeviewer.util.FileDrop;
|
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 *
|
* 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) {
|
public FileNavigationPane(final FileChangeNotifier fcn) {
|
||||||
super("ClassNavigation");
|
super("ClassNavigation");
|
||||||
this.fcn = fcn;
|
this.fcn = fcn;
|
||||||
|
@ -203,6 +232,30 @@ public class FileNavigationPane extends VisibleComponent implements
|
||||||
quickSearch.setForeground(Color.gray);
|
quickSearch.setForeground(Color.gray);
|
||||||
setTitle("Files");
|
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() {
|
this.open.addActionListener(new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
@ -513,6 +566,7 @@ public class FileNavigationPane extends VisibleComponent implements
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -556,8 +610,9 @@ public class FileNavigationPane extends VisibleComponent implements
|
||||||
|
|
||||||
public void openPath(TreePath path)
|
public void openPath(TreePath path)
|
||||||
{
|
{
|
||||||
if (path == null)
|
if (path == null || path.getPathCount() == 1) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final StringBuilder nameBuffer = new StringBuilder();
|
final StringBuilder nameBuffer = new StringBuilder();
|
||||||
for (int i = 2; i < path.getPathCount(); i++) {
|
for (int i = 2; i < path.getPathCount(); i++) {
|
||||||
|
|
|
@ -19,6 +19,7 @@ package the.bytecode.club.bytecodeviewer.util;
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
@ -29,31 +30,100 @@ public class LazyNameUtil
|
||||||
{
|
{
|
||||||
public static boolean SAME_NAME_JAR_WORKSPACE = false;
|
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()
|
public static void reset()
|
||||||
{
|
{
|
||||||
nameMap.clear();
|
nameMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String applyNameChanges(String name)
|
public static String applyNameChanges(String name) {
|
||||||
{
|
if (nameMap.containsKey(name)) {
|
||||||
if(nameMap.containsKey(name))
|
if (!SAME_NAME_JAR_WORKSPACE) {
|
||||||
{
|
|
||||||
if(!SAME_NAME_JAR_WORKSPACE)
|
|
||||||
SAME_NAME_JAR_WORKSPACE = true;
|
SAME_NAME_JAR_WORKSPACE = true;
|
||||||
|
|
||||||
int counter = nameMap.get(name)+1;
|
|
||||||
nameMap.put(name, counter);
|
|
||||||
|
|
||||||
return FilenameUtils.removeExtension(name)+"#"+counter+"."+FilenameUtils.getExtension(name);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
SeqAndCount seqAndCount = nameMap.get(name);
|
||||||
nameMap.put(name, 1);
|
nameMap.put(name, seqAndCount.incrSeqAndCount());
|
||||||
|
return FilenameUtils.removeExtension(name) + "#" + seqAndCount.getSeq() + "." + FilenameUtils.getExtension(name);
|
||||||
|
} else {
|
||||||
|
nameMap.put(name, SeqAndCount.init());
|
||||||
}
|
}
|
||||||
|
|
||||||
return name;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue