GP-1625: Improve consistency of DebuggerMemoryBytesProvider

This commit is contained in:
Dan 2024-03-08 12:36:17 -05:00
parent 7d189001d6
commit 8e3f97056b
9 changed files with 131 additions and 29 deletions

View file

@ -19,6 +19,7 @@ import static ghidra.app.plugin.core.debug.gui.DebuggerResources.ICON_REGISTER_M
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.datatransfer.DataFlavor;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.lang.invoke.MethodHandles;
@ -26,8 +27,7 @@ import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
@ -62,6 +62,7 @@ import ghidra.app.plugin.core.debug.utils.ProgramURLUtils;
import ghidra.app.plugin.core.marker.MarkerMarginProvider;
import ghidra.app.plugin.core.marker.MarkerOverviewProvider;
import ghidra.app.services.*;
import ghidra.app.services.DebuggerControlService.ControlModeChangeListener;
import ghidra.app.services.DebuggerListingService.LocationTrackingSpecChangeListener;
import ghidra.app.util.viewer.format.FormatManager;
import ghidra.app.util.viewer.listingpanel.ListingPanel;
@ -293,7 +294,7 @@ public class DebuggerListingProvider extends CodeViewerProvider {
private DebuggerStaticMappingService mappingService;
@AutoServiceConsumed
private DebuggerConsoleService consoleService;
@AutoServiceConsumed
//@AutoServiceConsumed via method
private DebuggerControlService controlService;
@AutoServiceConsumed
private ProgramManager programManager;
@ -354,6 +355,12 @@ public class DebuggerListingProvider extends CodeViewerProvider {
protected final ForStaticSyncMappingChangeListener mappingChangeListener =
new ForStaticSyncMappingChangeListener();
private final ControlModeChangeListener controlModeChangeListener = (trace, mode) -> {
if (trace == current.getTrace()) {
// for Paste action
contextChanged();
}
};
protected final boolean isMainListing;
@ -597,6 +604,17 @@ public class DebuggerListingProvider extends CodeViewerProvider {
}
}
@AutoServiceConsumed
private void setControlService(DebuggerControlService controlService) {
if (this.controlService != null) {
this.controlService.removeModeChangeListener(controlModeChangeListener);
}
this.controlService = controlService;
if (this.controlService != null) {
this.controlService.addModeChangeListener(controlModeChangeListener);
}
}
@AutoServiceConsumed
private void setConsoleService(DebuggerConsoleService consoleService) {
if (consoleService != null) {
@ -725,6 +743,14 @@ public class DebuggerListingProvider extends CodeViewerProvider {
return DateUtils.formatDateTimestamp(new Date(snapshot.getRealTime()));
}
@Override
public Icon getIcon() {
if (isMainListing()) {
return getBaseIcon();
}
return super.getIcon();
}
@Override
protected ListingActionContext newListingActionContext() {
return new DebuggerListingActionContext(this);
@ -740,6 +766,21 @@ public class DebuggerListingProvider extends CodeViewerProvider {
}
return context.getComponentProvider() == componentProvider;
}
@Override
public boolean canPaste(DataFlavor[] availableFlavors) {
if (controlService == null) {
return false;
}
Trace trace = current.getTrace();
if (trace == null) {
return false;
}
if (!controlService.getCurrentMode(trace).canEdit(current)) {
return false;
}
return super.canPaste(availableFlavors);
}
};
}

View file

@ -92,7 +92,7 @@ public class DebuggerMemoryBytesPlugin
private void createActions() {
actionNewMemory = NewMemoryAction.builder(this)
.enabled(true)
.onAction(c -> createNewDisconnectedProvider())
.onAction(c -> connectedProvider.cloneWindow())
.buildAndInstall(tool);
}

View file

@ -16,14 +16,14 @@
package ghidra.app.plugin.core.debug.gui.memory;
import java.awt.BorderLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.lang.invoke.MethodHandles;
import java.math.BigInteger;
import java.util.*;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.*;
import org.apache.commons.lang3.StringUtils;
@ -40,6 +40,8 @@ import ghidra.app.plugin.core.debug.gui.DebuggerResources.FollowsCurrentThreadAc
import ghidra.app.plugin.core.debug.gui.action.*;
import ghidra.app.plugin.core.debug.gui.action.AutoReadMemorySpec.AutoReadMemorySpecConfigFieldCodec;
import ghidra.app.plugin.core.format.ByteBlock;
import ghidra.app.services.DebuggerControlService;
import ghidra.app.services.DebuggerControlService.ControlModeChangeListener;
import ghidra.app.services.DebuggerTraceManagerService;
import ghidra.debug.api.action.GoToInput;
import ghidra.debug.api.action.LocationTrackingSpec;
@ -168,6 +170,8 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
@AutoServiceConsumed
private DebuggerTraceManagerService traceManager;
//@AutoServiceConsumed via method
private DebuggerControlService controlService;
@SuppressWarnings("unused")
private final AutoService.Wiring autoServiceWiring;
@ -191,6 +195,12 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
// TODO: followsCurrentSnap?
private final ListenerForChanges listenerForChanges = new ListenerForChanges();
private final ControlModeChangeListener controlModeChangeListener = (trace, mode) -> {
if (trace == getCurrent().getTrace()) {
// for Paste action
contextChanged();
}
};
DebuggerCoordinates current = DebuggerCoordinates.NOWHERE;
private DebuggerCoordinates previous = DebuggerCoordinates.NOWHERE;
@ -220,6 +230,13 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
readsMemTrait.goToCoordinates(current);
locationLabel.goToCoordinates(current);
if (isConnected) {
setTitle(DebuggerResources.TITLE_PROVIDER_MEMORY_BYTES);
}
else {
setTitle("[" + DebuggerResources.TITLE_PROVIDER_MEMORY_BYTES + "]");
}
updateTitle(); // Actually, the subtitle
setHelpLocation(DebuggerResources.HELP_PROVIDER_MEMORY_BYTES);
trackingLabel.addMouseListener(new MouseAdapter() {
@ -339,11 +356,50 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
setSubTitle(computeSubTitle());
}
@Override
public Icon getIcon() {
if (isMainViewer()) {
return getBaseIcon();
}
return super.getIcon();
}
@Override
protected ByteViewerActionContext newByteViewerActionContext() {
return new DebuggerMemoryBytesActionContext(this);
}
@Override
protected ByteViewerClipboardProvider newClipboardProvider() {
return new ByteViewerClipboardProvider(this, tool) {
@Override
public boolean canPaste(DataFlavor[] availableFlavors) {
if (controlService == null) {
return false;
}
Trace trace = current.getTrace();
if (trace == null) {
return false;
}
if (!controlService.getCurrentMode(trace).canEdit(current)) {
return false;
}
return super.canPaste(availableFlavors);
}
};
}
@AutoServiceConsumed
private void setControlService(DebuggerControlService controlService) {
if (this.controlService != null) {
this.controlService.removeModeChangeListener(controlModeChangeListener);
}
this.controlService = controlService;
if (this.controlService != null) {
this.controlService.addModeChangeListener(controlModeChangeListener);
}
}
protected void createActions() {
initTraits();

View file

@ -15,7 +15,7 @@
*/
package ghidra.app.plugin.core.debug.gui.memory;
import static ghidra.lifecycle.Unfinished.*;
import static ghidra.lifecycle.Unfinished.TODO;
import static org.junit.Assert.*;
import java.awt.*;
@ -49,7 +49,7 @@ import ghidra.app.plugin.core.debug.gui.DebuggerResources.FollowsCurrentThreadAc
import ghidra.app.plugin.core.debug.gui.action.*;
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
import ghidra.app.plugin.core.debug.service.control.DebuggerControlServicePlugin;
import ghidra.app.services.*;
import ghidra.app.services.DebuggerControlService;
import ghidra.async.SwingExecutorService;
import ghidra.debug.api.control.ControlMode;
import ghidra.debug.api.model.TraceRecorder;

View file

@ -79,7 +79,6 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
private static final String DIVIDER_LOCATION = "DividerLocation";
private ImageIcon navigatableIcon;
private Map<Program, ListingHighlightProvider> programHighlighterMap = new HashMap<>();
private ProgramHighlighterProvider highlighterAdapter;
@ -845,19 +844,6 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
return currentStringSelection;
}
@Override
public Icon getIcon() {
if (isConnected()) {
return super.getIcon();
}
if (navigatableIcon == null) {
Icon primaryIcon = super.getIcon();
navigatableIcon = NavigatableIconFactory.createSnapshotOverlayIcon(primaryIcon);
}
return navigatableIcon;
}
@Override
public Icon getNavigatableIcon() {
return getIcon();

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -45,11 +44,11 @@ public abstract class NavigatableComponentProviderAdapter extends ComponentProvi
@Override
public Icon getIcon() {
if (isConnected()) {
return super.getIcon();
return getBaseIcon();
}
if (navigatableIcon == null) {
Icon primaryIcon = super.getIcon();
Icon primaryIcon = getBaseIcon();
navigatableIcon = NavigatableIconFactory.createSnapshotOverlayIcon(primaryIcon);
}
return navigatableIcon;

View file

@ -57,7 +57,7 @@ public abstract class AbstractByteViewerPlugin<P extends ProgramByteViewerCompon
public P createNewDisconnectedProvider() {
P newProvider = createProvider(false);
disconnectedProviders.add(newProvider);
addProvider(newProvider);
tool.showComponentProvider(newProvider, true);
return newProvider;
}

View file

@ -90,7 +90,7 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
}
decorationComponent = new DecoratorPanel(panel, isConnected);
clipboardProvider = new ByteViewerClipboardProvider(this, tool);
clipboardProvider = newClipboardProvider();
addToTool();
createProgramActions();
@ -98,6 +98,10 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
registerNavigatable();
}
protected ByteViewerClipboardProvider newClipboardProvider() {
return new ByteViewerClipboardProvider(this, tool);
}
public void createProgramActions() {
cloneByteViewerAction = new CloneByteViewerAction();
tool.addLocalAction(this, cloneByteViewerAction);
@ -343,11 +347,11 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
@Override
public Icon getIcon() {
if (isConnected()) {
return super.getIcon();
return getBaseIcon();
}
if (navigatableIcon == null) {
Icon primaryIcon = super.getIcon();
Icon primaryIcon = getBaseIcon();
navigatableIcon = NavigatableIconFactory.createSnapshotOverlayIcon(primaryIcon);
}
return navigatableIcon;

View file

@ -628,6 +628,22 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
dockingTool.getWindowManager().setIcon(this, icon);
}
/**
* Get the icon provided to {@link #setIcon(Icon)}
*
* <p>
* This method is final, guaranteeing there is always a means for extensions of this class to
* obtain the original icon. Some classes may override {@link #getIcon()} to apply modifications
* when the icon is displayed in the UI. Further extensions of that class may wish to override
* {@link #getIcon()}, too, and so might want access to the original base icon. This method
* provides that access.
*
* @return the base icon
*/
protected final Icon getBaseIcon() {
return icon;
}
/**
* Signals that this provider's action for showing the provider should appear in the main
* toolbar