mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-09-19 18:21:26 +00:00
GP-4311: Add Context menu to Location labels
This commit is contained in:
parent
247528c7fe
commit
1bd3fe3669
|
@ -15,12 +15,18 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.debug.gui;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.*;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
|
||||
import org.apache.commons.collections4.ComparatorUtils;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.ComponentProvider;
|
||||
import ghidra.app.plugin.core.debug.gui.memory.DebuggerRegionActionContext;
|
||||
import ghidra.app.plugin.core.debug.gui.modules.DebuggerModuleActionContext;
|
||||
import ghidra.app.plugin.core.debug.gui.modules.DebuggerSectionActionContext;
|
||||
import ghidra.async.AsyncDebouncer;
|
||||
import ghidra.async.AsyncTimer;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
|
@ -204,4 +210,33 @@ public class DebuggerLocationLabel extends JLabel {
|
|||
setText(label);
|
||||
setToolTipText(label);
|
||||
}
|
||||
|
||||
public ActionContext getActionContext(ComponentProvider provider, MouseEvent event) {
|
||||
TraceProgramView view = current.getView();
|
||||
if (view == null) {
|
||||
return null;
|
||||
}
|
||||
if (address == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
TraceSection section = getNearestSectionContaining();
|
||||
if (section != null) {
|
||||
return new DebuggerSectionActionContext(provider, Set.of(section), this, true);
|
||||
}
|
||||
TraceModule module = getNearestModuleContaining();
|
||||
if (module != null) {
|
||||
return new DebuggerModuleActionContext(provider, Set.of(module), this, true);
|
||||
}
|
||||
TraceMemoryRegion region = getRegionContaining();
|
||||
if (region != null) {
|
||||
return new DebuggerRegionActionContext(provider, Set.of(region), this, true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
// The error should already be displayed in the label
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -433,10 +433,9 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
|||
* little conflated, since before the debugger, no one else presented a listing that could claim
|
||||
* to be "main" except the "connected" one. Here, we treat "connected" to mean that the address
|
||||
* is synchronized exactly with the other providers. "Main" on the other hand, does not
|
||||
* necessarily have that property, but it is still <em>not</em> a snapshot. It is the main
|
||||
* listing presented by this plugin, and so it has certain unique features. Calling
|
||||
* {@link DebuggerListingPlugin#getProvider()} will return the main dynamic listing, despite it
|
||||
* not really being "connected."
|
||||
* necessarily have that property, but it is still <em>not</em> a clone. It is the main listing
|
||||
* presented by this plugin, and so it has certain unique features. Calling
|
||||
* {@link DebuggerListingPlugin#getProvider()} will return the main dynamic listing.
|
||||
*
|
||||
* @return true if this is the main listing for the plugin.
|
||||
*/
|
||||
|
@ -884,6 +883,14 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionContext getActionContext(MouseEvent event) {
|
||||
if (event == null || event.getSource() != locationLabel) {
|
||||
return super.getActionContext(event);
|
||||
}
|
||||
return locationLabel.getActionContext(this, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void programSelectionChanged(ProgramSelection selection, EventTrigger trigger) {
|
||||
super.programSelectionChanged(selection, trigger);
|
||||
|
|
|
@ -21,7 +21,6 @@ import java.util.Collection;
|
|||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.TableColumn;
|
||||
|
@ -116,27 +115,11 @@ public class DebuggerLegacyRegionsPanel extends JPanel {
|
|||
}
|
||||
}
|
||||
|
||||
protected static RegionRow getSelectedRegionRow(ActionContext context) {
|
||||
if (!(context instanceof DebuggerRegionActionContext)) {
|
||||
return null;
|
||||
}
|
||||
DebuggerRegionActionContext ctx = (DebuggerRegionActionContext) context;
|
||||
Set<RegionRow> regions = ctx.getSelectedRegions();
|
||||
if (regions.size() != 1) {
|
||||
return null;
|
||||
}
|
||||
return regions.iterator().next();
|
||||
}
|
||||
|
||||
protected static Set<TraceMemoryRegion> getSelectedRegions(ActionContext context) {
|
||||
if (!(context instanceof DebuggerRegionActionContext)) {
|
||||
if (!(context instanceof DebuggerRegionActionContext ctx)) {
|
||||
return null;
|
||||
}
|
||||
DebuggerRegionActionContext ctx = (DebuggerRegionActionContext) context;
|
||||
return ctx.getSelectedRegions()
|
||||
.stream()
|
||||
.map(r -> r.getRegion())
|
||||
.collect(Collectors.toSet());
|
||||
return ctx.getSelectedRegions();
|
||||
}
|
||||
|
||||
private class RegionsListener extends TraceDomainObjectListener {
|
||||
|
@ -279,16 +262,6 @@ public class DebuggerLegacyRegionsPanel extends JPanel {
|
|||
return !ctx.getSelectedRegions().isEmpty();
|
||||
}
|
||||
|
||||
private static Set<TraceMemoryRegion> getSelectedRegions(DebuggerRegionActionContext ctx) {
|
||||
if (ctx == null) {
|
||||
return null;
|
||||
}
|
||||
return ctx.getSelectedRegions()
|
||||
.stream()
|
||||
.map(r -> r.getRegion())
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
protected void navigateToSelectedRegion() {
|
||||
if (listingService != null) {
|
||||
int selectedRow = regionTable.getSelectedRow();
|
||||
|
|
|
@ -27,6 +27,7 @@ import javax.swing.JPanel;
|
|||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.ToggleDockingAction;
|
||||
import docking.menu.MultiStateDockingAction;
|
||||
|
@ -539,6 +540,10 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
|||
@Override
|
||||
protected void writeConfigState(SaveState saveState) {
|
||||
super.writeConfigState(saveState);
|
||||
|
||||
CONFIG_STATE_HANDLER.writeConfigState(this, saveState);
|
||||
trackingTrait.writeConfigState(saveState);
|
||||
readsMemTrait.writeConfigState(saveState);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -547,6 +552,7 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
|||
|
||||
CONFIG_STATE_HANDLER.readConfigState(this, saveState);
|
||||
trackingTrait.readConfigState(saveState);
|
||||
readsMemTrait.readConfigState(saveState);
|
||||
|
||||
if (isMainViewer()) {
|
||||
followsCurrentThread = true;
|
||||
|
@ -555,7 +561,6 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
|||
actionFollowsCurrentThread.setSelected(followsCurrentThread);
|
||||
updateBorder();
|
||||
}
|
||||
// TODO: actionAutoReadMemory
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -583,6 +588,14 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
|||
locationLabel.goToAddress(currentLocation == null ? null : currentLocation.getAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionContext getActionContext(MouseEvent event) {
|
||||
if (event == null || event.getSource() != locationLabel) {
|
||||
return super.getActionContext(event);
|
||||
}
|
||||
return locationLabel.getActionContext(this, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cloneWindow() {
|
||||
final DebuggerMemoryBytesProvider newProvider = myPlugin.createNewDisconnectedProvider();
|
||||
|
|
|
@ -15,22 +15,41 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.memory;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import docking.ComponentProvider;
|
||||
import docking.DefaultActionContext;
|
||||
import docking.widgets.table.GTable;
|
||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||
|
||||
public class DebuggerRegionActionContext extends DefaultActionContext {
|
||||
private final Set<RegionRow> selectedRegions;
|
||||
private final Set<TraceMemoryRegion> selectedRegions;
|
||||
private final boolean forcedSingle;
|
||||
|
||||
private static Set<TraceMemoryRegion> toRegions(Collection<RegionRow> rows) {
|
||||
return rows.stream().map(RegionRow::getRegion).collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
|
||||
public DebuggerRegionActionContext(DebuggerRegionsProvider provider,
|
||||
Collection<RegionRow> selected, GTable table) {
|
||||
super(provider, selected, table);
|
||||
this.selectedRegions = Set.copyOf(selected);
|
||||
Collection<RegionRow> rows, GTable table) {
|
||||
this(provider, toRegions(rows), table, false);
|
||||
}
|
||||
|
||||
public Set<RegionRow> getSelectedRegions() {
|
||||
public DebuggerRegionActionContext(ComponentProvider provider,
|
||||
Set<TraceMemoryRegion> selected, Component sourceComponent, boolean forcedSingle) {
|
||||
super(provider, selected, sourceComponent);
|
||||
this.selectedRegions = selected;
|
||||
this.forcedSingle = forcedSingle;
|
||||
}
|
||||
|
||||
public Set<TraceMemoryRegion> getSelectedRegions() {
|
||||
return selectedRegions;
|
||||
}
|
||||
|
||||
public boolean isForcedSingle() {
|
||||
return forcedSingle;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -177,10 +177,8 @@ public class DebuggerRegionsPanel extends AbstractObjectsTableBasedPanel<TraceOb
|
|||
return new ModelQuery(schema.searchFor(TargetMemoryRegion.class, path, true));
|
||||
}
|
||||
|
||||
protected static Set<TraceMemoryRegion> getSelectedRegions(DebuggerObjectActionContext ctx) {
|
||||
return ctx == null ? null
|
||||
: AbstractObjectsTableBasedPanel.getSelected(ctx, TraceObjectMemoryRegion.class)
|
||||
.collect(Collectors.toSet());
|
||||
protected Set<TraceMemoryRegion> getSelectedRegions(DebuggerObjectActionContext ctx) {
|
||||
return ctx == null ? null : getSelected(ctx).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public DebuggerRegionsPanel(DebuggerRegionsProvider provider) {
|
||||
|
|
|
@ -278,20 +278,22 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter {
|
|||
|
||||
protected void createActions() {
|
||||
actionMapRegions = MapRegionsAction.builder(plugin)
|
||||
.enabledWhen(this::isContextNonEmpty)
|
||||
.popupWhen(this::isContextNonEmpty)
|
||||
.enabledWhen(ctx -> isContextNonEmpty(ctx) && isContextNotForcedSingle(ctx))
|
||||
.popupWhen(ctx -> isContextNonEmpty(ctx) && isContextNotForcedSingle(ctx))
|
||||
.onAction(this::activatedMapRegions)
|
||||
.buildAndInstallLocal(this);
|
||||
.buildAndInstall(tool);
|
||||
actionMapRegionTo = MapRegionToAction.builder(plugin)
|
||||
.enabledWhen(ctx -> currentProgram != null && isContextSingleSelection(ctx))
|
||||
.popupWhen(ctx -> currentProgram != null && isContextSingleSelection(ctx))
|
||||
.onAction(this::activatedMapRegionTo)
|
||||
.buildAndInstallLocal(this);
|
||||
.buildAndInstall(tool);
|
||||
actionMapRegionsTo = MapRegionsToAction.builder(plugin)
|
||||
.enabledWhen(ctx -> currentProgram != null && isContextNonEmpty(ctx))
|
||||
.popupWhen(ctx -> currentProgram != null && isContextNonEmpty(ctx))
|
||||
.enabledWhen(ctx -> currentProgram != null && isContextNonEmpty(ctx) &&
|
||||
isContextNotForcedSingle(ctx))
|
||||
.popupWhen(ctx -> currentProgram != null && isContextNonEmpty(ctx) &&
|
||||
isContextNotForcedSingle(ctx))
|
||||
.onAction(this::activatedMapRegionsTo)
|
||||
.buildAndInstallLocal(this);
|
||||
.buildAndInstall(tool);
|
||||
actionSelectAddresses = new SelectAddressesAction();
|
||||
actionSelectRows = SelectRowsAction.builder(plugin)
|
||||
.description("Select regions by dynamic selection")
|
||||
|
@ -329,26 +331,33 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter {
|
|||
}
|
||||
|
||||
private boolean isContextNonEmpty(ActionContext context) {
|
||||
if (context instanceof DebuggerRegionActionContext legacyCtx) {
|
||||
return legacyPanel.isContextNonEmpty(legacyCtx);
|
||||
if (context instanceof DebuggerRegionActionContext ctx) {
|
||||
return legacyPanel.isContextNonEmpty(ctx);
|
||||
}
|
||||
else if (context instanceof DebuggerObjectActionContext ctx) {
|
||||
return DebuggerRegionsPanel.isContextNonEmpty(ctx);
|
||||
return panel.isContextNonEmpty(ctx);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isContextNotForcedSingle(ActionContext context) {
|
||||
if (context instanceof DebuggerRegionActionContext ctx) {
|
||||
return !ctx.isForcedSingle();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isContextSingleSelection(ActionContext context) {
|
||||
Set<TraceMemoryRegion> sel = getSelectedRegions(context);
|
||||
return sel != null && sel.size() == 1;
|
||||
}
|
||||
|
||||
private static Set<TraceMemoryRegion> getSelectedRegions(ActionContext context) {
|
||||
if (context instanceof DebuggerRegionActionContext legacyCtx) {
|
||||
return DebuggerLegacyRegionsPanel.getSelectedRegions(legacyCtx);
|
||||
private Set<TraceMemoryRegion> getSelectedRegions(ActionContext context) {
|
||||
if (context instanceof DebuggerRegionActionContext ctx) {
|
||||
return DebuggerLegacyRegionsPanel.getSelectedRegions(ctx);
|
||||
}
|
||||
else if (context instanceof DebuggerObjectActionContext ctx) {
|
||||
return DebuggerRegionsPanel.getSelectedRegions(ctx);
|
||||
return panel.getSelectedRegions(ctx);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -43,20 +43,6 @@ import ghidra.trace.model.target.TraceObjectInterface;
|
|||
public abstract class AbstractObjectsTableBasedPanel<U extends TraceObjectInterface>
|
||||
extends ObjectsTablePanel implements ListSelectionListener, CellActivationListener {
|
||||
|
||||
public static boolean isContextNonEmpty(DebuggerObjectActionContext ctx) {
|
||||
return ctx != null && !ctx.getObjectValues().isEmpty();
|
||||
}
|
||||
|
||||
public static <T extends TraceObjectInterface> Stream<T> getSelected(
|
||||
DebuggerObjectActionContext ctx, Class<T> iface) {
|
||||
return ctx == null ? null
|
||||
: ctx.getObjectValues()
|
||||
.stream()
|
||||
.filter(v -> v.isObject())
|
||||
.map(v -> v.getChild().queryInterface(iface))
|
||||
.filter(r -> r != null);
|
||||
}
|
||||
|
||||
private final ComponentProvider provider;
|
||||
private final Class<U> objType;
|
||||
|
||||
|
@ -82,6 +68,19 @@ public abstract class AbstractObjectsTableBasedPanel<U extends TraceObjectInterf
|
|||
addCellActivationListener(this);
|
||||
}
|
||||
|
||||
public boolean isContextNonEmpty(DebuggerObjectActionContext ctx) {
|
||||
return getSelected(ctx).findAny().isPresent();
|
||||
}
|
||||
|
||||
public Stream<U> getSelected(DebuggerObjectActionContext ctx) {
|
||||
return ctx == null ? null
|
||||
: ctx.getObjectValues()
|
||||
.stream()
|
||||
.filter(v -> v.isObject())
|
||||
.map(v -> v.getChild().queryInterface(objType))
|
||||
.filter(r -> r != null);
|
||||
}
|
||||
|
||||
public DebuggerObjectActionContext getActionContext() {
|
||||
return myActionContext;
|
||||
}
|
||||
|
|
|
@ -46,17 +46,14 @@ public class DebuggerLegacyModulesPanel extends JPanel {
|
|||
|
||||
protected static Set<TraceModule> getSelectedModulesFromContext(
|
||||
DebuggerModuleActionContext context) {
|
||||
return context.getSelectedModules()
|
||||
.stream()
|
||||
.map(r -> r.getModule())
|
||||
.collect(Collectors.toSet());
|
||||
return context.getSelectedModules();
|
||||
}
|
||||
|
||||
protected static Set<TraceSection> getSelectedSectionsFromContext(
|
||||
DebuggerModuleActionContext context) {
|
||||
return context.getSelectedModules()
|
||||
.stream()
|
||||
.flatMap(r -> r.getModule().getSections().stream())
|
||||
.flatMap(m -> m.getSections().stream())
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
|
@ -69,24 +66,6 @@ public class DebuggerLegacyModulesPanel extends JPanel {
|
|||
return sel;
|
||||
}
|
||||
|
||||
protected static ModuleRow getSelectedModuleRowFromContext(
|
||||
DebuggerModuleActionContext context) {
|
||||
Set<ModuleRow> modules = context.getSelectedModules();
|
||||
if (modules.size() != 1) {
|
||||
return null;
|
||||
}
|
||||
return modules.iterator().next();
|
||||
}
|
||||
|
||||
protected static SectionRow getSelectedSectionRowFromContext(
|
||||
DebuggerSectionActionContext context) {
|
||||
Set<SectionRow> sections = context.getSelectedSections();
|
||||
if (sections.size() != 1) {
|
||||
return null;
|
||||
}
|
||||
return sections.iterator().next();
|
||||
}
|
||||
|
||||
protected enum ModuleTableColumns
|
||||
implements EnumeratedTableColumn<ModuleTableColumns, ModuleRow> {
|
||||
BASE("Base Address", Address.class, ModuleRow::getBase),
|
||||
|
|
|
@ -48,24 +48,21 @@ public class DebuggerLegacySectionsPanel extends JPanel {
|
|||
|
||||
protected static Set<TraceModule> getSelectedModulesFromContext(
|
||||
DebuggerSectionActionContext context) {
|
||||
return context.getSelectedSections()
|
||||
return context.getSelectedSections(false)
|
||||
.stream()
|
||||
.map(r -> r.getModule())
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
protected static Set<TraceSection> getSelectedSectionsFromContext(
|
||||
DebuggerSectionActionContext context) {
|
||||
return context.getSelectedSections()
|
||||
.stream()
|
||||
.map(r -> r.getSection())
|
||||
.collect(Collectors.toSet());
|
||||
DebuggerSectionActionContext context, boolean allowExpansion) {
|
||||
return context.getSelectedSections(allowExpansion);
|
||||
}
|
||||
|
||||
protected static AddressSetView getSelectedAddressesFromContext(
|
||||
DebuggerSectionActionContext context) {
|
||||
AddressSet sel = new AddressSet();
|
||||
for (TraceSection section : getSelectedSectionsFromContext(context)) {
|
||||
for (TraceSection section : getSelectedSectionsFromContext(context, false)) {
|
||||
sel.add(section.getRange());
|
||||
}
|
||||
return sel;
|
||||
|
|
|
@ -15,22 +15,41 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.modules;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import docking.ComponentProvider;
|
||||
import docking.DefaultActionContext;
|
||||
import docking.widgets.table.GTable;
|
||||
import ghidra.trace.model.modules.TraceModule;
|
||||
|
||||
public class DebuggerModuleActionContext extends DefaultActionContext {
|
||||
private final Set<ModuleRow> selectedModules;
|
||||
private final Set<TraceModule> selectedModules;
|
||||
private final boolean forcedSingle;
|
||||
|
||||
private static Set<TraceModule> toModules(Collection<ModuleRow> rows) {
|
||||
return rows.stream().map(ModuleRow::getModule).collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
|
||||
public DebuggerModuleActionContext(DebuggerModulesProvider provider,
|
||||
Collection<ModuleRow> selected, GTable table) {
|
||||
super(provider, selected, table);
|
||||
this.selectedModules = Set.copyOf(selected);
|
||||
Collection<ModuleRow> rows, GTable table) {
|
||||
this(provider, toModules(rows), table, false);
|
||||
}
|
||||
|
||||
public Set<ModuleRow> getSelectedModules() {
|
||||
public DebuggerModuleActionContext(ComponentProvider provider, Set<TraceModule> selected,
|
||||
Component sourceComponent, boolean forcedSingle) {
|
||||
super(provider, selected, sourceComponent);
|
||||
this.selectedModules = selected;
|
||||
this.forcedSingle = forcedSingle;
|
||||
}
|
||||
|
||||
public Set<TraceModule> getSelectedModules() {
|
||||
return selectedModules;
|
||||
}
|
||||
|
||||
public boolean isForcedSingle() {
|
||||
return forcedSingle;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -306,12 +306,13 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
return Set.of();
|
||||
}
|
||||
|
||||
protected static Set<TraceSection> getSelectedSections(ActionContext context) {
|
||||
protected static Set<TraceSection> getSelectedSections(ActionContext context,
|
||||
boolean allowExpansion) {
|
||||
if (context instanceof DebuggerModuleActionContext ctx) {
|
||||
return DebuggerLegacyModulesPanel.getSelectedSectionsFromContext(ctx);
|
||||
}
|
||||
if (context instanceof DebuggerSectionActionContext ctx) {
|
||||
return DebuggerLegacySectionsPanel.getSelectedSectionsFromContext(ctx);
|
||||
return DebuggerLegacySectionsPanel.getSelectedSectionsFromContext(ctx, allowExpansion);
|
||||
}
|
||||
if (context instanceof DebuggerObjectActionContext ctx) {
|
||||
return DebuggerModulesPanel.getSelectedSectionsFromContext(ctx);
|
||||
|
@ -372,7 +373,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
public ImportFromFileSystemAction() {
|
||||
super(plugin);
|
||||
setPopupMenuData(new MenuData(new String[] { NAME }, GROUP));
|
||||
addLocalAction(this);
|
||||
tool.addAction(this);
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
|
@ -467,7 +468,6 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
SelectAddressesAction actionSelectAddresses;
|
||||
ImportFromFileSystemAction actionImportFromFileSystem;
|
||||
ToggleDockingAction actionShowSectionsTable;
|
||||
// TODO: Save the state of this toggle? Not really compelled.
|
||||
ToggleDockingAction actionFilterSectionsByModules;
|
||||
DockingAction actionSelectCurrent;
|
||||
|
||||
|
@ -594,30 +594,32 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
.onAction(this::activatedMapManually)
|
||||
.buildAndInstallLocal(this);
|
||||
actionMapModules = MapModulesAction.builder(plugin)
|
||||
.enabledWhen(this::isContextNonEmpty)
|
||||
.popupWhen(this::isContextNonEmpty)
|
||||
.enabledWhen(ctx -> isContextHasModules(ctx) && isContextNotForcedSingle(ctx))
|
||||
.popupWhen(ctx -> isContextHasModules(ctx) && isContextNotForcedSingle(ctx))
|
||||
.onAction(this::activatedMapModules)
|
||||
.buildAndInstallLocal(this);
|
||||
.buildAndInstall(tool);
|
||||
actionMapModuleTo = MapModuleToAction.builder(plugin)
|
||||
.enabledWhen(ctx -> currentProgram != null && getSelectedModules(ctx).size() == 1)
|
||||
.popupWhen(ctx -> currentProgram != null && getSelectedModules(ctx).size() == 1)
|
||||
.onAction(this::activatedMapModuleTo)
|
||||
.buildAndInstallLocal(this);
|
||||
.buildAndInstall(tool);
|
||||
actionMapSections = MapSectionsAction.builder(plugin)
|
||||
.enabledWhen(this::isContextNonEmpty)
|
||||
.popupWhen(this::isContextNonEmpty)
|
||||
.enabledWhen(ctx -> isContextHasSections(ctx) && isContextNotForcedSingle(ctx))
|
||||
.popupWhen(ctx -> isContextHasSections(ctx) && isContextNotForcedSingle(ctx))
|
||||
.onAction(this::activatedMapSections)
|
||||
.buildAndInstallLocal(this);
|
||||
.buildAndInstall(tool);
|
||||
actionMapSectionTo = MapSectionToAction.builder(plugin)
|
||||
.enabledWhen(ctx -> currentProgram != null && getSelectedSections(ctx).size() == 1)
|
||||
.popupWhen(ctx -> currentProgram != null && getSelectedSections(ctx).size() == 1)
|
||||
.enabledWhen(
|
||||
ctx -> currentProgram != null && getSelectedSections(ctx, false).size() == 1)
|
||||
.popupWhen(
|
||||
ctx -> currentProgram != null && getSelectedSections(ctx, false).size() == 1)
|
||||
.onAction(this::activatedMapSectionTo)
|
||||
.buildAndInstallLocal(this);
|
||||
.buildAndInstall(tool);
|
||||
actionMapSectionsTo = MapSectionsToAction.builder(plugin)
|
||||
.enabledWhen(ctx -> currentProgram != null && isContextSectionsOfOneModule(ctx))
|
||||
.popupWhen(ctx -> currentProgram != null && isContextSectionsOfOneModule(ctx))
|
||||
.onAction(this::activatedMapSectionsTo)
|
||||
.buildAndInstallLocal(this);
|
||||
.buildAndInstall(tool);
|
||||
|
||||
actionAutoMap = AutoMapAction.builder(plugin)
|
||||
.onActionStateChanged(this::changedAutoMapSpec)
|
||||
|
@ -653,12 +655,20 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
contextChanged();
|
||||
}
|
||||
|
||||
private boolean isContextHasModules(ActionContext context) {
|
||||
return !getSelectedModules(context).isEmpty();
|
||||
}
|
||||
|
||||
private boolean isContextHasSections(ActionContext context) {
|
||||
return !getSelectedSections(context, false).isEmpty();
|
||||
}
|
||||
|
||||
private boolean isContextNonEmpty(ActionContext context) {
|
||||
if (context instanceof DebuggerModuleActionContext ctx) {
|
||||
return !ctx.getSelectedModules().isEmpty();
|
||||
}
|
||||
if (context instanceof DebuggerSectionActionContext ctx) {
|
||||
return !ctx.getSelectedSections().isEmpty();
|
||||
return !ctx.getSelectedSections(false).isEmpty();
|
||||
}
|
||||
if (context instanceof DebuggerObjectActionContext ctx) {
|
||||
return !ctx.getObjectValues().isEmpty();
|
||||
|
@ -666,8 +676,18 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
return false;
|
||||
}
|
||||
|
||||
private boolean isContextSectionsOfOneModule(ActionContext ignored) {
|
||||
Set<TraceSection> sel = getSelectedSections(myActionContext);
|
||||
private boolean isContextNotForcedSingle(ActionContext context) {
|
||||
if (context instanceof DebuggerModuleActionContext ctx) {
|
||||
return !ctx.isForcedSingle();
|
||||
}
|
||||
if (context instanceof DebuggerSectionActionContext ctx) {
|
||||
return !ctx.isForcedSingle();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isContextSectionsOfOneModule(ActionContext context) {
|
||||
Set<TraceSection> sel = getSelectedSections(context, false);
|
||||
if (sel == null || sel.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -713,40 +733,40 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
tool.showComponentProvider(provider, true);
|
||||
}
|
||||
|
||||
private void activatedMapModules(ActionContext ignored) {
|
||||
Set<TraceModule> sel = getSelectedModules(myActionContext);
|
||||
private void activatedMapModules(ActionContext context) {
|
||||
Set<TraceModule> sel = getSelectedModules(context);
|
||||
if (sel == null || sel.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
mapModules(sel);
|
||||
}
|
||||
|
||||
private void activatedMapModuleTo(ActionContext ignored) {
|
||||
Set<TraceModule> sel = getSelectedModules(myActionContext);
|
||||
private void activatedMapModuleTo(ActionContext context) {
|
||||
Set<TraceModule> sel = getSelectedModules(context);
|
||||
if (sel == null || sel.size() != 1) {
|
||||
return;
|
||||
}
|
||||
mapModuleTo(sel.iterator().next());
|
||||
}
|
||||
|
||||
private void activatedMapSections(ActionContext ignored) {
|
||||
Set<TraceSection> sel = getSelectedSections(myActionContext);
|
||||
private void activatedMapSections(ActionContext context) {
|
||||
Set<TraceSection> sel = getSelectedSections(context, true);
|
||||
if (sel == null || sel.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
mapSections(sel);
|
||||
}
|
||||
|
||||
private void activatedMapSectionsTo(ActionContext ignored) {
|
||||
Set<TraceSection> sel = getSelectedSections(myActionContext);
|
||||
private void activatedMapSectionsTo(ActionContext context) {
|
||||
Set<TraceSection> sel = getSelectedSections(context, true);
|
||||
if (sel == null || sel.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
mapSectionsTo(sel);
|
||||
}
|
||||
|
||||
private void activatedMapSectionTo(ActionContext ignored) {
|
||||
Set<TraceSection> sel = getSelectedSections(myActionContext);
|
||||
private void activatedMapSectionTo(ActionContext context) {
|
||||
Set<TraceSection> sel = getSelectedSections(context, false);
|
||||
if (sel == null || sel.size() != 1) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -15,32 +15,46 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.modules;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import docking.ComponentProvider;
|
||||
import docking.DefaultActionContext;
|
||||
import docking.widgets.table.GTable;
|
||||
import ghidra.trace.model.modules.TraceSection;
|
||||
|
||||
public class DebuggerSectionActionContext extends DefaultActionContext {
|
||||
private final Set<SectionRow> selectedSections;
|
||||
//private final Set<ModuleRecord> involvedModules;
|
||||
private final Set<TraceSection> selectedSections;
|
||||
private final boolean forcedSingle;
|
||||
|
||||
public DebuggerSectionActionContext(DebuggerModulesProvider provider,
|
||||
Collection<SectionRow> selected, GTable table) {
|
||||
super(provider, selected, table);
|
||||
this.selectedSections = Set.copyOf(selected);
|
||||
/*
|
||||
* this.involvedModules = Collections.unmodifiableSet(
|
||||
* selected.stream().map(SectionRecord::getModule).collect(Collectors.toSet()));
|
||||
*/
|
||||
private static Set<TraceSection> toSections(Collection<SectionRow> rows) {
|
||||
return rows.stream().map(SectionRow::getSection).collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
|
||||
public Set<SectionRow> getSelectedSections() {
|
||||
public DebuggerSectionActionContext(DebuggerModulesProvider provider,
|
||||
Collection<SectionRow> rows, GTable table) {
|
||||
this(provider, toSections(rows), table, false);
|
||||
}
|
||||
|
||||
public DebuggerSectionActionContext(ComponentProvider provider,
|
||||
Set<TraceSection> selected, Component sourceComponent, boolean forcedSingle) {
|
||||
super(provider, selected, sourceComponent);
|
||||
this.selectedSections = selected;
|
||||
this.forcedSingle = forcedSingle;
|
||||
}
|
||||
|
||||
public Set<TraceSection> getSelectedSections(boolean allowExpansion) {
|
||||
if (forcedSingle && allowExpansion) {
|
||||
return selectedSections.stream()
|
||||
.flatMap(s -> s.getModule().getSections().stream())
|
||||
.collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
return selectedSections;
|
||||
}
|
||||
|
||||
/*
|
||||
* // TODO: Do I need this? public Set<ModuleRecord> getInvolvedModules() { return
|
||||
* involvedModules; }
|
||||
*/
|
||||
public boolean isForcedSingle() {
|
||||
return forcedSingle;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue