GP-4134: Less abreasive refreshing of the Model tree.

This commit is contained in:
Dan 2023-12-18 11:15:57 -05:00
parent 804fb5ec17
commit e7fcf5f24a
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.target.*;
import ghidra.util.HTMLUtilities;
import ghidra.util.LockHold;
import ghidra.util.datastruct.WeakValueHashMap;
import utilities.util.IDKeyed;
@ -51,7 +52,7 @@ public class ObjectTreeModel implements DisplaysModified {
}
public void domainObjectRestored(DomainObjectChangeRecord rec) {
reload();
reloadSameTrace();
}
protected boolean isEventValue(TraceObjectValue value) {
@ -167,7 +168,7 @@ public class ObjectTreeModel implements DisplaysModified {
}
AbstractNode node =
byValue.computeIfAbsent(new IDKeyed<>(value), k -> createNode(value));
node.unloadChildren();
//node.unloadChildren();
//AbstractNode node = createNode(value);
if (value.isCanonical()) {
byObject.put(new IDKeyed<>(value.getChild()), node);
@ -204,6 +205,18 @@ public class ObjectTreeModel implements DisplaysModified {
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
public int compareTo(GTreeNode node) {
return TargetObjectKeyComparator.CHILD.compare(this.getName(), node.getName());
@ -211,7 +224,7 @@ public class ObjectTreeModel implements DisplaysModified {
@Override
public String getName() {
return getValue().getEntryKey() + "\n" + getValue().getMinSnap();
return getValue().getEntryKey() + "@" + getValue().getMinSnap();
}
@Override
@ -260,6 +273,50 @@ public class ObjectTreeModel implements DisplaysModified {
protected boolean isModified() {
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 {
@ -670,6 +727,15 @@ public class ObjectTreeModel implements DisplaysModified {
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) {
if (this.trace == trace) {
return;
@ -761,7 +827,7 @@ public class ObjectTreeModel implements DisplaysModified {
}
protected void spanChanged() {
reload();
reloadSameTrace();
}
public void setSpan(Lifespan span) {
@ -777,7 +843,7 @@ public class ObjectTreeModel implements DisplaysModified {
}
protected void showHiddenChanged() {
reload();
reloadSameTrace();
}
public void setShowHidden(boolean showHidden) {
@ -793,7 +859,7 @@ public class ObjectTreeModel implements DisplaysModified {
}
protected void showPrimitivesChanged() {
reload();
reloadSameTrace();
}
public void setShowPrimitives(boolean showPrimitives) {
@ -809,7 +875,7 @@ public class ObjectTreeModel implements DisplaysModified {
}
protected void showMethodsChanged() {
reload();
reloadSameTrace();
}
public void setShowMethods(boolean showMethods) {

View File

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

View File

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