* include & exclude multiple packages at the same time * use to tree instead of list to display packages. Co-authored-by: tobias <tobias.hotmail.com>
This commit is contained in:
@@ -112,6 +112,11 @@ public class JadxWrapper {
|
||||
return Arrays.asList(excludedPackages.split("[ ]+"));
|
||||
}
|
||||
|
||||
public void setExcludedPackages(List<String> packagesToExclude) {
|
||||
settings.setExcludedPackages(String.join(" ", packagesToExclude).trim());
|
||||
settings.sync();
|
||||
}
|
||||
|
||||
public void addExcludedPackage(String packageToExclude) {
|
||||
String newExclusion = settings.getExcludedPackages() + ' ' + packageToExclude;
|
||||
settings.setExcludedPackages(newExclusion.trim());
|
||||
|
||||
@@ -0,0 +1,298 @@
|
||||
package jadx.gui.ui;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.*;
|
||||
|
||||
import jadx.api.JavaPackage;
|
||||
import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.UiUtils;
|
||||
|
||||
public class ExcludePkgDialog extends JDialog {
|
||||
private static final long serialVersionUID = -1111111202104151030L;
|
||||
private static final ImageIcon PACKAGE_ICON = UiUtils.openIcon("package_obj");
|
||||
|
||||
private final transient MainWindow mainWindow;
|
||||
private transient JTree tree;
|
||||
private transient DefaultMutableTreeNode treeRoot;
|
||||
private final transient List<PkgNode> roots = new ArrayList<>();
|
||||
|
||||
public ExcludePkgDialog(MainWindow mainWindow) {
|
||||
super(mainWindow);
|
||||
this.mainWindow = mainWindow;
|
||||
initUI();
|
||||
UiUtils.addEscapeShortCutToDispose(this);
|
||||
initPackageList();
|
||||
}
|
||||
|
||||
private void initUI() {
|
||||
setTitle(NLS.str("exclude_dialog.title"));
|
||||
tree = new JTree();
|
||||
tree.setRowHeight(-1);
|
||||
treeRoot = new DefaultMutableTreeNode("Packages");
|
||||
DefaultTreeModel treeModel = new DefaultTreeModel(treeRoot);
|
||||
tree.setModel(treeModel);
|
||||
tree.setCellRenderer(new PkgListCellRenderer());
|
||||
JScrollPane listPanel = new JScrollPane(tree);
|
||||
listPanel.setBorder(BorderFactory.createLineBorder(Color.black));
|
||||
tree.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
TreePath path = tree.getPathForLocation(e.getX(), e.getY());
|
||||
if (path != null) {
|
||||
PkgNode node = (PkgNode) path.getLastPathComponent();
|
||||
node.toggle();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
JPanel actionPanel = new JPanel();
|
||||
BoxLayout boxLayout = new BoxLayout(actionPanel, BoxLayout.LINE_AXIS);
|
||||
actionPanel.setLayout(boxLayout);
|
||||
actionPanel.add(new Label(" "));
|
||||
JButton btnOk = new JButton(NLS.str("exclude_dialog.ok"));
|
||||
JButton btnAll = new JButton(NLS.str("exclude_dialog.select_all"));
|
||||
JButton btnInvert = new JButton(NLS.str("exclude_dialog.invert"));
|
||||
JButton btnDeselect = new JButton(NLS.str("exclude_dialog.deselect"));
|
||||
actionPanel.add(btnDeselect);
|
||||
actionPanel.add(btnInvert);
|
||||
actionPanel.add(btnAll);
|
||||
actionPanel.add(new Label(" "));
|
||||
actionPanel.add(btnOk);
|
||||
|
||||
JPanel mainPane = new JPanel(new BorderLayout(5, 5));
|
||||
mainPane.add(listPanel, BorderLayout.CENTER);
|
||||
mainPane.add(actionPanel, BorderLayout.SOUTH);
|
||||
mainPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
|
||||
getContentPane().add(mainPane);
|
||||
pack();
|
||||
setSize(600, 700);
|
||||
setLocationRelativeTo(null);
|
||||
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
setModalityType(ModalityType.MODELESS);
|
||||
|
||||
btnOk.addActionListener(e -> {
|
||||
mainWindow.getWrapper().setExcludedPackages(getExcludes());
|
||||
mainWindow.reOpenFile();
|
||||
dispose();
|
||||
});
|
||||
btnAll.addActionListener(e -> {
|
||||
roots.forEach(p -> p.setSelected(true));
|
||||
tree.updateUI();
|
||||
});
|
||||
btnDeselect.addActionListener(e -> {
|
||||
roots.forEach(p -> p.setSelected(false));
|
||||
tree.updateUI();
|
||||
});
|
||||
btnInvert.addActionListener(e -> {
|
||||
roots.forEach(PkgNode::toggle);
|
||||
tree.updateUI();
|
||||
});
|
||||
}
|
||||
|
||||
private void initPackageList() {
|
||||
List<String> pkgs = mainWindow.getWrapper().getDecompiler().getPackages()
|
||||
.stream()
|
||||
.map(JavaPackage::getFullName)
|
||||
.collect(Collectors.toList());
|
||||
getPackageTree(pkgs).forEach(treeRoot::add);
|
||||
initCheckbox();
|
||||
tree.expandPath(new TreePath(treeRoot.getPath()));
|
||||
}
|
||||
|
||||
private List<PkgNode> getPackageTree(List<String> names) {
|
||||
List<PkgNode> roots = new ArrayList<>();
|
||||
Set<String> nameSet = new HashSet<>();
|
||||
Map<String, List<PkgNode>> childMap = new HashMap<>();
|
||||
for (String name : names) {
|
||||
String parent = "";
|
||||
int last = 0;
|
||||
do {
|
||||
int pos = name.indexOf(".", last);
|
||||
if (pos == -1) {
|
||||
pos = name.length();
|
||||
}
|
||||
String fullName = name.substring(0, pos);
|
||||
if (!nameSet.contains(fullName)) {
|
||||
nameSet.add(fullName);
|
||||
PkgNode node = new PkgNode(fullName, name.substring(last, pos));
|
||||
if (!parent.isEmpty()) {
|
||||
childMap.computeIfAbsent(parent, k -> new ArrayList<>())
|
||||
.add(node);
|
||||
} else {
|
||||
roots.add(node);
|
||||
}
|
||||
}
|
||||
parent = fullName;
|
||||
last = pos + 1;
|
||||
} while (last < name.length());
|
||||
}
|
||||
addToParent(null, roots, childMap);
|
||||
return this.roots;
|
||||
}
|
||||
|
||||
private PkgNode addToParent(PkgNode parent, List<PkgNode> roots, Map<String, List<PkgNode>> childMap) {
|
||||
for (PkgNode root : roots) {
|
||||
String tempFullName = root.getFullName();
|
||||
do {
|
||||
List<PkgNode> children = childMap.get(tempFullName);
|
||||
if (children != null) {
|
||||
if (children.size() == 1) {
|
||||
PkgNode next = children.get(0);
|
||||
next.name = root.name + "." + next.name;
|
||||
tempFullName = next.fullName;
|
||||
next.fullName = root.fullName;
|
||||
root = next;
|
||||
continue;
|
||||
} else {
|
||||
addToParent(root, children, childMap);
|
||||
}
|
||||
}
|
||||
if (parent == null) {
|
||||
this.roots.add(root);
|
||||
} else {
|
||||
parent.add(root);
|
||||
}
|
||||
break;
|
||||
} while (true);
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
private List<String> getExcludes() {
|
||||
List<String> excludes = new ArrayList<>();
|
||||
walkTree(true, p -> excludes.add(p.getFullName()));
|
||||
return excludes;
|
||||
}
|
||||
|
||||
private void initCheckbox() {
|
||||
Font tmp = mainWindow.getSettings().getFont();
|
||||
Font font = tmp.deriveFont(tmp.getSize() + 1.f);
|
||||
Set<String> excluded = new HashSet<>(mainWindow.getWrapper().getExcludedPackages());
|
||||
walkTree(false, p -> p.initCheckbox(excluded.contains(p.getFullName()), font));
|
||||
}
|
||||
|
||||
private void walkTree(boolean findSelected, Consumer<PkgNode> consumer) {
|
||||
List<PkgNode> queue = new ArrayList<>(roots);
|
||||
for (int i = 0; i < queue.size(); i++) {
|
||||
PkgNode node = queue.get(i);
|
||||
if (findSelected && node.isSelected()) {
|
||||
consumer.accept(node);
|
||||
} else {
|
||||
if (!findSelected) {
|
||||
consumer.accept(node);
|
||||
}
|
||||
for (int j = 0; j < node.getChildCount(); j++) {
|
||||
queue.add((PkgNode) node.getChildAt(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class PkgNode extends DefaultMutableTreeNode {
|
||||
private static final long serialVersionUID = -1111111202104151430L;
|
||||
|
||||
String name;
|
||||
String fullName;
|
||||
JCheckBox checkbox;
|
||||
|
||||
PkgNode(String fullName, String name) {
|
||||
this.name = name;
|
||||
this.fullName = fullName;
|
||||
}
|
||||
|
||||
void initCheckbox(boolean select, Font font) {
|
||||
if (!select) {
|
||||
if (getParent() instanceof PkgNode) {
|
||||
select = ((PkgNode) getParent()).isSelected();
|
||||
}
|
||||
}
|
||||
checkbox = new JCheckBox(name, select);
|
||||
checkbox.setFont(font);
|
||||
}
|
||||
|
||||
boolean toggle() {
|
||||
boolean selected = !checkbox.isSelected();
|
||||
setSelected(selected);
|
||||
toggleParents(selected);
|
||||
return selected;
|
||||
}
|
||||
|
||||
void toggleParents(boolean select) {
|
||||
if (getParent() instanceof PkgNode) {
|
||||
PkgNode p = ((PkgNode) getParent());
|
||||
if (select) {
|
||||
select = p.isChildrenAllSelected();
|
||||
if (select) {
|
||||
p.checkbox.setSelected(true);
|
||||
p.toggleParents(true);
|
||||
}
|
||||
} else {
|
||||
p.checkbox.setSelected(false);
|
||||
p.toggleParents(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setSelected(boolean select) {
|
||||
checkbox.setSelected(select);
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
((PkgNode) getChildAt(i)).setSelected(select);
|
||||
}
|
||||
}
|
||||
|
||||
boolean isSelected() {
|
||||
return checkbox.isSelected();
|
||||
}
|
||||
|
||||
String getFullName() {
|
||||
return fullName;
|
||||
}
|
||||
|
||||
String getDisplayName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
boolean isChildrenAllSelected() {
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
if (!((PkgNode) getChildAt(i)).isSelected()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PkgListCellRenderer extends DefaultTreeCellRenderer {
|
||||
private static final long serialVersionUID = -1111111202104151235L;
|
||||
|
||||
@Override
|
||||
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row,
|
||||
boolean hasFocus) {
|
||||
if (value instanceof PkgNode) {
|
||||
PkgNode node = (PkgNode) value;
|
||||
node.checkbox.setBackground(Color.white);
|
||||
node.checkbox.setForeground(Color.black);
|
||||
return node.checkbox;
|
||||
}
|
||||
Component c = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
|
||||
setIcon(PACKAGE_ICON);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package jadx.gui.ui;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -25,6 +26,7 @@ class JPackagePopupMenu extends JPopupMenu {
|
||||
this.mainWindow = mainWindow;
|
||||
|
||||
add(makeExcludeItem(pkg));
|
||||
add(makeExcludeItem());
|
||||
JMenuItem menuItem = makeRenameMenuItem(pkg);
|
||||
if (menuItem != null) {
|
||||
add(menuItem);
|
||||
@@ -115,4 +117,15 @@ class JPackagePopupMenu extends JPopupMenu {
|
||||
});
|
||||
return excludeItem;
|
||||
}
|
||||
|
||||
private JMenuItem makeExcludeItem() {
|
||||
return new JMenuItem(new AbstractAction(NLS.str("popup.exclude_packages")) {
|
||||
private static final long serialVersionUID = -1111111202104151028L;
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
new ExcludePkgDialog(mainWindow).setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,12 +183,19 @@ popup.select_all=Alle auswählen
|
||||
popup.find_usage=Verwendung suchen
|
||||
popup.go_to_declaration=Zur Erklärung gehen
|
||||
popup.exclude=Ausschließen
|
||||
#popup.exclude_packages=Exclude packages
|
||||
#popup.add_comment=Comment
|
||||
#popup.search_comment=Search comments
|
||||
popup.rename=Umbennen
|
||||
#popup.search=
|
||||
#popup.search_global=
|
||||
|
||||
#exclude_dialog.title=Package Selector
|
||||
#exclude_dialog.ok=OK
|
||||
#exclude_dialog.select_all=Select all
|
||||
#exclude_dialog.deselect=Deselect
|
||||
#exclude_dialog.invert=Invert
|
||||
|
||||
confirm.save_as_title=Speichern unter bestätigen
|
||||
confirm.save_as_message=%s existiert bereits.\nErsetzen?
|
||||
confirm.not_saved_title=Projekt speichern
|
||||
|
||||
@@ -183,12 +183,19 @@ popup.select_all=Select All
|
||||
popup.find_usage=Find Usage
|
||||
popup.go_to_declaration=Go to declaration
|
||||
popup.exclude=Exclude
|
||||
popup.exclude_packages=Exclude packages
|
||||
popup.add_comment=Comment
|
||||
popup.search_comment=Search comments
|
||||
popup.rename=Rename
|
||||
popup.search=Search "%s"
|
||||
popup.search_global=Global Search "%s"
|
||||
|
||||
exclude_dialog.title=Package Selector
|
||||
exclude_dialog.ok=OK
|
||||
exclude_dialog.select_all=Select all
|
||||
exclude_dialog.deselect=Deselect
|
||||
exclude_dialog.invert=Invert
|
||||
|
||||
confirm.save_as_title=Confirm Save as
|
||||
confirm.save_as_message=%s already exists.\nDo you want to replace it?
|
||||
confirm.not_saved_title=Save project
|
||||
|
||||
@@ -183,12 +183,19 @@ popup.select_all=Seleccionar todo
|
||||
#popup.find_usage=
|
||||
#popup.go_to_declaration=
|
||||
#popup.exclude=
|
||||
#popup.exclude_packages=Exclude packages
|
||||
#popup.add_comment=Comment
|
||||
#popup.search_comment=Search comments
|
||||
popup.rename=Nimeta ümber
|
||||
#popup.search=
|
||||
#popup.search_global=
|
||||
|
||||
#exclude_dialog.title=Package Selector
|
||||
#exclude_dialog.ok=OK
|
||||
#exclude_dialog.select_all=Select all
|
||||
#exclude_dialog.deselect=Deselect
|
||||
#exclude_dialog.invert=Invert
|
||||
|
||||
#confirm.save_as_title=
|
||||
#confirm.save_as_message=
|
||||
#confirm.not_saved_title=
|
||||
|
||||
@@ -183,12 +183,19 @@ popup.select_all=모두 선택
|
||||
popup.find_usage=사용 찾기
|
||||
popup.go_to_declaration=선언문으로 이동
|
||||
popup.exclude=제외
|
||||
#popup.exclude_packages=Exclude packages
|
||||
popup.add_comment=주석
|
||||
popup.search_comment=주석 검색
|
||||
popup.rename=이름 바꾸기
|
||||
popup.search="%s" 검색
|
||||
popup.search_global="%s" 전역 검색
|
||||
|
||||
#exclude_dialog.title=Package Selector
|
||||
#exclude_dialog.ok=OK
|
||||
#exclude_dialog.select_all=Select all
|
||||
#exclude_dialog.deselect=Deselect
|
||||
#exclude_dialog.invert=Invert
|
||||
|
||||
confirm.save_as_title=다른 이름으로 저장 확인
|
||||
confirm.save_as_message=%s이(가) 이미 있습니다.\n바꾸시겠습니까?
|
||||
confirm.not_saved_title=프로젝트 저장
|
||||
|
||||
@@ -183,12 +183,19 @@ popup.select_all=全选
|
||||
popup.find_usage=查找用例
|
||||
popup.go_to_declaration=跳到声明
|
||||
popup.exclude=排除
|
||||
#popup.exclude_packages=Exclude packages
|
||||
#popup.add_comment=Comment
|
||||
#popup.search_comment=Search comments
|
||||
popup.rename=改名
|
||||
#popup.search=
|
||||
#popup.search_global=
|
||||
|
||||
#exclude_dialog.title=Package Selector
|
||||
#exclude_dialog.ok=OK
|
||||
#exclude_dialog.select_all=Select all
|
||||
#exclude_dialog.deselect=Deselect
|
||||
#exclude_dialog.invert=Invert
|
||||
|
||||
confirm.save_as_title=确认另存为
|
||||
confirm.save_as_message=%s 已存在。\n你想替换它吗?
|
||||
confirm.not_saved_title=保存项目
|
||||
|
||||
Reference in New Issue
Block a user