Merge remote-tracking branch 'origin/GP-4134_Dan_modelTreeReload--SQUASHED'

This commit is contained in:
Ryan Kurtz 2023-12-18 11:33:11 -05:00
commit aec8641320
3 changed files with 75 additions and 10 deletions

View File

@ -30,6 +30,7 @@ import ghidra.trace.model.*;
import ghidra.trace.model.Trace.TraceObjectChangeType; import ghidra.trace.model.Trace.TraceObjectChangeType;
import ghidra.trace.model.target.*; import ghidra.trace.model.target.*;
import ghidra.util.HTMLUtilities; import ghidra.util.HTMLUtilities;
import ghidra.util.LockHold;
import ghidra.util.datastruct.WeakValueHashMap; import ghidra.util.datastruct.WeakValueHashMap;
import utilities.util.IDKeyed; import utilities.util.IDKeyed;
@ -51,7 +52,7 @@ public class ObjectTreeModel implements DisplaysModified {
} }
public void domainObjectRestored(DomainObjectChangeRecord rec) { public void domainObjectRestored(DomainObjectChangeRecord rec) {
reload(); reloadSameTrace();
} }
protected boolean isEventValue(TraceObjectValue value) { protected boolean isEventValue(TraceObjectValue value) {
@ -167,7 +168,7 @@ public class ObjectTreeModel implements DisplaysModified {
} }
AbstractNode node = AbstractNode node =
byValue.computeIfAbsent(new IDKeyed<>(value), k -> createNode(value)); byValue.computeIfAbsent(new IDKeyed<>(value), k -> createNode(value));
node.unloadChildren(); //node.unloadChildren();
//AbstractNode node = createNode(value); //AbstractNode node = createNode(value);
if (value.isCanonical()) { if (value.isCanonical()) {
byObject.put(new IDKeyed<>(value.getChild()), node); byObject.put(new IDKeyed<>(value.getChild()), node);
@ -204,6 +205,18 @@ public class ObjectTreeModel implements DisplaysModified {
addNode(i, node); addNode(i, node);
} }
@Override
public void dispose() {
/**
* Our nodes are re-usable. They're cached so that as an item comes and goes, its
* corresponding node can also come and go without being re-instantiated each time.
* Furthermore, it's like to have all the same children as before, too. For now, we'll
* just ignore dispose. If there's too many unexpected behaviors resulting from this,
* then perhaps we should just have dispose also remove itself from the node cache.
*/
// DO NOTHING
}
@Override @Override
public int compareTo(GTreeNode node) { public int compareTo(GTreeNode node) {
return TargetObjectKeyComparator.CHILD.compare(this.getName(), node.getName()); return TargetObjectKeyComparator.CHILD.compare(this.getName(), node.getName());
@ -211,7 +224,7 @@ public class ObjectTreeModel implements DisplaysModified {
@Override @Override
public String getName() { public String getName() {
return getValue().getEntryKey() + "\n" + getValue().getMinSnap(); return getValue().getEntryKey() + "@" + getValue().getMinSnap();
} }
@Override @Override
@ -260,6 +273,50 @@ public class ObjectTreeModel implements DisplaysModified {
protected boolean isModified() { protected boolean isModified() {
return isValueModified(getValue()); return isValueModified(getValue());
} }
protected synchronized void reloadChildrenNow() {
if (!isLoaded()) {
return;
}
// Use a merge to effect the minimal changes to set the children
var current = List.copyOf(children());
var generated = generateChildren();
// NB. The two lists ought to be sorted already.
int ic = 0;
int ig = 0;
int diff = 0;
while (ic < current.size() && ig < generated.size()) {
GTreeNode nc = current.get(ic);
GTreeNode ng = generated.get(ig);
int comp = nc.compareTo(ng);
if (comp == 0) {
ic++;
ig++;
}
else if (comp < 0) {
removeNode(nc);
diff--;
ic++;
}
else { // comp > 0
addNode(ic + diff, ng);
diff++;
ig++;
}
}
while (ic < current.size()) {
GTreeNode nc = current.get(ic);
removeNode(nc);
// diff--; // Not really needed
ic++;
}
while (ig < generated.size()) {
GTreeNode ng = generated.get(ig);
addNode(ic + diff, ng);
diff++;
ig++;
}
}
} }
class RootNode extends AbstractNode { class RootNode extends AbstractNode {
@ -670,6 +727,15 @@ public class ObjectTreeModel implements DisplaysModified {
root.unloadChildren(); root.unloadChildren();
} }
protected void reloadSameTrace() {
try (LockHold hold = trace == null ? null : trace.lockRead()) {
for (AbstractNode node : List.copyOf(nodeCache.byObject.values())) {
node.reloadChildrenNow();
}
root.reloadChildrenNow();
}
}
public void setTrace(Trace trace) { public void setTrace(Trace trace) {
if (this.trace == trace) { if (this.trace == trace) {
return; return;
@ -761,7 +827,7 @@ public class ObjectTreeModel implements DisplaysModified {
} }
protected void spanChanged() { protected void spanChanged() {
reload(); reloadSameTrace();
} }
public void setSpan(Lifespan span) { public void setSpan(Lifespan span) {
@ -777,7 +843,7 @@ public class ObjectTreeModel implements DisplaysModified {
} }
protected void showHiddenChanged() { protected void showHiddenChanged() {
reload(); reloadSameTrace();
} }
public void setShowHidden(boolean showHidden) { public void setShowHidden(boolean showHidden) {
@ -793,7 +859,7 @@ public class ObjectTreeModel implements DisplaysModified {
} }
protected void showPrimitivesChanged() { protected void showPrimitivesChanged() {
reload(); reloadSameTrace();
} }
public void setShowPrimitives(boolean showPrimitives) { public void setShowPrimitives(boolean showPrimitives) {
@ -809,7 +875,7 @@ public class ObjectTreeModel implements DisplaysModified {
} }
protected void showMethodsChanged() { protected void showMethodsChanged() {
reload(); reloadSameTrace();
} }
public void setShowMethods(boolean showMethods) { public void setShowMethods(boolean showMethods) {

View File

@ -153,7 +153,7 @@ public class ObjectsTreePanel extends JPanel {
if (limitToSnap) { if (limitToSnap) {
treeModel.setSpan(Lifespan.at(current.getSnap())); treeModel.setSpan(Lifespan.at(current.getSnap()));
} }
tree.filterChanged(); //tree.filterChanged();
// Repaint for bold current path is already going to happen // Repaint for bold current path is already going to happen
} }
} }
@ -299,7 +299,6 @@ public class ObjectsTreePanel extends JPanel {
} }
} }
public void setSelectedObject(TraceObject object) { public void setSelectedObject(TraceObject object) {
if (object == null) { if (object == null) {
tree.clearSelectionPaths(); tree.clearSelectionPaths();

View File

@ -410,7 +410,7 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
GTree tree = modelProvider.objectsTreePanel.tree; GTree tree = modelProvider.objectsTreePanel.tree;
GTreeNode node = waitForPass(() -> { GTreeNode node = waitForPass(() -> {
GTreeNode n = Unique.assertOne(tree.getSelectedNodes()); GTreeNode n = Unique.assertOne(tree.getSelectedNodes());
assertEquals("Processes\n0", n.getName()); assertEquals("Processes@0", n.getName());
return n; return n;
}); });
clickTreeNode(tree, node, MouseEvent.BUTTON1); clickTreeNode(tree, node, MouseEvent.BUTTON1);