Right-Click Context Menu API

This commit is contained in:
Konloch 2021-07-27 00:26:38 -07:00
parent 70a205c5d9
commit 3abdbf6b68
11 changed files with 433 additions and 142 deletions

View file

@ -23,7 +23,8 @@ import me.konloch.kontainer.io.DiskWriter;
import org.apache.commons.io.FilenameUtils;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.resources.IconResources;
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu.ContextMenu;
import the.bytecode.club.bytecodeviewer.resources.importing.Import;
import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings;
import the.bytecode.club.bytecodeviewer.translation.TranslatedComponents;
@ -82,45 +83,8 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
{
if (selPath == null)
return;
boolean isContainerSelected = selPath.getParentPath() != null && selPath.getParentPath().getParentPath() == null;
//TODO this is hacky - there is probably a better way to do this
tree.setSelectionPath(selPath);
DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
boolean isResourceSelected = !node.children().hasMoreElements();
rightClickMenu.removeAll();
//container selected
if(isContainerSelected)
rightClickMenu.add(new ResourceListRightClickRemove(this, x, y, tree));
else if(isResourceSelected) //container resource selected
rightClickMenu.add(new ResourceListRightClickOpen(this, x, y, tree));
if(isContainerSelected || !isResourceSelected)
{
rightClickMenu.add(new AbstractAction("Expand", IconResources.CollapsedIcon.createCollapsedIcon())
{
@Override
public void actionPerformed(ActionEvent e)
{
TreePath selPath = ResourceListPane.this.tree.getPathForLocation(x, y);
expandAll(tree, Objects.requireNonNull(selPath), true);
}
});
rightClickMenu.add(new AbstractAction("Collapse", IconResources.ExpandedIcon.createExpandedIcon())
{
@Override
public void actionPerformed(ActionEvent e)
{
TreePath selPath = ResourceListPane.this.tree.getPathForLocation(x, y);
expandAll(tree, Objects.requireNonNull(selPath), false);
}
});
}
ContextMenu.buildMenu(tree, selPath, rightClickMenu);
rightClickMenu.show(this.tree, x, y);
}
@ -186,7 +150,7 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
tree.expandPath(new TreePath(tree.getModel().getRoot()));
tree.updateUI();
//TODO add a setting for this
//TODO add a setting to expand on resource import
// expandAll(tree, true);
}
@ -276,7 +240,7 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
}
@SuppressWarnings("rawtypes")
private void expandAll(final JTree tree, final TreePath parent,
public void expandAll(final JTree tree, final TreePath parent,
final boolean expand) {
// Traverse children
final TreeNode node = (TreeNode) parent.getLastPathComponent();
@ -302,6 +266,23 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
tree.repaint();
tree.updateUI();
}
public void quickDecompile(Decompiler decompiler, TreePath selPath)
{
Decompiler tempDecompiler1 = BytecodeViewer.viewer.viewPane1.getSelectedDecompiler();
Decompiler tempDecompiler2 = BytecodeViewer.viewer.viewPane2.getSelectedDecompiler();
Decompiler tempDecompiler3 = BytecodeViewer.viewer.viewPane3.getSelectedDecompiler();
BytecodeViewer.viewer.viewPane1.setSelectedDecompiler(decompiler);
BytecodeViewer.viewer.viewPane2.setSelectedDecompiler(Decompiler.NONE);
BytecodeViewer.viewer.viewPane3.setSelectedDecompiler(Decompiler.NONE);
openPath(selPath);
BytecodeViewer.viewer.viewPane1.setSelectedDecompiler(tempDecompiler1);
BytecodeViewer.viewer.viewPane2.setSelectedDecompiler(tempDecompiler2);
BytecodeViewer.viewer.viewPane3.setSelectedDecompiler(tempDecompiler3);
}
public void openPath(TreePath path)
{

View file

@ -1,79 +0,0 @@
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.resources.ResourceContainer;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.awt.event.ActionEvent;
import java.util.Enumeration;
import java.util.Objects;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
/**
* @author Konloch
* @since 6/22/2021
*/
public class ResourceListRightClickRemove extends AbstractAction
{
private final ResourceListPane resourceListPane;
private final int x;
private final int y;
private final ResourceTree tree;
public ResourceListRightClickRemove(ResourceListPane resourceListPane, int x, int y, ResourceTree tree)
{
super("Remove");
this.resourceListPane = resourceListPane;
this.x = x;
this.y = y;
this.tree = tree;
}
@Override
public void actionPerformed(ActionEvent e)
{
TreePath selPath = resourceListPane.tree.getClosestPathForLocation(x, y);
DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) Objects.requireNonNull(selPath).getLastPathComponent();
Enumeration<?> enumeration = resourceListPane.treeRoot.children();
while (enumeration.hasMoreElements())
{
DefaultMutableTreeNode node = (DefaultMutableTreeNode) enumeration.nextElement();
if (node.isNodeAncestor(selectNode))
{
DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
root.remove(node);
for (ResourceContainer resourceContainer : BytecodeViewer.resourceContainers)
{
if (resourceContainer.name.equals(selectNode.toString()))
{
resourceListPane.removeResource(resourceContainer);
resourceListPane.removeFile(resourceContainer);
break;
}
}
return;
}
}
}
}

View file

@ -0,0 +1,33 @@
package the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.ResourceTree;
import javax.swing.*;
import javax.swing.tree.TreePath;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
/**
* @author Konloch
* @since 7/26/2021
*/
public interface BuildContextMenuItem
{
void buildMenu(ResourceTree tree, TreePath selPath, JPopupMenu menu);
}

View file

@ -0,0 +1,85 @@
package the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.ResourceTree;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu.impl.*;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.util.ArrayList;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
/**
* @author Konloch
* @since 7/26/2021
*/
public class ContextMenu
{
private static ContextMenu SINGLETON = new ContextMenu();
private final ArrayList<ContextMenuItem> contextMenuItems = new ArrayList<>();
static
{
addContext(new Remove());
addContext(new Open());
addContext(new QuickOpen());
addContext(new Expand());
addContext(new Collapse());
}
public static void addContext(ContextMenuItem menuItem)
{
SINGLETON.contextMenuItems.add(menuItem);
}
public static void buildMenu(ResourceTree tree, TreePath selPath, JPopupMenu menu)
{
menu.removeAll();
boolean isContainerSelected = selPath.getParentPath() != null && selPath.getParentPath().getParentPath() == null;
//TODO this is hacky - there is probably a better way to do this
tree.setSelectionPath(selPath);
DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
boolean isResourceSelected = !node.children().hasMoreElements();
for(ContextMenuItem item : SINGLETON.contextMenuItems)
{
switch(item.getMenuType())
{
case CONTAINER:
if(!isContainerSelected)
continue;
break;
case RESOURCE:
if(!isResourceSelected || isContainerSelected)
continue;
break;
case DIRECTORY:
if(isResourceSelected)
continue;
break;
}
item.getBuildContextMenuItem().buildMenu(tree, selPath, menu);
}
}
}

View file

@ -0,0 +1,44 @@
package the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
/**
* @author Konloch
* @since 7/26/2021
*/
public class ContextMenuItem
{
private final ContextMenuType menuType;
private final BuildContextMenuItem buildContextMenuItem;
public ContextMenuItem(ContextMenuType menuType, BuildContextMenuItem buildContextMenuItem) {
this.menuType = menuType;
this.buildContextMenuItem = buildContextMenuItem;
}
public ContextMenuType getMenuType()
{
return menuType;
}
public BuildContextMenuItem getBuildContextMenuItem()
{
return buildContextMenuItem;
}
}

View file

@ -0,0 +1,31 @@
package the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
/**
* @author Konloch
* @since 7/26/2021
*/
public enum ContextMenuType
{
ALL,
RESOURCE,
DIRECTORY,
CONTAINER,
}

View file

@ -1,7 +1,10 @@
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
package the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu.impl;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu.ContextMenuItem;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu.ContextMenuType;
import javax.swing.*;
import javax.swing.tree.TreePath;
import java.awt.event.ActionEvent;
/***************************************************************************
@ -26,26 +29,20 @@ import java.awt.event.ActionEvent;
* @author Konloch
* @since 7/26/2021
*/
public class ResourceListRightClickOpen extends AbstractAction
public class Collapse extends ContextMenuItem
{
private final ResourceListPane resourceListPane;
private final int x;
private final int y;
private final ResourceTree tree;
public ResourceListRightClickOpen(ResourceListPane resourceListPane, int x, int y, ResourceTree tree)
public Collapse()
{
super("Open");
this.resourceListPane = resourceListPane;
this.x = x;
this.y = y;
this.tree = tree;
}
@Override
public void actionPerformed(ActionEvent e)
{
TreePath selPath = resourceListPane.tree.getClosestPathForLocation(x, y);
resourceListPane.openPath(selPath);
super(ContextMenuType.DIRECTORY, ((tree, selPath, menu) ->
{
menu.add(new AbstractAction("Collapse")
{
@Override
public void actionPerformed(ActionEvent e)
{
BytecodeViewer.viewer.resourcePane.expandAll(tree, selPath, false);
}
});
}));
}
}

View file

@ -0,0 +1,48 @@
package the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu.impl;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu.ContextMenuItem;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu.ContextMenuType;
import javax.swing.*;
import java.awt.event.ActionEvent;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
/**
* @author Konloch
* @since 7/26/2021
*/
public class Expand extends ContextMenuItem
{
public Expand()
{
super(ContextMenuType.DIRECTORY, ((tree, selPath, menu) ->
{
menu.add(new AbstractAction("Expand")
{
@Override
public void actionPerformed(ActionEvent e)
{
BytecodeViewer.viewer.resourcePane.expandAll(tree, selPath, true);
}
});
}));
}
}

View file

@ -0,0 +1,48 @@
package the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu.impl;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu.ContextMenuItem;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu.ContextMenuType;
import javax.swing.*;
import java.awt.event.ActionEvent;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
/**
* @author Konloch
* @since 7/26/2021
*/
public class Open extends ContextMenuItem
{
public Open()
{
super(ContextMenuType.RESOURCE, ((tree, selPath, menu) ->
{
menu.add(new AbstractAction("Open")
{
@Override
public void actionPerformed(ActionEvent e)
{
BytecodeViewer.viewer.resourcePane.openPath(selPath);
}
});
}));
}
}

View file

@ -0,0 +1,55 @@
package the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu.impl;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.decompilers.Decompiler;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu.ContextMenuItem;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu.ContextMenuType;
import javax.swing.*;
import javax.swing.tree.TreePath;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
/**
* @author Konloch
* @since 7/26/2021
*/
public class QuickOpen extends ContextMenuItem
{
public QuickOpen()
{
super(ContextMenuType.RESOURCE, ((tree, selPath, menu) ->
{
JMenu quickOpen = new JMenu("Quick Open");
quickOpen.add(createMenu("Procyon", ()->BytecodeViewer.viewer.resourcePane.quickDecompile(Decompiler.PROCYON_DECOMPILER, selPath)));
quickOpen.add(createMenu("CFR", ()->BytecodeViewer.viewer.resourcePane.quickDecompile(Decompiler.CFR_DECOMPILER, selPath)));
quickOpen.add(createMenu("FernFlower", ()->BytecodeViewer.viewer.resourcePane.quickDecompile(Decompiler.FERNFLOWER_DECOMPILER, selPath)));
quickOpen.add(createMenu("Krakatau", ()->BytecodeViewer.viewer.resourcePane.quickDecompile(Decompiler.KRAKATAU_DECOMPILER, selPath)));
quickOpen.add(createMenu("Bytecode", ()->BytecodeViewer.viewer.resourcePane.quickDecompile(Decompiler.BYTECODE_DISASSEMBLER, selPath)));
menu.add(quickOpen);
}));
}
private static JMenuItem createMenu(String name, Runnable onClick)
{
JMenuItem menu = new JMenuItem(name);
menu.addActionListener((e)->onClick.run());
return menu;
}
}

View file

@ -0,0 +1,48 @@
package the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu.impl;
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu.ContextMenuItem;
import the.bytecode.club.bytecodeviewer.gui.resourcelist.contextmenu.ContextMenuType;
import javax.swing.*;
import java.awt.event.ActionEvent;
/***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
/**
* @author Konloch
* @since 7/26/2021
*/
public class Remove extends ContextMenuItem
{
public Remove()
{
super(ContextMenuType.CONTAINER, ((tree, selPath, menu) ->
{
menu.add(new AbstractAction("Remove")
{
@Override
public void actionPerformed(ActionEvent e)
{
BytecodeViewer.viewer.resourcePane.expandAll(tree, selPath, false);
}
});
}));
}
}