GT-3457 - GTree Edit Fix - fixed bug that would cause new namespace tree

nodes to not be in edit mode as intended
This commit is contained in:
dragonmacher 2020-01-17 14:27:13 -05:00
parent cf0c434d51
commit bd362d9cf6
11 changed files with 357 additions and 92 deletions

View file

@ -27,6 +27,7 @@ import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BooleanSupplier;
import javax.swing.*;
import javax.swing.Timer;
@ -44,6 +45,7 @@ import docking.widgets.tree.internal.*;
import docking.widgets.tree.support.*;
import docking.widgets.tree.support.GTreeSelectionEvent.EventOrigin;
import docking.widgets.tree.tasks.*;
import generic.timer.ExpiringSwingTimer;
import ghidra.util.*;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException;
@ -978,23 +980,45 @@ public class GTree extends JPanel implements BusyListener {
}
public void addGTModelListener(TreeModelListener listener) {
tree.getModel().addTreeModelListener(listener);
model.addTreeModelListener(listener);
}
public void removeGTModelListener(TreeModelListener listener) {
tree.getModel().removeTreeModelListener(listener);
model.removeTreeModelListener(listener);
}
public void setEditable(boolean editable) {
tree.setEditable(editable);
}
public void startEditing(final GTreeNode parent, final String childName) {
/**
* Requests that the node with the given name, in the given parent, be edited. <b>This
* operation (as with many others on this tree) is asynchronous.</b> 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
*/
public void startEditing(GTreeNode parent, final String childName) {
// 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(parent);
runTask(new GTreeStartEditingTask(GTree.this, tree, parent, childName));
//
// The request to edit the node may be for a node that has not yet been added to this
// tree. Further, some clients will buffer events, which means that the node the client
// wishes to edit may not yet be in the parent node even if we run this request later on
// the Swing thread. To deal with this, we use a construct that will run our request
// once the given node has been added to the parent.
//
BooleanSupplier isReady = () -> parent.getChild(childName) != null;
int expireMs = 3000;
ExpiringSwingTimer.runWhen(isReady, expireMs, () -> {
runTask(new GTreeStartEditingTask(GTree.this, tree, parent, childName));
});
}
@Override

View file

@ -28,6 +28,7 @@ import docking.widgets.tree.*;
import ghidra.util.Msg;
import ghidra.util.SystemUtilities;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import util.CollectionUtils;
@ -43,7 +44,7 @@ public class GTreeStartEditingTask extends GTreeTask {
}
@Override
public void run(final TaskMonitor monitor) {
public void run(final TaskMonitor monitor) throws CancelledException {
runOnSwingThread(() -> {
if (monitor.isCancelled()) {
return; // we can be cancelled while waiting for Swing to run us
@ -58,18 +59,21 @@ public class GTreeStartEditingTask extends GTreeTask {
}
private void edit() {
final GTreeNode child = parent.getChild(childName);
if (child == null) {
GTreeNode editNode = parent.getChild(childName);
if (editNode == null) {
if (tree.isFiltered()) {
Msg.showWarn(getClass(), tree, "Cannot Edit Tree Node",
"Cannot edit tree node \"" + childName + "\" while tree is filtered.");
"Can't edit tree node \"" + childName + "\" while tree is filtered.");
}
else {
Msg.debug(this,
"Can't find node \"" + childName + "\" to edit.");
}
Msg.debug(this,
"Can't find node for \"" + childName + "\". Perhaps it is filtered out?");
return;
}
TreePath path = child.getTreePath();
TreePath path = editNode.getTreePath();
final Set<GTreeNode> childrenBeforeEdit = new HashSet<>(parent.getChildren());
final CellEditor cellEditor = tree.getCellEditor();
@ -95,7 +99,7 @@ public class GTreeStartEditingTask extends GTreeTask {
* has finished and been applied.
*/
private void reselectNode() {
String newName = child.getName();
String newName = editNode.getName();
GTreeNode newChild = parent.getChild(newName);
if (newChild == null) {
throw new AssertException("Unable to find new node by name: " + newName);
@ -140,7 +144,7 @@ public class GTreeStartEditingTask extends GTreeTask {
}
});
tree.setNodeEditable(child);
tree.setNodeEditable(editNode);
jTree.startEditingAtPath(path);
}