GP-4295: Fix plot column range. Prohibit nav to future.

This commit is contained in:
Dan 2024-02-15 14:35:37 -05:00
parent 0820d96ec4
commit 9cc9659817
7 changed files with 99 additions and 6 deletions

View file

@ -48,6 +48,7 @@ public abstract class AbstractQueryTableModel<T> extends ThreadedTableModel<T, T
} }
protected void objectRestored(DomainObjectChangeRecord record) { protected void objectRestored(DomainObjectChangeRecord record) {
AbstractQueryTableModel.this.maxSnapChanged();
reload(); reload();
} }

View file

@ -273,9 +273,14 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
private final SeekListener seekListener = pos -> { private final SeekListener seekListener = pos -> {
long snap = Math.round(pos); long snap = Math.round(pos);
if (current.getTrace() == null || snap < 0) { if (snap < 0) {
snap = 0; snap = 0;
} }
long max =
current.getTrace() == null ? 0 : current.getTrace().getTimeManager().getMaxSnap();
if (snap > max) {
snap = max;
}
traceManager.activateSnap(snap); traceManager.activateSnap(snap);
}; };

View file

@ -17,6 +17,7 @@ package ghidra.app.plugin.core.debug.gui.model.columns;
import docking.widgets.table.*; import docking.widgets.table.*;
import docking.widgets.table.RangeCursorTableHeaderRenderer.SeekListener; import docking.widgets.table.RangeCursorTableHeaderRenderer.SeekListener;
import generic.Span;
import generic.Span.SpanSet; import generic.Span.SpanSet;
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueRow; import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueRow;
import ghidra.docking.settings.Settings; import ghidra.docking.settings.Settings;
@ -59,6 +60,10 @@ public class TraceValueLifePlotColumn
headerRenderer.setFullRange(fullRange); headerRenderer.setFullRange(fullRange);
} }
public Span<Long, ?> getFullRange() {
return cellRenderer.getFullRange();
}
public void setSnap(long snap) { public void setSnap(long snap) {
headerRenderer.setCursorPosition(snap); headerRenderer.setCursorPosition(snap);
} }

View file

@ -274,9 +274,14 @@ public class DebuggerLegacyThreadsPanel extends JPanel {
headerRenderer.addSeekListener(seekListener = pos -> { headerRenderer.addSeekListener(seekListener = pos -> {
long snap = Math.round(pos); long snap = Math.round(pos);
if (current.getTrace() == null || snap < 0) { if (snap < 0) {
snap = 0; snap = 0;
} }
long max =
current.getTrace() == null ? 0 : current.getTrace().getTimeManager().getMaxSnap();
if (snap > max) {
snap = max;
}
traceManager.activateSnap(snap); traceManager.activateSnap(snap);
myActionContext = new DebuggerSnapActionContext(current.getTrace(), snap); myActionContext = new DebuggerSnapActionContext(current.getTrace(), snap);
provider.legacyThreadsPanelContextChanged(); provider.legacyThreadsPanelContextChanged();

View file

@ -170,9 +170,14 @@ public class DebuggerThreadsPanel extends AbstractObjectsTableBasedPanel<TraceOb
private final SeekListener seekListener = pos -> { private final SeekListener seekListener = pos -> {
long snap = Math.round(pos); long snap = Math.round(pos);
if (current.getTrace() == null || snap < 0) { if (snap < 0) {
snap = 0; snap = 0;
} }
long max =
current.getTrace() == null ? 0 : current.getTrace().getTimeManager().getMaxSnap();
if (snap > max) {
snap = max;
}
traceManager.activateSnap(snap); traceManager.activateSnap(snap);
}; };

View file

@ -19,7 +19,7 @@ import static org.junit.Assert.*;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.*;
import org.jdom.JDOMException; import org.jdom.JDOMException;
import org.junit.*; import org.junit.*;
@ -36,6 +36,7 @@ import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.PrimitiveRow;
import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueRow; import ghidra.app.plugin.core.debug.gui.model.ObjectTableModel.ValueRow;
import ghidra.app.plugin.core.debug.gui.model.ObjectTreeModel.AbstractNode; import ghidra.app.plugin.core.debug.gui.model.ObjectTreeModel.AbstractNode;
import ghidra.app.plugin.core.debug.gui.model.PathTableModel.PathRow; import ghidra.app.plugin.core.debug.gui.model.PathTableModel.PathRow;
import ghidra.app.plugin.core.debug.gui.model.columns.TraceValueLifePlotColumn;
import ghidra.app.plugin.core.debug.gui.model.columns.TraceValueValColumn; import ghidra.app.plugin.core.debug.gui.model.columns.TraceValueValColumn;
import ghidra.dbg.target.TargetEventScope; import ghidra.dbg.target.TargetEventScope;
import ghidra.dbg.target.TargetObject; import ghidra.dbg.target.TargetObject;
@ -1162,4 +1163,75 @@ public class DebuggerModelProviderTest extends AbstractGhidraHeadedDebuggerTest
waitForPass(() -> assertEquals(14, waitForPass(() -> assertEquals(14,
modelProvider.elementsTablePanel.tableModel.getModelData().size())); modelProvider.elementsTablePanel.tableModel.getModelData().size()));
} }
protected Stream<DynamicTableColumn<?, ?, ?>> streamColumns(
GDynamicColumnTableModel<?, ?> model) {
return IntStream.range(0, model.getColumnCount()).mapToObj(model::getColumn);
}
protected <T extends DynamicTableColumn<?, ?, ?>> T findColumnOfType(
GDynamicColumnTableModel<?, ?> model, Class<T> type) {
return streamColumns(model)
.flatMap(c -> type.isInstance(c) ? Stream.of(type.cast(c)) : Stream.of())
.findAny()
.orElse(null);
}
@Test
public void testLifePlotColumnFitsSnapshotsOnActivate() throws Throwable {
TraceValueLifePlotColumn plotCol = findColumnOfType(
modelProvider.elementsTablePanel.tableModel, TraceValueLifePlotColumn.class);
createTraceAndPopulateObjects();
traceManager.activateTrace(tb.trace);
waitForSwing();
// NB. The plot adds a margin of 1
assertEquals(Lifespan.span(0, 21), plotCol.getFullRange());
}
@Test
public void testLifePlotColumnFitsSnapshotsOnAddSnapshot() throws Throwable {
TraceValueLifePlotColumn plotCol = findColumnOfType(
modelProvider.elementsTablePanel.tableModel, TraceValueLifePlotColumn.class);
createTraceAndPopulateObjects();
traceManager.activateTrace(tb.trace);
waitForSwing();
try (Transaction tx = tb.startTransaction()) {
tb.trace.getTimeManager().getSnapshot(30, true);
}
waitForDomainObject(tb.trace);
// NB. The plot adds a margin of 1
assertEquals(Lifespan.span(0, 31), plotCol.getFullRange());
try (Transaction tx = tb.startTransaction()) {
tb.trace.getTimeManager().getSnapshot(31, true);
}
waitForDomainObject(tb.trace);
assertEquals(Lifespan.span(0, 32), plotCol.getFullRange());
}
@Test
public void testLifePlotColumnFitsSnapshotsOnAddSnapshotSupressEvents() throws Throwable {
TraceValueLifePlotColumn plotCol = findColumnOfType(
modelProvider.elementsTablePanel.tableModel, TraceValueLifePlotColumn.class);
createTraceAndPopulateObjects();
traceManager.activateTrace(tb.trace);
waitForSwing();
tb.trace.setEventsEnabled(false);
try (Transaction tx = tb.startTransaction()) {
tb.trace.getTimeManager().getSnapshot(30, true);
}
tb.trace.setEventsEnabled(true);
waitForDomainObject(tb.trace);
// NB. The plot adds a margin of 1
assertEquals(Lifespan.span(0, 31), plotCol.getFullRange());
}
} }

View file

@ -42,8 +42,8 @@ public class RangeCursorTableHeaderRenderer<N extends Number & Comparable<N>>
if ((e.getButton() != MouseEvent.BUTTON1)) { if ((e.getButton() != MouseEvent.BUTTON1)) {
return; return;
} }
doSeek(e);
e.consume(); e.consume();
doSeek(e);
} }
@Override @Override
@ -53,8 +53,8 @@ public class RangeCursorTableHeaderRenderer<N extends Number & Comparable<N>>
if ((e.getModifiersEx() & (onmask | offmask)) != onmask) { if ((e.getModifiersEx() & (onmask | offmask)) != onmask) {
return; return;
} }
doSeek(e);
e.consume(); e.consume();
doSeek(e);
} }
protected void doSeek(MouseEvent e) { protected void doSeek(MouseEvent e) {