feat(plugins): new API method to add popup menu entry for tree nodes (#2412)
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
package jadx.api.gui.tree;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.tree.TreeNode;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.metadata.ICodeNodeRef;
|
||||
|
||||
public interface ITreeNode extends TreeNode {
|
||||
|
||||
/**
|
||||
* Locale independent node identifier
|
||||
*/
|
||||
String getID();
|
||||
|
||||
/**
|
||||
* Node title
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Node icon
|
||||
*/
|
||||
Icon getIcon();
|
||||
|
||||
/**
|
||||
* Related code node reference.
|
||||
*/
|
||||
@Nullable
|
||||
ICodeNodeRef getCodeNodeRef();
|
||||
}
|
||||
@@ -2,13 +2,16 @@ package jadx.api.plugins.gui;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.gui.tree.ITreeNode;
|
||||
import jadx.api.metadata.ICodeNodeRef;
|
||||
|
||||
public interface JadxGuiContext {
|
||||
@@ -35,6 +38,15 @@ public interface JadxGuiContext {
|
||||
@Nullable String keyBinding,
|
||||
Consumer<ICodeNodeRef> action);
|
||||
|
||||
/**
|
||||
* Add popup menu entry for tree node
|
||||
*
|
||||
* @param name entry title
|
||||
* @param addPredicate check if entry should be added for provided node, called on popup creation
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
void addTreePopupMenuEntry(String name, Predicate<ITreeNode> addPredicate, Consumer<ITreeNode> action);
|
||||
|
||||
/**
|
||||
* Attach new key binding to main window
|
||||
*
|
||||
|
||||
@@ -22,6 +22,7 @@ public class CommonGuiPluginsContext {
|
||||
private final Map<PluginContext, GuiPluginContext> pluginsMap = new HashMap<>();
|
||||
|
||||
private final List<CodePopupAction> codePopupActionList = new ArrayList<>();
|
||||
private final List<TreePopupMenuEntry> treePopupMenuEntries = new ArrayList<>();
|
||||
|
||||
public CommonGuiPluginsContext(MainWindow mainWindow) {
|
||||
this.mainWindow = mainWindow;
|
||||
@@ -39,6 +40,7 @@ public class CommonGuiPluginsContext {
|
||||
|
||||
public void reset() {
|
||||
codePopupActionList.clear();
|
||||
treePopupMenuEntries.clear();
|
||||
mainWindow.resetPluginsMenu();
|
||||
}
|
||||
|
||||
@@ -50,6 +52,10 @@ public class CommonGuiPluginsContext {
|
||||
return codePopupActionList;
|
||||
}
|
||||
|
||||
public List<TreePopupMenuEntry> getTreePopupMenuEntries() {
|
||||
return treePopupMenuEntries;
|
||||
}
|
||||
|
||||
public void addMenuAction(String name, Runnable action) {
|
||||
ActionHandler item = new ActionHandler(ev -> {
|
||||
try {
|
||||
|
||||
@@ -3,6 +3,7 @@ package jadx.gui.plugins.context;
|
||||
import java.awt.Container;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JFrame;
|
||||
@@ -16,6 +17,7 @@ import org.slf4j.LoggerFactory;
|
||||
import jadx.api.JadxDecompiler;
|
||||
import jadx.api.JavaClass;
|
||||
import jadx.api.JavaNode;
|
||||
import jadx.api.gui.tree.ITreeNode;
|
||||
import jadx.api.metadata.ICodeNodeRef;
|
||||
import jadx.api.plugins.events.IJadxEvents;
|
||||
import jadx.api.plugins.events.types.NodeRenamedByUser;
|
||||
@@ -75,6 +77,11 @@ public class GuiPluginContext implements JadxGuiContext {
|
||||
commonContext.getCodePopupActionList().add(new CodePopupAction(name, enabled, keyBinding, action));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTreePopupMenuEntry(String name, Predicate<ITreeNode> addPredicate, Consumer<ITreeNode> action) {
|
||||
commonContext.getTreePopupMenuEntries().add(new TreePopupMenuEntry(name, addPredicate, action));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerGlobalKeyBinding(String id, String keyBinding, Runnable action) {
|
||||
KeyStroke keyStroke = KeyStroke.getKeyStroke(keyBinding);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package jadx.gui.plugins.context;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.swing.JMenuItem;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.gui.tree.ITreeNode;
|
||||
|
||||
public class TreePopupMenuEntry {
|
||||
private final String name;
|
||||
private final Predicate<ITreeNode> addPredicate;
|
||||
private final Consumer<ITreeNode> action;
|
||||
|
||||
public TreePopupMenuEntry(String name, Predicate<ITreeNode> addPredicate, Consumer<ITreeNode> action) {
|
||||
this.name = name;
|
||||
this.addPredicate = addPredicate;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public @Nullable JMenuItem buildEntry(ITreeNode node) {
|
||||
if (!addPredicate.test(node)) {
|
||||
return null;
|
||||
}
|
||||
JMenuItem menuItem = new JMenuItem(name);
|
||||
menuItem.addActionListener(ev -> action.accept(node));
|
||||
return menuItem;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.TreeNode;
|
||||
@@ -16,13 +15,14 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.api.JavaNode;
|
||||
import jadx.api.gui.tree.ITreeNode;
|
||||
import jadx.api.metadata.ICodeNodeRef;
|
||||
import jadx.core.utils.ListUtils;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.ui.panel.ContentPanel;
|
||||
import jadx.gui.ui.tab.TabbedPane;
|
||||
|
||||
public abstract class JNode extends DefaultMutableTreeNode implements Comparable<JNode> {
|
||||
public abstract class JNode extends DefaultMutableTreeNode implements ITreeNode, Comparable<JNode> {
|
||||
|
||||
private static final long serialVersionUID = -5154479091781041008L;
|
||||
|
||||
@@ -39,6 +39,7 @@ public abstract class JNode extends DefaultMutableTreeNode implements Comparable
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICodeNodeRef getCodeNodeRef() {
|
||||
return null;
|
||||
}
|
||||
@@ -59,8 +60,7 @@ public abstract class JNode extends DefaultMutableTreeNode implements Comparable
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract Icon getIcon();
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
JavaNode javaNode = getJavaNode();
|
||||
if (javaNode == null) {
|
||||
@@ -77,11 +77,7 @@ public abstract class JNode extends DefaultMutableTreeNode implements Comparable
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* JNode identifier.
|
||||
* Should be locale independent.
|
||||
* TODO: implement list or enum of custom tree nodes to allow extension from plugins
|
||||
*/
|
||||
@Override
|
||||
public String getID() {
|
||||
return makeString();
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ import javax.swing.JFileChooser;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
@@ -107,6 +108,8 @@ import jadx.gui.jobs.TaskWithExtraOnFinish;
|
||||
import jadx.gui.logs.LogCollector;
|
||||
import jadx.gui.logs.LogOptions;
|
||||
import jadx.gui.logs.LogPanel;
|
||||
import jadx.gui.plugins.context.CommonGuiPluginsContext;
|
||||
import jadx.gui.plugins.context.TreePopupMenuEntry;
|
||||
import jadx.gui.plugins.mappings.RenameMappingsGui;
|
||||
import jadx.gui.plugins.quark.QuarkDialog;
|
||||
import jadx.gui.settings.ExportProjectProperties;
|
||||
@@ -917,6 +920,16 @@ public class MainWindow extends JFrame {
|
||||
return;
|
||||
}
|
||||
JPopupMenu menu = node.onTreePopupMenu(this);
|
||||
CommonGuiPluginsContext pluginsContext = getWrapper().getGuiPluginsContext();
|
||||
for (TreePopupMenuEntry entry : pluginsContext.getTreePopupMenuEntries()) {
|
||||
JMenuItem menuItem = entry.buildEntry(node);
|
||||
if (menuItem != null) {
|
||||
if (menu == null) {
|
||||
menu = new JPopupMenu();
|
||||
}
|
||||
menu.add(menuItem);
|
||||
}
|
||||
}
|
||||
if (menu != null) {
|
||||
menu.show(e.getComponent(), e.getX(), e.getY());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user