Right-Click Context Menu
Adds better control to the resource list and gives a right-click context menu that changes depending on the selected node More work is needed and a proper context API should be provided
This commit is contained in:
parent
f7e47540dc
commit
70a205c5d9
3 changed files with 119 additions and 47 deletions
|
@ -78,33 +78,48 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
|
||||||
|
|
||||||
public final KeyAdapter search = new SearchKeyAdapter(this);
|
public final KeyAdapter search = new SearchKeyAdapter(this);
|
||||||
|
|
||||||
private void showPopMenu(ResourceTree tree, TreePath selPath, int x, int y)
|
private void showContextMenu(ResourceTree tree, TreePath selPath, int x, int y)
|
||||||
{
|
{
|
||||||
if (selPath == null)
|
if (selPath == null)
|
||||||
return;
|
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();
|
rightClickMenu.removeAll();
|
||||||
|
|
||||||
rightClickMenu.add(new ResourceListRightClickRemove(this, x, y, tree));
|
//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));
|
||||||
|
|
||||||
rightClickMenu.add(new AbstractAction("Expand", IconResources.CollapsedIcon.createCollapsedIcon())
|
if(isContainerSelected || !isResourceSelected)
|
||||||
{
|
{
|
||||||
@Override
|
rightClickMenu.add(new AbstractAction("Expand", IconResources.CollapsedIcon.createCollapsedIcon())
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
{
|
||||||
TreePath selPath = ResourceListPane.this.tree.getPathForLocation(x, y);
|
@Override
|
||||||
expandAll(tree, Objects.requireNonNull(selPath), true);
|
public void actionPerformed(ActionEvent e)
|
||||||
}
|
{
|
||||||
});
|
TreePath selPath = ResourceListPane.this.tree.getPathForLocation(x, y);
|
||||||
rightClickMenu.add(new AbstractAction("Collapse", IconResources.ExpandedIcon.createExpandedIcon())
|
expandAll(tree, Objects.requireNonNull(selPath), true);
|
||||||
{
|
}
|
||||||
@Override
|
});
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
|
rightClickMenu.add(new AbstractAction("Collapse", IconResources.ExpandedIcon.createExpandedIcon())
|
||||||
{
|
{
|
||||||
TreePath selPath = ResourceListPane.this.tree.getPathForLocation(x, y);
|
@Override
|
||||||
expandAll(tree, Objects.requireNonNull(selPath), false);
|
public void actionPerformed(ActionEvent e)
|
||||||
}
|
{
|
||||||
});
|
TreePath selPath = ResourceListPane.this.tree.getPathForLocation(x, y);
|
||||||
|
expandAll(tree, Objects.requireNonNull(selPath), false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
rightClickMenu.show(this.tree, x, y);
|
rightClickMenu.show(this.tree, x, y);
|
||||||
}
|
}
|
||||||
|
@ -119,6 +134,7 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
|
||||||
public ResourceListPane()
|
public ResourceListPane()
|
||||||
{
|
{
|
||||||
super("Files", TranslatedComponents.FILES);
|
super("Files", TranslatedComponents.FILES);
|
||||||
|
|
||||||
tree.setRootVisible(false);
|
tree.setRootVisible(false);
|
||||||
tree.setShowsRootHandles(true);
|
tree.setShowsRootHandles(true);
|
||||||
quickSearch.setForeground(Color.gray);
|
quickSearch.setForeground(Color.gray);
|
||||||
|
@ -371,22 +387,12 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
|
||||||
if (e.isMetaDown())
|
if (e.isMetaDown())
|
||||||
{
|
{
|
||||||
ResourceTree tree = (ResourceTree) e.getSource();
|
ResourceTree tree = (ResourceTree) e.getSource();
|
||||||
TreePath selPath = ResourceListPane.this.tree.getPathForLocation(e.getX(), e.getY());
|
TreePath selPath = ResourceListPane.this.tree.getClosestPathForLocation(e.getX(), e.getY());
|
||||||
|
|
||||||
if (selPath == null)
|
if (selPath == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) selPath.getLastPathComponent();
|
showContextMenu(tree, selPath, e.getX(), e.getY());
|
||||||
Enumeration<?> enumeration = treeRoot.children();
|
|
||||||
while (enumeration.hasMoreElements())
|
|
||||||
{
|
|
||||||
DefaultMutableTreeNode node = (DefaultMutableTreeNode) enumeration.nextElement();
|
|
||||||
if (node.isNodeAncestor(selectNode))
|
|
||||||
{
|
|
||||||
//rightClickMenu.show(tree, e.getX(), e.getY());
|
|
||||||
showPopMenu(tree, selPath, e.getX(), e.getY());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -406,7 +412,8 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
|
||||||
this.tree.addMouseListener(new MouseAdapter() {
|
this.tree.addMouseListener(new MouseAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void mousePressed(MouseEvent e) {
|
public void mousePressed(MouseEvent e) {
|
||||||
openPath(tree.getPathForLocation(e.getX(), e.getY()));
|
if(e.getButton() == MouseEvent.BUTTON1) //right-click
|
||||||
|
openPath(tree.getPathForLocation(e.getX(), e.getY()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -428,22 +435,31 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
|
||||||
public void keyTyped(KeyEvent e) { }
|
public void keyTyped(KeyEvent e) { }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void keyPressed(KeyEvent e) {
|
public void keyPressed(KeyEvent e)
|
||||||
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
{
|
||||||
if (e.getSource() instanceof ResourceTree) {
|
if (e.getKeyCode() == KeyEvent.VK_ENTER)
|
||||||
|
{
|
||||||
|
if (e.getSource() instanceof ResourceTree)
|
||||||
|
{
|
||||||
ResourceTree tree = (ResourceTree) e.getSource();
|
ResourceTree tree = (ResourceTree) e.getSource();
|
||||||
openPath(tree.getSelectionPath());
|
openPath(tree.getSelectionPath());
|
||||||
}
|
}
|
||||||
} else if ((int) e.getKeyChar() != 0 && (int) e.getKeyChar() != 8 && (int) e.getKeyChar() != 127 && (int) e.getKeyChar() != 65535 && !e.isControlDown() && !e.isAltDown()) {
|
}
|
||||||
|
else if ((int) e.getKeyChar() != 0 &&
|
||||||
|
(int) e.getKeyChar() != 8 &&
|
||||||
|
(int) e.getKeyChar() != 127 &&
|
||||||
|
(int) e.getKeyChar() != 65535 &&
|
||||||
|
!e.isControlDown() &&
|
||||||
|
!e.isAltDown())
|
||||||
|
{
|
||||||
quickSearch.grabFocus();
|
quickSearch.grabFocus();
|
||||||
quickSearch.setText("" + e.getKeyChar());
|
quickSearch.setText("" + e.getKeyChar());
|
||||||
cancel = true;
|
cancel = true;
|
||||||
} else if (e.isControlDown() && (int) e.getKeyChar() == 6) //ctrl + f
|
|
||||||
{
|
|
||||||
quickSearch.grabFocus();
|
|
||||||
} else {
|
|
||||||
cancel = true;
|
|
||||||
}
|
}
|
||||||
|
else if (e.isControlDown() && (int) e.getKeyChar() == 6) //ctrl + f
|
||||||
|
quickSearch.grabFocus();
|
||||||
|
else
|
||||||
|
cancel = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -451,18 +467,23 @@ public class ResourceListPane extends TranslatedVisibleComponent implements File
|
||||||
public void attachQuickSearchListeners()
|
public void attachQuickSearchListeners()
|
||||||
{
|
{
|
||||||
quickSearch.addKeyListener(search);
|
quickSearch.addKeyListener(search);
|
||||||
quickSearch.addFocusListener(new FocusListener() {
|
quickSearch.addFocusListener(new FocusListener()
|
||||||
|
{
|
||||||
@Override
|
@Override
|
||||||
public void focusGained(final FocusEvent arg0) {
|
public void focusGained(final FocusEvent arg0)
|
||||||
if (quickSearch.getText().equals(TranslatedStrings.QUICK_FILE_SEARCH_NO_FILE_EXTENSION.toString())) {
|
{
|
||||||
|
if (quickSearch.getText().equals(TranslatedStrings.QUICK_FILE_SEARCH_NO_FILE_EXTENSION.toString()))
|
||||||
|
{
|
||||||
quickSearch.setText("");
|
quickSearch.setText("");
|
||||||
quickSearch.setForeground(Color.black);
|
quickSearch.setForeground(Color.black);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void focusLost(final FocusEvent arg0) {
|
public void focusLost(final FocusEvent arg0)
|
||||||
if (quickSearch.getText().isEmpty()) {
|
{
|
||||||
|
if (quickSearch.getText().isEmpty())
|
||||||
|
{
|
||||||
quickSearch.setText(TranslatedStrings.QUICK_FILE_SEARCH_NO_FILE_EXTENSION.toString());
|
quickSearch.setText(TranslatedStrings.QUICK_FILE_SEARCH_NO_FILE_EXTENSION.toString());
|
||||||
quickSearch.setForeground(Color.gray);
|
quickSearch.setForeground(Color.gray);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
package the.bytecode.club.bytecodeviewer.gui.resourcelist;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.tree.TreePath;
|
||||||
|
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 ResourceListRightClickOpen extends AbstractAction
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,7 +51,7 @@ public class ResourceListRightClickRemove extends AbstractAction
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e)
|
public void actionPerformed(ActionEvent e)
|
||||||
{
|
{
|
||||||
TreePath selPath = resourceListPane.tree.getPathForLocation(x, y);
|
TreePath selPath = resourceListPane.tree.getClosestPathForLocation(x, y);
|
||||||
DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) Objects.requireNonNull(selPath).getLastPathComponent();
|
DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) Objects.requireNonNull(selPath).getLastPathComponent();
|
||||||
Enumeration<?> enumeration = resourceListPane.treeRoot.children();
|
Enumeration<?> enumeration = resourceListPane.treeRoot.children();
|
||||||
while (enumeration.hasMoreElements())
|
while (enumeration.hasMoreElements())
|
||||||
|
|
Loading…
Reference in a new issue