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 a320657d0b..12af16ef05 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 @@ -276,7 +276,7 @@ public class GTree extends JPanel implements BusyListener { updateModelFilter(); } - public void ignoreFilter(GTreeNode node) { + private void ignoreFilter(GTreeNode node) { if (!isFiltered()) { return; } @@ -1094,8 +1094,8 @@ public class GTree extends JPanel implements BusyListener { // once the given node has been added to the parent. // GTreeNode modelParent = getModelNode(parent); - forceNewNodeIntoView(modelParent, childName, newViewNode -> { - runTask(new GTreeStartEditingTask(GTree.this, tree, newViewNode)); + forceNewNodeIntoView(modelParent, childName, viewNode -> { + runTask(new GTreeStartEditingTask(GTree.this, tree, viewNode)); }); } @@ -1111,7 +1111,14 @@ public class GTree extends JPanel implements BusyListener { // which must be loaded before we can edit expandPath(child.getParent()); - runTask(new GTreeStartEditingTask(GTree.this, tree, child)); + // force the filter to accept the new node + ignoreFilter(child); + + // Wait for the view to update from any filtering that may take place + GTreeNode modelParent = getModelNode(child.getParent()); + getViewNode(modelParent, child.getName(), viewNode -> { + runTask(new GTreeStartEditingTask(GTree.this, tree, viewNode)); + }); } @Override diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectTreeContext.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectTreeContext.java index d3660aac35..3d9aca35cb 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectTreeContext.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectTreeContext.java @@ -19,12 +19,13 @@ import java.util.List; import javax.swing.tree.TreePath; +import docking.widgets.tree.GTreeNode; import ghidra.framework.main.datatree.*; import ghidra.framework.model.DomainFile; import ghidra.framework.model.DomainFolder; /** - * Common methods appropriate for both the {@link FrontEndProjectTreeContext} and the + * Common methods appropriate for both the {@link FrontEndProjectTreeContext} and the * {@link DialogProjectTreeContext}. The project tree actions require that the contexts be * separate even though they need many of the same methods. By extracting the methods to this * interface, the contexts can be kept separate, but can share action code. @@ -67,4 +68,9 @@ public interface ProjectTreeContext { */ public TreePath[] getSelectionPaths(); + /** + * Returns the node that represents the context object for this context + * @return the node + */ + public GTreeNode getContextNode(); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DialogProjectTreeContext.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DialogProjectTreeContext.java index b82a507581..8b53e360b9 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DialogProjectTreeContext.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DialogProjectTreeContext.java @@ -21,6 +21,7 @@ import java.util.List; import javax.swing.tree.TreePath; import docking.ActionContext; +import docking.widgets.tree.GTreeNode; import ghidra.framework.main.datatable.ProjectTreeContext; import ghidra.framework.model.*; @@ -93,4 +94,8 @@ public class DialogProjectTreeContext extends ActionContext implements ProjectTr return selectedFiles.size(); } + @Override + public GTreeNode getContextNode() { + return (GTreeNode) super.getContextObject(); + } } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/FrontEndProjectTreeContext.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/FrontEndProjectTreeContext.java index 8a6346521a..e9dd44660b 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/FrontEndProjectTreeContext.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/FrontEndProjectTreeContext.java @@ -20,6 +20,7 @@ import java.util.List; import javax.swing.tree.TreePath; import docking.ComponentProvider; +import docking.widgets.tree.GTreeNode; import ghidra.framework.main.datatable.ProjectDataContext; import ghidra.framework.main.datatable.ProjectTreeContext; import ghidra.framework.model.*; @@ -56,4 +57,9 @@ public class FrontEndProjectTreeContext extends ProjectDataContext public DataTree getTree() { return tree; } + + @Override + public GTreeNode getContextNode() { + return (GTreeNode) super.getContextObject(); + } } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataNewFolderAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataNewFolderAction.java index cc60f5817c..657e4ea745 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataNewFolderAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataNewFolderAction.java @@ -16,8 +16,6 @@ package ghidra.framework.main.projectdata.actions; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; import javax.swing.Icon; @@ -26,10 +24,10 @@ import docking.action.MenuData; import docking.widgets.tree.GTreeNode; import ghidra.framework.main.datatable.ProjectTreeContext; import ghidra.framework.main.datatree.DataTree; +import ghidra.framework.main.datatree.DomainFileNode; import ghidra.framework.model.DomainFile; import ghidra.framework.model.DomainFolder; import ghidra.util.InvalidNameException; -import ghidra.util.Swing; import ghidra.util.exception.AssertException; import resources.ResourceManager; @@ -54,25 +52,14 @@ public class ProjectDataNewFolderAction return (context.getFolderCount() + context.getFileCount()) == 1; } - /** - * Create a new folder for the selected node that represents - * a folder. - */ private void createNewFolder(T context) { + DomainFolder parentFolder = getFolder(context); - DomainFolder newFolder = createNewFolderWithDefaultName(parentFolder); + GTreeNode parent = getParentNode(context); DataTree tree = context.getTree(); - - Swing.runLater(() -> { - GTreeNode node = findNodeForFolder(tree, newFolder); - if (node != null) { - tree.ignoreFilter(node); - tree.setEditable(true); - tree.startEditing(node); - } - }); - + tree.setEditable(true); + tree.startEditing(parent, newFolder.getName()); } private DomainFolder createNewFolderWithDefaultName(DomainFolder parentFolder) { @@ -85,30 +72,6 @@ public class ProjectDataNewFolderAction } } - /** - * Get folder path as list with top-level folder being first in the list. - * Root folder is not included in list. - * @param folder - * @param folderPathList folder path list - */ - private static final void getFolderPath(DomainFolder folder, List folderPathList) { - if (folder.getParent() != null) { - // don't recurse if we are the root, don't add our 'name' to the list - getFolderPath(folder.getParent(), folderPathList); - folderPathList.add(folder.getName()); - } - } - - private GTreeNode findNodeForFolder(DataTree tree, DomainFolder newFolder) { - List folderPathList = new ArrayList<>(); - getFolderPath(newFolder, folderPathList); - GTreeNode node = tree.getModelRoot(); - for (int i = 0; node != null && i < folderPathList.size(); i++) { - node = node.getChild(folderPathList.get(i)); - } - return node; - } - private String getNewFolderName(DomainFolder parent) { String baseName = "NewFolder"; String name = baseName; @@ -130,4 +93,12 @@ public class ProjectDataNewFolderAction return file.getParent(); } + private GTreeNode getParentNode(T context) { + + GTreeNode node = context.getContextNode(); + if (node instanceof DomainFileNode) { + return ((DomainFileNode) node).getParent(); + } + return node; + } }