From 9f2679a9f750d6509cfeff004ae8642c8ed73161 Mon Sep 17 00:00:00 2001 From: ghidravore Date: Mon, 15 Nov 2021 11:38:19 -0500 Subject: [PATCH] GP-1445 fixing issue with renaming a datatype that has the same name as a category at the same level --- .../core/datamgr/actions/RenameAction.java | 10 ++--- .../core/symboltree/actions/RenameAction.java | 10 ++--- .../datamgr/DataTypeManagerPluginTest.java | 39 +++++++++++++++++++ .../main/java/docking/widgets/tree/GTree.java | 24 +++++++++--- .../tree/tasks/GTreeStartEditingTask.java | 16 ++++++-- .../actions/ProjectDataRenameAction.java | 2 +- 6 files changed, 80 insertions(+), 21 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RenameAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RenameAction.java index ca5ab9a414..fcd05afe75 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RenameAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/RenameAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +15,6 @@ */ package ghidra.app.plugin.core.datamgr.actions; -import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin; -import ghidra.app.plugin.core.datamgr.DataTypesActionContext; -import ghidra.app.plugin.core.datamgr.tree.*; - import javax.swing.tree.TreePath; import docking.ActionContext; @@ -27,6 +22,9 @@ import docking.action.DockingAction; import docking.action.MenuData; import docking.widgets.tree.GTree; import docking.widgets.tree.GTreeNode; +import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin; +import ghidra.app.plugin.core.datamgr.DataTypesActionContext; +import ghidra.app.plugin.core.datamgr.tree.*; public class RenameAction extends DockingAction { @@ -76,7 +74,7 @@ public class RenameAction extends DockingAction { void rename(final DataTypeArchiveGTree tree) { TreePath path = tree.getSelectionPath(); final GTreeNode node = (GTreeNode) path.getLastPathComponent(); - tree.startEditing(node.getParent(), node.getName()); + tree.startEditing(node); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/RenameAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/RenameAction.java index 6f379d5ac6..fd142c52a3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/RenameAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/actions/RenameAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +15,13 @@ */ package ghidra.app.plugin.core.symboltree.actions; -import ghidra.app.plugin.core.symboltree.SymbolTreeActionContext; -import ghidra.app.plugin.core.symboltree.SymbolTreePlugin; -import ghidra.app.plugin.core.symboltree.nodes.SymbolNode; - import javax.swing.tree.TreePath; 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; public class RenameAction extends SymbolTreeContextAction { @@ -47,7 +45,7 @@ public class RenameAction extends SymbolTreeContextAction { public void actionPerformed(SymbolTreeActionContext context) { TreePath[] selectionPaths = context.getSelectedSymbolTreePaths(); GTreeNode node = (GTreeNode) selectionPaths[0].getLastPathComponent(); - context.getSymbolTree().startEditing(node.getParent(), node.getName()); + context.getSymbolTree().startEditing(node); } } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java index 6f854fec5f..83a1150837 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/datamgr/DataTypeManagerPluginTest.java @@ -377,6 +377,45 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe assertNotNull(programNode.getChild(newCategoryName)); } + @Test + public void testRenameDataTypeWithSameNameAsCategory() throws Exception { + // select a category + expandNode(programNode); + String miscNodeName = "MISC"; + final CategoryNode miscNode = (CategoryNode) programNode.getChild(miscNodeName); + assertNotNull(miscNode); + StructureDataType struct = new StructureDataType("MISC", 0); + struct.add(new DWordDataType()); + builder.addDataType(struct); + waitForTree(); + DataType resolved = program.getDataTypeManager().resolve(struct, null); + DataTypeNode node = programNode.getNode(resolved); + selectNode(node); + + final DockingActionIf action = getAction(plugin, "Rename"); + assertTrue(action.isEnabledForContext(treeContext)); + + // select "Rename" action + final String newDatatypeName = "ItWorked"; + DataTypeTestUtils.performAction(action, tree); + waitForTree(); + runSwing(() -> { + int rowForPath = jTree.getRowForPath(miscNode.getTreePath()); + + DefaultTreeCellEditor cellEditor = (DefaultTreeCellEditor) tree.getCellEditor(); + Container container = (Container) cellEditor.getTreeCellEditorComponent(jTree, miscNode, + true, true, true, rowForPath); + JTextField textField = (JTextField) container.getComponent(0); + + textField.setText(newDatatypeName); + jTree.stopEditing(); + }); + waitForProgram(); + waitForTree(); + + assertEquals("ItWorked", resolved.getName()); + } + @Test public void testRenameCategoryDuplicate() throws Exception { expandNode(programNode); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTree.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTree.java index 303d4fe19a..20fc91cc7c 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTree.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTree.java @@ -943,13 +943,12 @@ public class GTree extends JPanel implements BusyListener { } /** - * Requests that the node with the given name, in the given parent, be edited. This - * operation (as with many others on this tree) is asynchronous. This request will be - * buffered as needed to wait for the given node to be added to the parent, up to a timeout - * period. + * Requests that the node with the given name, in the given parent, be edited. This + * operation is asynchronous. This request will be buffered as needed to wait for + * the given node to be added to the parent, up to a timeout period. * * @param parent the parent node - * @param childName the child node name + * @param childName the name of the child to edit */ public void startEditing(GTreeNode parent, final String childName) { @@ -972,6 +971,21 @@ public class GTree extends JPanel implements BusyListener { }); } + /** + * Requests that the node be edited. This operation is asynchronous. + * + * @param child the node to edit + */ + public void startEditing(GTreeNode child) { + + // we call this here, even though the JTree will do this for us, so that we will trigger + // a load call before this task is run, in case lazy nodes are involved in this tree, + // which must be loaded before we can edit + expandPath(child.getParent()); + + runTask(new GTreeStartEditingTask(GTree.this, tree, child)); + } + @Override public synchronized void addMouseListener(MouseListener listener) { mouseListenerDelegate.addMouseListener(listener); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/tasks/GTreeStartEditingTask.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/tasks/GTreeStartEditingTask.java index 3132cce3bf..97bc88cd38 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/tasks/GTreeStartEditingTask.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/tasks/GTreeStartEditingTask.java @@ -36,6 +36,7 @@ public class GTreeStartEditingTask extends GTreeTask { private final GTreeNode parent; private final String childName; + private GTreeNode editNode; public GTreeStartEditingTask(GTree gTree, JTree jTree, GTreeNode parent, String childName) { super(gTree); @@ -43,6 +44,13 @@ public class GTreeStartEditingTask extends GTreeTask { this.childName = childName; } + public GTreeStartEditingTask(GTree gTree, JTree jTree, GTreeNode editNode) { + super(gTree); + this.parent = editNode.getParent(); + this.childName = editNode.getName(); + this.editNode = editNode; + } + @Override public void run(final TaskMonitor monitor) throws CancelledException { runOnSwingThread(() -> { @@ -66,10 +74,12 @@ public class GTreeStartEditingTask extends GTreeTask { return; } - GTreeNode editNode = parent.getChild(childName); if (editNode == null) { - Msg.debug(this, "Can't find node \"" + childName + "\" to edit."); - return; + editNode = parent.getChild(childName); + if (editNode == null) { + Msg.debug(this, "Can't find node \"" + childName + "\" to edit."); + return; + } } TreePath path = editNode.getTreePath(); diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataRenameAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataRenameAction.java index 2544f91588..df7382e344 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataRenameAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataRenameAction.java @@ -66,7 +66,7 @@ public class ProjectDataRenameAction extends FrontendProjectTreeAction { DataTree tree = (DataTree) component; GTreeNode node = (GTreeNode) context.getContextObject(); tree.setEditable(true); - tree.startEditing(node.getParent(), node.getName()); + tree.startEditing(node); } else if (component instanceof GTable) { GTable table = (GTable) component;