mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-25 23:15:10 +08:00
Merge remote-tracking branch
'origin/GP-6944-dragonmacher-symbol-tree-delete-org-node' (Closes #3252)
This commit is contained in:
+42
-13
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -16,15 +16,18 @@
|
||||
package ghidra.app.plugin.core.symboltree.actions;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import docking.action.KeyBindingData;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.plugin.core.symboltree.SymbolTreeActionContext;
|
||||
import ghidra.app.plugin.core.symboltree.SymbolTreePlugin;
|
||||
import ghidra.app.plugin.core.symboltree.nodes.SymbolNode;
|
||||
import ghidra.app.plugin.core.symboltree.nodes.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import resources.Icons;
|
||||
@@ -53,8 +56,11 @@ public class DeleteAction extends SymbolTreeContextAction {
|
||||
|
||||
for (TreePath treePath : selectionPaths) {
|
||||
Object object = treePath.getLastPathComponent();
|
||||
if (!(object instanceof SymbolNode)) {
|
||||
return false; // can only delete symbol nodes
|
||||
if (!(object instanceof SymbolNode) &&
|
||||
!(object instanceof OrganizationNode)) {
|
||||
// can only delete symbol nodes or the fake organization nodes, as those are just
|
||||
// small groups of symbols
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,18 +70,41 @@ public class DeleteAction extends SymbolTreeContextAction {
|
||||
@Override
|
||||
public void actionPerformed(SymbolTreeActionContext context) {
|
||||
TreePath[] selectionPaths = context.getSelectedSymbolTreePaths();
|
||||
List<SymbolTreeNode> nodes = getNodes(selectionPaths);
|
||||
Program program = plugin.getProgram();
|
||||
int transactionID = program.startTransaction("Delete Symbol(s)");
|
||||
try {
|
||||
for (TreePath treePath : selectionPaths) {
|
||||
SymbolNode symbolNode = (SymbolNode) treePath.getLastPathComponent();
|
||||
Symbol symbol = symbolNode.getSymbol();
|
||||
program.withTransaction("Delete Symbols(s)", () -> {
|
||||
for (SymbolTreeNode node : nodes) {
|
||||
Symbol symbol = node.getSymbol();
|
||||
symbol.delete();
|
||||
symbolNode.getParent().removeNode(symbolNode);
|
||||
node.getParent().removeNode(node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private List<SymbolTreeNode> getNodes(TreePath[] paths) {
|
||||
List<SymbolTreeNode> nodes = new ArrayList<>();
|
||||
for (TreePath treePath : paths) {
|
||||
Object object = treePath.getLastPathComponent();
|
||||
if (object instanceof SymbolNode symbolNode) {
|
||||
nodes.add(symbolNode);
|
||||
}
|
||||
else if (object instanceof OrganizationNode orgNode) {
|
||||
getNodes(orgNode, nodes);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
private void getNodes(OrganizationNode orgNode, List<SymbolTreeNode> nodes) {
|
||||
List<GTreeNode> children = orgNode.getChildren();
|
||||
for (GTreeNode node : children) {
|
||||
if (node instanceof SymbolNode symbolNode) {
|
||||
nodes.add(symbolNode);
|
||||
}
|
||||
else if (node instanceof OrganizationNode childOrgNode) {
|
||||
getNodes(childOrgNode, nodes);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+47
@@ -18,6 +18,8 @@ package ghidra.app.plugin.core.symboltree;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.SwingUtilities;
|
||||
@@ -723,7 +725,52 @@ public class SymbolTreePlugin2Test extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
// verify node is in the tree
|
||||
assertClassNodes("ClassGroup1::ClassGroup10::ClassGroup100::NewClass");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteOrgNode() throws Exception {
|
||||
|
||||
//
|
||||
// Tests that OrganizationNodes can be deleted from the UI
|
||||
//
|
||||
|
||||
// set org node threshold to a low value
|
||||
ToolOptions options = tool.getOptions(SymbolTreePlugin.OPTIONS_CATEGORY);
|
||||
int newThreshold = 4;
|
||||
options.setInt(SymbolTreePlugin.OPTION_NAME_GROUP_THRESHOLD, newThreshold);
|
||||
|
||||
/*
|
||||
Create enough nodes to trigger an org node.
|
||||
|
||||
Namespaces
|
||||
NsGroup1
|
||||
NsGroup10
|
||||
NsGroup100
|
||||
NsGroup2
|
||||
NsGroup3
|
||||
*/
|
||||
createOrgNamespaces(newThreshold);
|
||||
openNamespaceNodes("NsGroup1::NsGroup10::NsGroup100");
|
||||
|
||||
GTreeNode group10 = getNode(tree, "Global", "Namespaces", "NsGroup1", "NsGroup10");
|
||||
|
||||
List<GTreeNode> children = group10.getChildren();
|
||||
List<SymbolNode> symbols =
|
||||
children.stream().map(n -> (SymbolNode) n).collect(Collectors.toList());
|
||||
|
||||
util.selectNode(group10);
|
||||
|
||||
ActionContext context = util.getSymbolTreeContext();
|
||||
performTreeAction(deleteAction, context);
|
||||
|
||||
GTreeNode group1 = getNode(tree, "Global", "Namespaces", "NsGroup1");
|
||||
group10 = group1.getChild("NsGroup10");
|
||||
assertNull(group10);
|
||||
|
||||
for (SymbolNode node : symbols) {
|
||||
Symbol symbol = node.getSymbol();
|
||||
assertTrue(symbol.isDeleted());
|
||||
}
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
Reference in New Issue
Block a user