mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-04-25 17:25:17 +02:00
GP-6607: Port Snapshot Table to the (background) Threaded impl.
This commit is contained in:
@@ -25,7 +25,6 @@ import javax.swing.*;
|
||||
import docking.ReusableDialogComponentProvider;
|
||||
import docking.widgets.table.*;
|
||||
import docking.widgets.table.ColumnSortState.SortDirection;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import ghidra.app.services.DebuggerStaticMappingService;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
@@ -29,7 +29,6 @@ import docking.action.*;
|
||||
import docking.action.builder.ActionBuilder;
|
||||
import docking.menu.MultiActionDockingAction;
|
||||
import docking.widgets.table.*;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import ghidra.app.context.ProgramLocationActionContext;
|
||||
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
|
||||
@@ -36,7 +36,7 @@ import docking.action.*;
|
||||
import docking.actions.PopupActionProvider;
|
||||
import docking.widgets.table.ColumnSortState.SortDirection;
|
||||
import docking.widgets.table.CustomToStringCellRenderer;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import docking.widgets.table.EnumeratedTableColumn;
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
|
||||
@@ -29,7 +29,6 @@ import javax.swing.table.TableCellEditor;
|
||||
import db.Transaction;
|
||||
import docking.ReusableDialogComponentProvider;
|
||||
import docking.widgets.table.*;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.app.plugin.core.debug.gui.copying.DebuggerCopyPlan.Copier;
|
||||
import ghidra.app.services.*;
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.util.function.Function;
|
||||
import javax.swing.table.TableCellEditor;
|
||||
|
||||
import docking.widgets.table.*;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractDebuggerMapProposalDialog;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.debug.api.modules.RegionMapProposal.RegionMapEntry;
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.util.function.Function;
|
||||
import javax.swing.table.TableCellEditor;
|
||||
|
||||
import docking.widgets.table.*;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractDebuggerMapProposalDialog;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.debug.api.modules.ModuleMapProposal.ModuleMapEntry;
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.util.function.Function;
|
||||
import javax.swing.table.*;
|
||||
|
||||
import docking.widgets.table.*;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractDebuggerMapProposalDialog;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.debug.api.modules.SectionMapProposal.SectionMapEntry;
|
||||
|
||||
@@ -30,7 +30,6 @@ import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.widgets.table.*;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerProvider;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
@@ -132,7 +131,7 @@ public class DebuggerStaticMappingProvider extends ComponentProviderAdapter
|
||||
}
|
||||
}
|
||||
|
||||
protected static class MappingTableModel extends DebouncedRowWrappedEnumeratedColumnTableModel< //
|
||||
protected static class MappingTableModel extends DebouncedRowWrappedEnumeratedColumnTableModel<
|
||||
StaticMappingTableColumns, ObjectKey, StaticMappingRow, TraceStaticMapping> {
|
||||
|
||||
public MappingTableModel(PluginTool tool) {
|
||||
|
||||
@@ -31,7 +31,6 @@ import javax.swing.table.*;
|
||||
import db.Transaction;
|
||||
import docking.action.DockingAction;
|
||||
import docking.widgets.table.*;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import generic.theme.GColor;
|
||||
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
|
||||
@@ -26,7 +26,6 @@ import javax.swing.*;
|
||||
import docking.DialogComponentProvider;
|
||||
import docking.widgets.table.*;
|
||||
import docking.widgets.table.ColumnSortState.SortDirection;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.app.plugin.core.debug.mapping.DebuggerPlatformOffer;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
|
||||
@@ -26,9 +26,7 @@ import javax.swing.*;
|
||||
import docking.ActionContext;
|
||||
import docking.ReusableDialogComponentProvider;
|
||||
import docking.action.DockingAction;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import docking.widgets.table.GTable;
|
||||
import docking.widgets.table.*;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.lang.Language;
|
||||
|
||||
@@ -38,7 +38,6 @@ import docking.actions.PopupActionProvider;
|
||||
import docking.widgets.AbstractGCellRenderer;
|
||||
import docking.widgets.table.*;
|
||||
import docking.widgets.table.ColumnSortState.SortDirection;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import generic.theme.GColor;
|
||||
import ghidra.app.plugin.core.data.DataSettingsDialog;
|
||||
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
||||
|
||||
@@ -16,31 +16,24 @@
|
||||
package ghidra.app.plugin.core.debug.gui.time;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.widgets.table.*;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import docking.widgets.table.threaded.GThreadedTablePanel;
|
||||
import generic.theme.GColor;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.framework.model.DomainObjectEvent;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.TraceDomainObjectListener;
|
||||
import ghidra.trace.model.target.TraceObjectValue;
|
||||
import ghidra.trace.model.target.path.KeyPath;
|
||||
import ghidra.trace.model.time.TraceSnapshot;
|
||||
import ghidra.trace.model.time.TraceTimeManager;
|
||||
import ghidra.trace.model.time.schedule.TraceSchedule;
|
||||
import ghidra.trace.model.time.schedule.TraceSchedule.TimeRadix;
|
||||
import ghidra.trace.util.TraceEvents;
|
||||
import ghidra.util.DateUtils;
|
||||
import ghidra.util.table.GhidraTableFilterPanel;
|
||||
import ghidra.util.table.column.AbstractGColumnRenderer;
|
||||
@@ -178,77 +171,6 @@ public class DebuggerSnapshotTablePanel extends JPanel {
|
||||
}
|
||||
}
|
||||
|
||||
protected class SnapshotTableModel
|
||||
extends DefaultEnumeratedColumnTableModel<SnapshotTableColumns, SnapshotRow> {
|
||||
public SnapshotTableModel(PluginTool tool) {
|
||||
super(tool, "Snapshots", SnapshotTableColumns.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SnapshotTableColumns> defaultSortOrder() {
|
||||
return List.of(SnapshotTableColumns.TIME);
|
||||
}
|
||||
|
||||
Trace getTrace() {
|
||||
return currentTrace;
|
||||
}
|
||||
|
||||
DebuggerCoordinates getCurrent() {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
private class SnapshotListener extends TraceDomainObjectListener {
|
||||
public SnapshotListener() {
|
||||
listenForUntyped(DomainObjectEvent.RESTORED, e -> objectRestored());
|
||||
|
||||
listenFor(TraceEvents.SNAPSHOT_ADDED, this::snapAdded);
|
||||
listenFor(TraceEvents.SNAPSHOT_CHANGED, this::snapChanged);
|
||||
listenFor(TraceEvents.SNAPSHOT_DELETED, this::snapDeleted);
|
||||
|
||||
listenFor(TraceEvents.VALUE_CREATED, this::valueCreated);
|
||||
listenFor(TraceEvents.VALUE_DELETED, this::valueDeleted);
|
||||
}
|
||||
|
||||
private void objectRestored() {
|
||||
loadSnapshots();
|
||||
}
|
||||
|
||||
private void snapAdded(TraceSnapshot snapshot) {
|
||||
if (snapshot.getKey() < 0 && hideScratch) {
|
||||
return;
|
||||
}
|
||||
SnapshotRow row = new SnapshotRow(snapshot, tool);
|
||||
snapshotTableModel.add(row);
|
||||
}
|
||||
|
||||
private void snapChanged(TraceSnapshot snapshot) {
|
||||
if (snapshot.getKey() < 0 && hideScratch) {
|
||||
return;
|
||||
}
|
||||
snapshotTableModel.notifyUpdatedWith(row -> row.getSnapshot() == snapshot);
|
||||
}
|
||||
|
||||
private void snapDeleted(TraceSnapshot snapshot) {
|
||||
if (snapshot.getKey() < 0 && hideScratch) {
|
||||
return;
|
||||
}
|
||||
snapshotTableModel.deleteWith(row -> row.getSnapshot() == snapshot);
|
||||
}
|
||||
|
||||
private void valueCreated(TraceObjectValue value) {
|
||||
if (value.getCanonicalPath().equals(KeyPath.of(TraceTimeManager.KEY_TIME_RADIX))) {
|
||||
snapshotTableModel.fireTableDataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void valueDeleted(TraceObjectValue value) {
|
||||
if (value.getCanonicalPath().equals(KeyPath.of(TraceTimeManager.KEY_TIME_RADIX))) {
|
||||
snapshotTableModel.fireTableDataChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class StyleCurrentSnapRenderer extends AbstractGColumnRenderer<Object>
|
||||
implements GTableAccess {
|
||||
|
||||
@@ -363,102 +285,34 @@ public class DebuggerSnapshotTablePanel extends JPanel {
|
||||
|
||||
protected final PluginTool tool;
|
||||
protected final SnapshotTableModel snapshotTableModel;
|
||||
protected final GThreadedTablePanel<SnapshotRow> snapshotTablePanel;
|
||||
protected final GTable snapshotTable;
|
||||
protected final GhidraTableFilterPanel<SnapshotRow> snapshotFilterPanel;
|
||||
protected boolean hideScratch = false;
|
||||
|
||||
private Trace currentTrace;
|
||||
private volatile DebuggerCoordinates current = DebuggerCoordinates.NOWHERE;
|
||||
|
||||
protected final SnapshotListener listener = new SnapshotListener();
|
||||
|
||||
public DebuggerSnapshotTablePanel(PluginTool tool) {
|
||||
super(new BorderLayout());
|
||||
this.tool = tool;
|
||||
snapshotTableModel = new SnapshotTableModel(tool);
|
||||
snapshotTable = new GTable(snapshotTableModel);
|
||||
snapshotTablePanel = new GThreadedTablePanel<>(snapshotTableModel);
|
||||
snapshotTable = snapshotTablePanel.getTable();
|
||||
|
||||
snapshotTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
add(new JScrollPane(snapshotTable));
|
||||
add(snapshotTablePanel);
|
||||
|
||||
snapshotFilterPanel = new GhidraTableFilterPanel<>(snapshotTable, snapshotTableModel);
|
||||
add(snapshotFilterPanel, BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
private void addNewListeners() {
|
||||
if (currentTrace == null) {
|
||||
return;
|
||||
}
|
||||
currentTrace.addListener(listener);
|
||||
}
|
||||
|
||||
private void removeOldListeners() {
|
||||
if (currentTrace == null) {
|
||||
return;
|
||||
}
|
||||
currentTrace.removeListener(listener);
|
||||
}
|
||||
|
||||
public void setTrace(Trace trace) {
|
||||
if (currentTrace == trace) {
|
||||
return;
|
||||
}
|
||||
removeOldListeners();
|
||||
currentTrace = trace;
|
||||
addNewListeners();
|
||||
loadSnapshots();
|
||||
snapshotTableModel.setTrace(trace);
|
||||
}
|
||||
|
||||
public Trace getTrace() {
|
||||
return currentTrace;
|
||||
return snapshotTableModel.getTrace();
|
||||
}
|
||||
|
||||
public void setHideScratchSnapshots(boolean hideScratch) {
|
||||
if (this.hideScratch == hideScratch) {
|
||||
return;
|
||||
}
|
||||
this.hideScratch = hideScratch;
|
||||
if (hideScratch) {
|
||||
deleteScratchSnapshots();
|
||||
}
|
||||
else {
|
||||
loadScratchSnapshots();
|
||||
}
|
||||
}
|
||||
|
||||
protected void loadSnapshots() {
|
||||
snapshotTableModel.clear();
|
||||
if (currentTrace == null) {
|
||||
return;
|
||||
}
|
||||
TraceTimeManager manager = currentTrace.getTimeManager();
|
||||
|
||||
List<SnapshotRow> toAdd = new ArrayList<>();
|
||||
for (TraceSnapshot snapshot : hideScratch
|
||||
? manager.getSnapshots(0, true, Long.MAX_VALUE, true)
|
||||
: manager.getAllSnapshots()) {
|
||||
SnapshotRow row = new SnapshotRow(snapshot, tool);
|
||||
toAdd.add(row);
|
||||
if (current != DebuggerCoordinates.NOWHERE &&
|
||||
snapshot.getKey() == current.getViewSnap()) {
|
||||
}
|
||||
}
|
||||
snapshotTableModel.addAll(toAdd);
|
||||
}
|
||||
|
||||
protected void deleteScratchSnapshots() {
|
||||
snapshotTableModel.deleteWith(s -> s.getSnap() < 0);
|
||||
}
|
||||
|
||||
protected void loadScratchSnapshots() {
|
||||
if (currentTrace == null) {
|
||||
return;
|
||||
}
|
||||
TraceTimeManager manager = currentTrace.getTimeManager();
|
||||
Collection<? extends TraceSnapshot> sratch =
|
||||
manager.getSnapshots(Long.MIN_VALUE, true, 0, false);
|
||||
snapshotTableModel.addAll(sratch.stream()
|
||||
.map(s -> new SnapshotRow(s, tool))
|
||||
.collect(Collectors.toList()));
|
||||
snapshotTableModel.setHideScratch(hideScratch);
|
||||
}
|
||||
|
||||
public ListSelectionModel getSelectionModel() {
|
||||
@@ -471,9 +325,8 @@ public class DebuggerSnapshotTablePanel extends JPanel {
|
||||
}
|
||||
|
||||
public void setCurrent(DebuggerCoordinates coords) {
|
||||
assert coords.getTrace() == currentTrace;
|
||||
boolean fire = coords.getViewSnap() != current.getViewSnap();
|
||||
current = coords;
|
||||
boolean fire = coords.getViewSnap() != snapshotTableModel.getCurrent().getViewSnap();
|
||||
snapshotTableModel.setCurrent(coords);
|
||||
if (fire) {
|
||||
snapshotTable.repaint();
|
||||
}
|
||||
@@ -490,7 +343,13 @@ public class DebuggerSnapshotTablePanel extends JPanel {
|
||||
if (Objects.equals(curSnap, snap)) {
|
||||
return;
|
||||
}
|
||||
SnapshotRow row = snapshotTableModel.findFirst(r -> r.getSnap() == snap);
|
||||
|
||||
if (snapshotTableModel.getTrace() == null) {
|
||||
return;
|
||||
}
|
||||
TraceSnapshot snapshot =
|
||||
snapshotTableModel.getTrace().getTimeManager().getSnapshot(snap, false);
|
||||
SnapshotRow row = snapshotTableModel.rowMap.get(snapshot);
|
||||
if (row == null) {
|
||||
snapshotTable.clearSelection();
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.time;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import docking.widgets.table.ThreadedEnumeratedColumnTableModel;
|
||||
import ghidra.app.plugin.core.debug.gui.time.DebuggerSnapshotTablePanel.SnapshotTableColumns;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.framework.model.DomainObjectEvent;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.TraceDomainObjectListener;
|
||||
import ghidra.trace.model.target.TraceObjectValue;
|
||||
import ghidra.trace.model.target.path.KeyPath;
|
||||
import ghidra.trace.model.time.TraceSnapshot;
|
||||
import ghidra.trace.model.time.TraceTimeManager;
|
||||
import ghidra.trace.util.TraceEvents;
|
||||
import ghidra.util.datastruct.Accumulator;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
class SnapshotTableModel
|
||||
extends ThreadedEnumeratedColumnTableModel<SnapshotTableColumns, SnapshotRow> {
|
||||
|
||||
private class SnapshotListener extends TraceDomainObjectListener {
|
||||
public SnapshotListener() {
|
||||
listenForUntyped(DomainObjectEvent.RESTORED, e -> objectRestored());
|
||||
|
||||
listenFor(TraceEvents.SNAPSHOT_ADDED, this::snapAdded);
|
||||
listenFor(TraceEvents.SNAPSHOT_CHANGED, this::snapChanged);
|
||||
listenFor(TraceEvents.SNAPSHOT_DELETED, this::snapDeleted);
|
||||
|
||||
listenFor(TraceEvents.VALUE_CREATED, this::valueCreated);
|
||||
listenFor(TraceEvents.VALUE_DELETED, this::valueDeleted);
|
||||
}
|
||||
|
||||
private void objectRestored() {
|
||||
reload();
|
||||
}
|
||||
|
||||
private void snapAdded(TraceSnapshot snapshot) {
|
||||
addSnapshot(snapshot);
|
||||
}
|
||||
|
||||
private void snapChanged(TraceSnapshot snapshot) {
|
||||
updateSnapshot(snapshot);
|
||||
}
|
||||
|
||||
private void snapDeleted(TraceSnapshot snapshot) {
|
||||
removeSnapshot(snapshot);
|
||||
}
|
||||
|
||||
private void valueCreated(TraceObjectValue value) {
|
||||
if (value.getCanonicalPath().equals(KeyPath.of(TraceTimeManager.KEY_TIME_RADIX))) {
|
||||
fireTableDataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void valueDeleted(TraceObjectValue value) {
|
||||
if (value.getCanonicalPath().equals(KeyPath.of(TraceTimeManager.KEY_TIME_RADIX))) {
|
||||
fireTableDataChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final SnapshotListener listener = new SnapshotListener();
|
||||
protected final Map<TraceSnapshot, SnapshotRow> rowMap = new HashMap<>();
|
||||
|
||||
private volatile Trace currentTrace; // Because it gets set before current
|
||||
private volatile DebuggerCoordinates current = DebuggerCoordinates.NOWHERE;
|
||||
private boolean hideScratch;
|
||||
|
||||
public SnapshotTableModel(PluginTool tool) {
|
||||
super(tool, "Snapshots", SnapshotTableColumns.class, null, true);
|
||||
}
|
||||
|
||||
private void addNewListeners() {
|
||||
if (currentTrace == null) {
|
||||
return;
|
||||
}
|
||||
currentTrace.addListener(listener);
|
||||
}
|
||||
|
||||
private void removeOldListeners() {
|
||||
if (currentTrace == null) {
|
||||
return;
|
||||
}
|
||||
currentTrace.removeListener(listener);
|
||||
}
|
||||
|
||||
public void setTrace(Trace trace) {
|
||||
if (this.currentTrace == trace) {
|
||||
return;
|
||||
}
|
||||
removeOldListeners();
|
||||
this.currentTrace = trace;
|
||||
addNewListeners();
|
||||
|
||||
reload();
|
||||
}
|
||||
|
||||
public Trace getTrace() {
|
||||
return currentTrace;
|
||||
}
|
||||
|
||||
public void setCurrent(DebuggerCoordinates coords) {
|
||||
assert coords.getTrace() == currentTrace;
|
||||
this.current = coords;
|
||||
}
|
||||
|
||||
public DebuggerCoordinates getCurrent() {
|
||||
return current;
|
||||
}
|
||||
|
||||
public void setHideScratch(boolean hideScratch) {
|
||||
if (this.hideScratch == hideScratch) {
|
||||
return;
|
||||
}
|
||||
this.hideScratch = hideScratch;
|
||||
reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SnapshotTableColumns> defaultSortOrder() {
|
||||
return List.of(SnapshotTableColumns.TIME);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLoad(Accumulator<SnapshotRow> accumulator, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
rowMap.clear();
|
||||
if (currentTrace == null) {
|
||||
return;
|
||||
}
|
||||
TraceTimeManager manager = currentTrace.getTimeManager();
|
||||
Long maxSnap = manager.getMaxSnap();
|
||||
monitor.initialize(maxSnap == null ? 0 : maxSnap.longValue(), "Reading Snapshots");
|
||||
for (TraceSnapshot snapshot : hideScratch
|
||||
? manager.getSnapshots(0, true, Long.MAX_VALUE, true)
|
||||
: manager.getAllSnapshots()) {
|
||||
SnapshotRow row = new SnapshotRow(snapshot, serviceProvider);
|
||||
rowMap.put(snapshot, row);
|
||||
accumulator.add(row);
|
||||
monitor.setProgress(Math.max(0, snapshot.getKey()));
|
||||
monitor.checkCancelled();
|
||||
}
|
||||
}
|
||||
|
||||
public void addSnapshot(TraceSnapshot snapshot) {
|
||||
if (snapshot.getKey() < 0 && hideScratch) {
|
||||
return;
|
||||
}
|
||||
SnapshotRow row =
|
||||
rowMap.computeIfAbsent(snapshot, s -> new SnapshotRow(s, serviceProvider));
|
||||
addObject(row);
|
||||
}
|
||||
|
||||
public void updateSnapshot(TraceSnapshot snapshot) {
|
||||
if (snapshot.getKey() < 0 && hideScratch) {
|
||||
return;
|
||||
}
|
||||
SnapshotRow row = rowMap.get(snapshot);
|
||||
if (row == null) {
|
||||
return;
|
||||
}
|
||||
updateObject(row);
|
||||
}
|
||||
|
||||
public void removeSnapshot(TraceSnapshot snapshot) {
|
||||
if (snapshot.getKey() < 0 && hideScratch) {
|
||||
return;
|
||||
}
|
||||
SnapshotRow row = rowMap.remove(snapshot);
|
||||
if (row == null) {
|
||||
return;
|
||||
}
|
||||
removeObject(row);
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,6 @@ import docking.action.DockingAction;
|
||||
import docking.action.ToggleDockingAction;
|
||||
import docking.action.builder.ActionBuilder;
|
||||
import docking.widgets.table.*;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import generic.theme.GColor;
|
||||
import ghidra.app.context.ListingActionContext;
|
||||
import ghidra.app.context.ProgramLocationActionContext;
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -17,14 +17,15 @@ package ghidra.app.plugin.core.debug.utils;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import docking.widgets.table.EnumeratedTableColumn;
|
||||
import docking.widgets.table.RowWrappedEnumeratedColumnTableModel;
|
||||
import ghidra.async.AsyncDebouncer;
|
||||
import ghidra.async.AsyncTimer;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.util.Swing;
|
||||
|
||||
public class DebouncedRowWrappedEnumeratedColumnTableModel<C extends Enum<C> & EnumeratedTableColumn<C, R>, K, R, T>
|
||||
public class DebouncedRowWrappedEnumeratedColumnTableModel<
|
||||
C extends Enum<C> & EnumeratedTableColumn<C, R>, K, R, T>
|
||||
extends RowWrappedEnumeratedColumnTableModel<C, K, R, T> {
|
||||
|
||||
AsyncDebouncer<Void> debouncer = new AsyncDebouncer<Void>(AsyncTimer.DEFAULT_TIMER, 100);
|
||||
|
||||
@@ -102,25 +102,26 @@ public class DebuggerTimeProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||
|
||||
createSnaplessTrace();
|
||||
addSnapshots();
|
||||
waitForBusyTool(tool);
|
||||
assertDisabled(listingProvider, timePlugin.actionRenameSnapshot);
|
||||
|
||||
traceManager.openTrace(tb.trace);
|
||||
waitForSwing();
|
||||
waitForBusyTool(tool);
|
||||
assertDisabled(listingProvider, timePlugin.actionRenameSnapshot);
|
||||
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
waitForBusyTool(tool);
|
||||
assertEnabled(listingProvider, timePlugin.actionRenameSnapshot);
|
||||
|
||||
traceManager.activateSnap(10);
|
||||
waitForSwing();
|
||||
waitForBusyTool(tool);
|
||||
performEnabledAction(listingProvider, timePlugin.actionRenameSnapshot, false);
|
||||
InputDialog dialog = waitForDialogComponent(InputDialog.class);
|
||||
assertEquals("Snap 10", dialog.getValue());
|
||||
|
||||
dialog.setValue("My Snapshot");
|
||||
dialog.close(); // isCancelled (private) defaults to false
|
||||
waitForSwing();
|
||||
waitForBusyTool(tool);
|
||||
|
||||
DBTraceSnapshot snapshot = tb.trace.getTimeManager().getSnapshot(10, false);
|
||||
assertEquals("My Snapshot", snapshot.getDescription());
|
||||
@@ -130,6 +131,7 @@ public class DebuggerTimeProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
waitForBusyTool(tool);
|
||||
assertProviderEmpty();
|
||||
}
|
||||
|
||||
@@ -138,12 +140,13 @@ public class DebuggerTimeProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||
createSnaplessTrace();
|
||||
traceManager.openTrace(tb.trace);
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderEmpty();
|
||||
|
||||
addSnapshots();
|
||||
waitForDomainObject(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderPopulated();
|
||||
}
|
||||
@@ -158,12 +161,13 @@ public class DebuggerTimeProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||
}
|
||||
traceManager.openTrace(tb.trace);
|
||||
traceManager.activateThread(thread);
|
||||
waitForSwing();
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderEmpty();
|
||||
|
||||
addSnapshots();
|
||||
waitForDomainObject(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderPopulated();
|
||||
}
|
||||
@@ -174,11 +178,12 @@ public class DebuggerTimeProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||
traceManager.openTrace(tb.trace);
|
||||
addSnapshots();
|
||||
waitForDomainObject(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderEmpty();
|
||||
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderPopulated();
|
||||
}
|
||||
@@ -189,11 +194,12 @@ public class DebuggerTimeProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||
traceManager.openTrace(tb.trace);
|
||||
addSnapshots();
|
||||
waitForDomainObject(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderEmpty();
|
||||
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderPopulated();
|
||||
|
||||
@@ -201,6 +207,7 @@ public class DebuggerTimeProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||
tb.trace.getTimeManager().getSnapshot(10, false).delete();
|
||||
}
|
||||
waitForDomainObject(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertEquals(1, timeProvider.mainPanel.snapshotTableModel.getModelData().size());
|
||||
}
|
||||
@@ -210,20 +217,23 @@ public class DebuggerTimeProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||
createSnaplessTrace();
|
||||
traceManager.openTrace(tb.trace);
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderEmpty();
|
||||
|
||||
addSnapshots();
|
||||
waitForDomainObject(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderPopulated();
|
||||
|
||||
undo(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderEmpty();
|
||||
|
||||
redo(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderPopulated();
|
||||
}
|
||||
@@ -233,19 +243,21 @@ public class DebuggerTimeProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||
createSnaplessTrace();
|
||||
traceManager.openTrace(tb.trace);
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderEmpty();
|
||||
|
||||
try (Transaction tx = tb.startTransaction()) {
|
||||
addSnapshots();
|
||||
waitForDomainObject(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderPopulated();
|
||||
|
||||
tx.abort();
|
||||
}
|
||||
waitForDomainObject(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderEmpty();
|
||||
}
|
||||
@@ -260,7 +272,7 @@ public class DebuggerTimeProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||
assertProviderEmpty();
|
||||
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderPopulated();
|
||||
|
||||
@@ -276,15 +288,17 @@ public class DebuggerTimeProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||
traceManager.openTrace(tb.trace);
|
||||
addSnapshots();
|
||||
waitForDomainObject(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderEmpty();
|
||||
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
waitForBusyTool(tool);
|
||||
|
||||
SnapshotRow row = timeProvider.mainPanel.snapshotTableModel.getModelData().get(0);
|
||||
runSwing(() -> row.setDescription("Custom Description"));
|
||||
waitForDomainObject(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertEquals("Custom Description",
|
||||
tb.trace.getTimeManager().getSnapshot(0, false).getDescription());
|
||||
@@ -298,11 +312,12 @@ public class DebuggerTimeProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||
traceManager.openTrace(tb.trace);
|
||||
addSnapshots();
|
||||
waitForDomainObject(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertProviderEmpty();
|
||||
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
waitForBusyTool(tool);
|
||||
|
||||
clickTableCell(timeProvider.mainPanel.snapshotTable, 0, 0, 2);
|
||||
assertEquals(0, traceManager.getCurrentSnap());
|
||||
@@ -318,9 +333,10 @@ public class DebuggerTimeProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||
addSnapshots();
|
||||
addScratchSnapshot();
|
||||
waitForDomainObject(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertEquals(3, timeProvider.mainPanel.snapshotTableModel.getModelData().size());
|
||||
}
|
||||
@@ -331,14 +347,16 @@ public class DebuggerTimeProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||
traceManager.openTrace(tb.trace);
|
||||
addSnapshots();
|
||||
waitForDomainObject(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertEquals(2, timeProvider.mainPanel.snapshotTableModel.getModelData().size());
|
||||
|
||||
addScratchSnapshot();
|
||||
waitForDomainObject(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertEquals(3, timeProvider.mainPanel.snapshotTableModel.getModelData().size());
|
||||
}
|
||||
@@ -350,19 +368,22 @@ public class DebuggerTimeProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||
addSnapshots();
|
||||
addScratchSnapshot();
|
||||
waitForDomainObject(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertEquals(false, timeProvider.hideScratch);
|
||||
assertEquals(3, timeProvider.mainPanel.snapshotTableModel.getModelData().size());
|
||||
|
||||
performAction(timeProvider.actionHideScratch);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertEquals(true, timeProvider.hideScratch);
|
||||
assertEquals(2, timeProvider.mainPanel.snapshotTableModel.getModelData().size());
|
||||
|
||||
performAction(timeProvider.actionHideScratch);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertEquals(false, timeProvider.hideScratch);
|
||||
assertEquals(3, timeProvider.mainPanel.snapshotTableModel.getModelData().size());
|
||||
@@ -377,9 +398,10 @@ public class DebuggerTimeProviderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||
addSnapshots();
|
||||
addScratchSnapshot();
|
||||
waitForDomainObject(tb.trace);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
waitForBusyTool(tool);
|
||||
|
||||
assertEquals(true, timeProvider.hideScratch);
|
||||
List<SnapshotRow> data = timeProvider.mainPanel.snapshotTableModel.getModelData();
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package docking.widgets.table;
|
||||
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
@@ -18,15 +18,7 @@ package docking.widgets.table;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.swing.table.TableCellEditor;
|
||||
|
||||
import docking.widgets.table.ColumnSortState.SortDirection;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.util.table.column.GColumnRenderer;
|
||||
|
||||
/**
|
||||
* A table model whose columns are described using an {@link Enum}.
|
||||
@@ -39,128 +31,16 @@ import ghidra.util.table.column.GColumnRenderer;
|
||||
*/
|
||||
public class DefaultEnumeratedColumnTableModel<C extends Enum<C> & EnumeratedTableColumn<C, R>, R>
|
||||
extends GDynamicColumnTableModel<R, Void> implements EnumeratedColumnTableModel<R> {
|
||||
// NOTE: If I need to track indices, addSortListener
|
||||
/**
|
||||
* An interface on enums used to describe table columns
|
||||
*
|
||||
* @param <C> the type of the enum
|
||||
* @param <R> the type of rows
|
||||
*/
|
||||
public static interface EnumeratedTableColumn<C extends Enum<C>, R> {
|
||||
/**
|
||||
* Get the value class of cells in this column
|
||||
*
|
||||
* @return the class
|
||||
*/
|
||||
public Class<?> getValueClass();
|
||||
|
||||
/**
|
||||
* Get the value of this column for the given row
|
||||
*
|
||||
* @param row the row
|
||||
* @return the value
|
||||
*/
|
||||
public Object getValueOf(R row);
|
||||
|
||||
/**
|
||||
* Get the name of this column
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
public String getHeader();
|
||||
|
||||
/**
|
||||
* Get the value of this column for the given row
|
||||
*
|
||||
* @param row the row
|
||||
* @param value the new value
|
||||
*/
|
||||
default public void setValueOf(R row, Object value) {
|
||||
throw new UnsupportedOperationException("Cell is not editable");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this column can be modified for the given row
|
||||
*
|
||||
* @param row the row
|
||||
* @return true if editable
|
||||
*/
|
||||
default public boolean isEditable(R row) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this column can be sorted
|
||||
*
|
||||
* <p>
|
||||
* TODO: Either this should be implemented as ported to {@link GDynamicColumnTableModel}, or
|
||||
* removed.
|
||||
*
|
||||
* @return true if sortable
|
||||
*/
|
||||
default public boolean isSortable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this column should be visible by default
|
||||
*
|
||||
* @return true if visible
|
||||
*/
|
||||
default public boolean isVisible() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default sort direction for this column
|
||||
*
|
||||
* @return the sort direction
|
||||
*/
|
||||
default public SortDirection defaultSortDirection() {
|
||||
return SortDirection.ASCENDING;
|
||||
}
|
||||
|
||||
default public int getPreferredWidth() {
|
||||
return AbstractGTableModel.WIDTH_UNDEFINED;
|
||||
}
|
||||
|
||||
default public int getMinWidth() {
|
||||
return AbstractGTableModel.WIDTH_UNDEFINED;
|
||||
}
|
||||
|
||||
default public int getMaxWidth() {
|
||||
return AbstractGTableModel.WIDTH_UNDEFINED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Because of limitations with Java generics and Enumerations, type checking cannot be
|
||||
* guaranteed here. The user must ensure that any returned by {@link #getValueOf(Object)}
|
||||
* can be accepted by the renderer returned here. The framework will perform an unchecked
|
||||
* cast of the renderer.
|
||||
*
|
||||
* @return the renderer
|
||||
*/
|
||||
default public GColumnRenderer<?> getRenderer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default public TableCellEditor getEditor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default public SettingsDefinition[] getSettingsDefinitions() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private final List<R> modelData = new ArrayList<>();
|
||||
private final String name;
|
||||
private final C[] cols;
|
||||
private final List<C> cols;
|
||||
|
||||
public DefaultEnumeratedColumnTableModel(PluginTool tool, String name, Class<C> colType) {
|
||||
super(tool);
|
||||
public DefaultEnumeratedColumnTableModel(ServiceProvider serviceProvider, String name,
|
||||
Class<C> colType) {
|
||||
super(serviceProvider);
|
||||
this.name = name;
|
||||
this.cols = colType.getEnumConstants();
|
||||
this.cols = List.of(colType.getEnumConstants());
|
||||
|
||||
reloadColumns(); // Smell
|
||||
}
|
||||
@@ -181,98 +61,9 @@ public class DefaultEnumeratedColumnTableModel<C extends Enum<C> & EnumeratedTab
|
||||
}
|
||||
}
|
||||
|
||||
static class EnumeratedDynamicTableColumn<R>
|
||||
extends AbstractDynamicTableColumn<R, Object, Void>
|
||||
implements EditableDynamicTableColumn<R, Object, Void> {
|
||||
private final EnumeratedTableColumn<?, R> col;
|
||||
|
||||
public EnumeratedDynamicTableColumn(EnumeratedTableColumn<?, R> col) {
|
||||
this.col = col;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return col.getHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(R rowObject, Settings settings, Void data,
|
||||
ServiceProvider serviceProvider) throws IllegalArgumentException {
|
||||
return col.getValueOf(rowObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Class<Object> getColumnClass() {
|
||||
return (Class<Object>) col.getValueClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEditable(R row, Settings settings, Void dataSource,
|
||||
ServiceProvider serviceProvider) {
|
||||
return col.isEditable(row);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueOf(R row, Object value, Settings settings, Void dataSource,
|
||||
ServiceProvider serviceProvider) {
|
||||
col.setValueOf(row, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public GColumnRenderer<Object> getColumnRenderer() {
|
||||
return (GColumnRenderer<Object>) col.getRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableCellEditor getColumnEditor() {
|
||||
return col.getEditor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnPreferredWidth() {
|
||||
return col.getPreferredWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnMaxWidth() {
|
||||
return col.getMaxWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnMinWidth() {
|
||||
return col.getMinWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettingsDefinition[] getSettingsDefinitions() {
|
||||
SettingsDefinition[] defs = col.getSettingsDefinitions();
|
||||
if (defs != null) {
|
||||
return defs;
|
||||
}
|
||||
return super.getSettingsDefinitions();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TableColumnDescriptor<R> createTableColumnDescriptor() {
|
||||
TableColumnDescriptor<R> descriptor = new TableColumnDescriptor<>();
|
||||
if (cols != null) { // Smells
|
||||
List<C> defaultOrder = defaultSortOrder();
|
||||
for (C col : cols) {
|
||||
EnumeratedDynamicTableColumn<R> ecol = new EnumeratedDynamicTableColumn<R>(col);
|
||||
if (col.isVisible()) {
|
||||
descriptor.addVisibleColumn(ecol,
|
||||
defaultOrder.indexOf(col), // -1 means not found, not sorted
|
||||
col.defaultSortDirection().isAscending());
|
||||
}
|
||||
else {
|
||||
descriptor.addHiddenColumn(ecol);
|
||||
}
|
||||
}
|
||||
}
|
||||
return descriptor;
|
||||
return EnumeratedColumnTableModel.createTableColumnDescriptor(cols, defaultSortOrder());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -54,4 +54,23 @@ public interface EnumeratedColumnTableModel<R> extends RowObjectTableModel<R> {
|
||||
R findFirst(Predicate<R> predicate);
|
||||
|
||||
public void clear();
|
||||
|
||||
static <C extends Enum<C> & EnumeratedTableColumn<C, R>, R> TableColumnDescriptor<R>
|
||||
createTableColumnDescriptor(Collection<C> cols, List<C> defaultOrder) {
|
||||
TableColumnDescriptor<R> descriptor = new TableColumnDescriptor<>();
|
||||
if (cols != null) { // Smells
|
||||
for (C col : cols) {
|
||||
EnumeratedDynamicTableColumn<R> ecol = new EnumeratedDynamicTableColumn<R>(col);
|
||||
if (col.isVisible()) {
|
||||
descriptor.addVisibleColumn(ecol,
|
||||
defaultOrder.indexOf(col), // -1 means not found, not sorted
|
||||
col.defaultSortDirection().isAscending());
|
||||
}
|
||||
else {
|
||||
descriptor.addHiddenColumn(ecol);
|
||||
}
|
||||
}
|
||||
}
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package docking.widgets.table;
|
||||
|
||||
import javax.swing.table.TableCellEditor;
|
||||
|
||||
import docking.widgets.table.EnumeratedColumnTableModel.EditableDynamicTableColumn;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.util.table.column.GColumnRenderer;
|
||||
|
||||
class EnumeratedDynamicTableColumn<R>
|
||||
extends AbstractDynamicTableColumn<R, Object, Void>
|
||||
implements EditableDynamicTableColumn<R, Object, Void> {
|
||||
private final EnumeratedTableColumn<?, R> col;
|
||||
|
||||
public EnumeratedDynamicTableColumn(EnumeratedTableColumn<?, R> col) {
|
||||
this.col = col;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return col.getHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(R rowObject, Settings settings, Void data,
|
||||
ServiceProvider serviceProvider) throws IllegalArgumentException {
|
||||
return col.getValueOf(rowObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Class<Object> getColumnClass() {
|
||||
return (Class<Object>) col.getValueClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEditable(R row, Settings settings, Void dataSource,
|
||||
ServiceProvider serviceProvider) {
|
||||
return col.isEditable(row);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueOf(R row, Object value, Settings settings, Void dataSource,
|
||||
ServiceProvider serviceProvider) {
|
||||
col.setValueOf(row, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public GColumnRenderer<Object> getColumnRenderer() {
|
||||
return (GColumnRenderer<Object>) col.getRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableCellEditor getColumnEditor() {
|
||||
return col.getEditor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnPreferredWidth() {
|
||||
return col.getPreferredWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnMaxWidth() {
|
||||
return col.getMaxWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnMinWidth() {
|
||||
return col.getMinWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettingsDefinition[] getSettingsDefinitions() {
|
||||
SettingsDefinition[] defs = col.getSettingsDefinitions();
|
||||
if (defs != null) {
|
||||
return defs;
|
||||
}
|
||||
return super.getSettingsDefinitions();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package docking.widgets.table;
|
||||
|
||||
import javax.swing.table.TableCellEditor;
|
||||
|
||||
import docking.widgets.table.ColumnSortState.SortDirection;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.util.table.column.GColumnRenderer;
|
||||
|
||||
// NOTE: If I need to track indices, addSortListener
|
||||
/**
|
||||
* An interface on enums used to describe table columns
|
||||
*
|
||||
* @param <C> the type of the enum
|
||||
* @param <R> the type of rows
|
||||
*/
|
||||
public interface EnumeratedTableColumn<C extends Enum<C>, R> {
|
||||
/**
|
||||
* Get the value class of cells in this column
|
||||
*
|
||||
* @return the class
|
||||
*/
|
||||
public Class<?> getValueClass();
|
||||
|
||||
/**
|
||||
* Get the value of this column for the given row
|
||||
*
|
||||
* @param row the row
|
||||
* @return the value
|
||||
*/
|
||||
public Object getValueOf(R row);
|
||||
|
||||
/**
|
||||
* Get the name of this column
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
public String getHeader();
|
||||
|
||||
/**
|
||||
* Get the value of this column for the given row
|
||||
*
|
||||
* @param row the row
|
||||
* @param value the new value
|
||||
*/
|
||||
default public void setValueOf(R row, Object value) {
|
||||
throw new UnsupportedOperationException("Cell is not editable");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this column can be modified for the given row
|
||||
*
|
||||
* @param row the row
|
||||
* @return true if editable
|
||||
*/
|
||||
default public boolean isEditable(R row) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this column can be sorted
|
||||
*
|
||||
* <p>
|
||||
* TODO: Either this should be implemented as ported to {@link GDynamicColumnTableModel}, or
|
||||
* removed.
|
||||
*
|
||||
* @return true if sortable
|
||||
*/
|
||||
default public boolean isSortable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this column should be visible by default
|
||||
*
|
||||
* @return true if visible
|
||||
*/
|
||||
default public boolean isVisible() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default sort direction for this column
|
||||
*
|
||||
* @return the sort direction
|
||||
*/
|
||||
default public SortDirection defaultSortDirection() {
|
||||
return SortDirection.ASCENDING;
|
||||
}
|
||||
|
||||
default public int getPreferredWidth() {
|
||||
return AbstractGTableModel.WIDTH_UNDEFINED;
|
||||
}
|
||||
|
||||
default public int getMinWidth() {
|
||||
return AbstractGTableModel.WIDTH_UNDEFINED;
|
||||
}
|
||||
|
||||
default public int getMaxWidth() {
|
||||
return AbstractGTableModel.WIDTH_UNDEFINED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Because of limitations with Java generics and Enumerations, type checking cannot be
|
||||
* guaranteed here. The user must ensure that any returned by {@link #getValueOf(Object)} can be
|
||||
* accepted by the renderer returned here. The framework will perform an unchecked cast of the
|
||||
* renderer.
|
||||
*
|
||||
* @return the renderer
|
||||
*/
|
||||
default public GColumnRenderer<?> getRenderer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default public TableCellEditor getEditor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default public SettingsDefinition[] getSettingsDefinitions() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -21,7 +21,6 @@ import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package docking.widgets.table;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import docking.widgets.table.threaded.ThreadedTableModel;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public abstract class ThreadedEnumeratedColumnTableModel<
|
||||
C extends Enum<C> & EnumeratedTableColumn<C, R>, R> extends ThreadedTableModel<R, Void> {
|
||||
|
||||
private final List<C> cols;
|
||||
|
||||
protected ThreadedEnumeratedColumnTableModel(ServiceProvider serviceProvider, String name,
|
||||
Class<C> colType, TaskMonitor monitor, boolean loadIncrementally) {
|
||||
super(name, serviceProvider, monitor, loadIncrementally);
|
||||
this.cols = List.of(colType.getEnumConstants());
|
||||
|
||||
reloadColumns();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default sort order of the table
|
||||
*
|
||||
* @return the list of columns in order of descending priority
|
||||
*/
|
||||
public List<C> defaultSortOrder() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TableColumnDescriptor<R> createTableColumnDescriptor() {
|
||||
return EnumeratedColumnTableModel.createTableColumnDescriptor(cols, defaultSortOrder());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void getDataSource() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,6 @@ import javax.swing.table.TableColumn;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import docking.widgets.table.RangeCursorTableHeaderRenderer.SeekListener;
|
||||
import generic.Span;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
|
||||
@@ -24,9 +24,7 @@ import java.util.stream.Stream;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import docking.widgets.table.GTable;
|
||||
import docking.widgets.table.*;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.util.table.GhidraTableFilterPanel;
|
||||
import ghidra.util.table.column.GColumnRenderer;
|
||||
|
||||
@@ -23,9 +23,7 @@ import java.util.function.Function;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.widgets.table.DefaultEnumeratedColumnProgramTableModel;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import docking.widgets.table.GTable;
|
||||
import docking.widgets.table.*;
|
||||
import generic.theme.GColor;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.pcode.emu.symz3.SymZ3RecordsExecution.RecInstruction;
|
||||
|
||||
@@ -23,9 +23,7 @@ import java.util.function.Function;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.widgets.table.DefaultEnumeratedColumnProgramTableModel;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import docking.widgets.table.GTable;
|
||||
import docking.widgets.table.*;
|
||||
import generic.theme.GColor;
|
||||
import ghidra.app.plugin.processors.sleigh.template.OpTpl;
|
||||
import ghidra.app.util.pcode.*;
|
||||
|
||||
Reference in New Issue
Block a user