GP-6085 - Flow Arrows - Change to a service-based system for margin providers to allow flow arrows in snapshots

This commit is contained in:
dragonmacher
2025-11-21 17:50:32 -05:00
parent d193345dde
commit eb10bd7e08
50 changed files with 2144 additions and 1546 deletions
@@ -85,7 +85,8 @@ import ghidra.util.Msg;
servicesRequired = {
DebuggerLogicalBreakpointService.class,
MarkerService.class,
})
}
)
public class DebuggerBreakpointMarkerPlugin extends Plugin {
private static final Color COLOR_BREAKPOINT_ENABLED_MARKER =
@@ -496,7 +497,7 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
new ProgramLocationActionContext(null, location.getProgram(),
new ProgramLocation(location.getProgram(), location.getAddr()), null, null);
if (contextCanManipulateBreakpoints(context)) {
doToggleBreakpointsAt(ToggleBreakpointAction.NAME, context);
doToggleBreakpointsAt(AbstractToggleBreakpointAction.NAME, context);
}
}
}
@@ -753,28 +754,32 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
@AutoOptionDefined(
name = DebuggerResources.OPTION_NAME_COLORS_ENABLED_BREAKPOINT_COLORING_BACKGROUND,
description = "Whether or not to color background for memory at an enabled breakpoint",
help = @HelpInfo(anchor = "colors"))
help = @HelpInfo(anchor = "colors")
)
private boolean breakpointEnabledColoringBackground =
DebuggerResources.DEFAULT_COLOR_ENABLED_BREAKPOINT_COLORING_BACKGROUND;
@AutoOptionDefined(
name = DebuggerResources.OPTION_NAME_COLORS_DISABLED_BREAKPOINT_COLORING_BACKGROUND,
description = "Whether or not to color background for memory at a disabled breakpoint",
help = @HelpInfo(anchor = "colors"))
help = @HelpInfo(anchor = "colors")
)
private boolean breakpointDisabledColoringBackground =
DebuggerResources.DEFAULT_COLOR_DISABLED_BREAKPOINT_COLORING_BACKGROUND;
@AutoOptionDefined(
name = DebuggerResources.OPTION_NAME_COLORS_INEFF_EN_BREAKPOINT_COLORING_BACKGROUND,
description = "Whether or not to color background for memory at an enabled, but ineffective, breakpoint",
help = @HelpInfo(anchor = "colors"))
help = @HelpInfo(anchor = "colors")
)
private boolean breakpointIneffEnColoringBackground =
DebuggerResources.DEFAULT_COLOR_INEFF_EN_BREAKPOINT_COLORING_BACKGROUND;
@AutoOptionDefined(
name = DebuggerResources.OPTION_NAME_COLORS_INEFF_DIS_BREAKPOINT_COLORING_BACKGROUND,
description = "Whether or not to color background for memory at an disabled, but ineffective, breakpoint",
help = @HelpInfo(anchor = "colors"))
help = @HelpInfo(anchor = "colors")
)
private boolean breakpointIneffDisColoringBackground =
DebuggerResources.DEFAULT_COLOR_INEFF_DIS_BREAKPOINT_COLORING_BACKGROUND;
@@ -832,7 +837,8 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
}
@AutoOptionConsumed(
name = DebuggerResources.OPTION_NAME_COLORS_ENABLED_BREAKPOINT_COLORING_BACKGROUND)
name = DebuggerResources.OPTION_NAME_COLORS_ENABLED_BREAKPOINT_COLORING_BACKGROUND
)
private void setEnabledBreakpointMarkerBackground(boolean breakpointColoringBackground) {
for (BreakpointMarkerSets markers : markersByProgram.values()) {
markers.setEnabledColoringBackground(breakpointColoringBackground);
@@ -840,7 +846,8 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
}
@AutoOptionConsumed(
name = DebuggerResources.OPTION_NAME_COLORS_DISABLED_BREAKPOINT_COLORING_BACKGROUND)
name = DebuggerResources.OPTION_NAME_COLORS_DISABLED_BREAKPOINT_COLORING_BACKGROUND
)
private void setDisabledBreakpointMarkerBackground(boolean breakpointColoringBackground) {
for (BreakpointMarkerSets markers : markersByProgram.values()) {
markers.setDisabledColoringBackground(breakpointColoringBackground);
@@ -848,7 +855,8 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
}
@AutoOptionConsumed(
name = DebuggerResources.OPTION_NAME_COLORS_INEFF_EN_BREAKPOINT_COLORING_BACKGROUND)
name = DebuggerResources.OPTION_NAME_COLORS_INEFF_EN_BREAKPOINT_COLORING_BACKGROUND
)
private void setIneffectiveEBreakpointMarkerBackground(boolean breakpointColoringBackground) {
for (BreakpointMarkerSets markers : markersByProgram.values()) {
markers.setIneffectiveEnabledColoringBackground(breakpointColoringBackground);
@@ -856,7 +864,8 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
}
@AutoOptionConsumed(
name = DebuggerResources.OPTION_NAME_COLORS_INEFF_DIS_BREAKPOINT_COLORING_BACKGROUND)
name = DebuggerResources.OPTION_NAME_COLORS_INEFF_DIS_BREAKPOINT_COLORING_BACKGROUND
)
private void setIneffectiveDBreakpointMarkerBackground(boolean breakpointColoringBackground) {
for (BreakpointMarkerSets markers : markersByProgram.values()) {
markers.setIneffectiveDisabledColoringBackground(breakpointColoringBackground);
@@ -1089,7 +1098,8 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
actionDisableBreakpoint = new DisableBreakpointAction();
actionClearBreakpoint = new ClearBreakpointAction();
tool.setMenuGroup(new String[] { SetBreakpointAction.NAME }, SetBreakpointAction.GROUP);
tool.setMenuGroup(new String[] { AbstractSetBreakpointAction.NAME },
SetBreakpointAction.GROUP);
}
@Override
@@ -198,7 +198,7 @@ public class DebuggerListingPlugin extends AbstractCodeBrowserPlugin<DebuggerLis
}
@Override
public void locationChanged(CodeViewerProvider provider, ProgramLocation location) {
public void broadcastLocationChanged(CodeViewerProvider provider, ProgramLocation location) {
// TODO: Fix cursor?
// Do not fire ProgramLocationPluginEvent.
if (provider == connectedProvider) {
@@ -207,7 +207,7 @@ public class DebuggerListingPlugin extends AbstractCodeBrowserPlugin<DebuggerLis
}
@Override
public void selectionChanged(CodeViewerProvider provider, ProgramSelection selection) {
public void broadcastSelectionChanged(CodeViewerProvider provider, ProgramSelection selection) {
if (provider != connectedProvider) {
return;
}
@@ -220,7 +220,7 @@ public class DebuggerListingPlugin extends AbstractCodeBrowserPlugin<DebuggerLis
}
@Override
public void highlightChanged(CodeViewerProvider provider, ProgramSelection highlight) {
public void broadcastHighlightChanged(CodeViewerProvider provider, ProgramSelection highlight) {
if (provider != connectedProvider) {
return;
}
@@ -15,7 +15,7 @@
*/
package ghidra.app.plugin.core.debug.gui.listing;
import static ghidra.app.plugin.core.debug.gui.DebuggerResources.ICON_REGISTER_MARKER;
import static ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
import java.awt.BorderLayout;
import java.awt.Color;
@@ -130,13 +130,6 @@ public class DebuggerListingProvider extends CodeViewerProvider {
}
}
protected class MarkerSetChangeListener implements ChangeListener {
@Override
public void stateChanged(ChangeEvent e) {
getListingPanel().getFieldPanel().repaint();
}
}
protected class ForStaticSyncMappingChangeListener
implements DebuggerStaticMappingChangeListener {
@Override
@@ -335,7 +328,6 @@ public class DebuggerListingProvider extends CodeViewerProvider {
protected final JLabel trackingLabel = new JLabel();
protected final MultiBlendedListingBackgroundColorModel colorModel;
protected final MarkerSetChangeListener markerChangeListener = new MarkerSetChangeListener();
protected MarkerServiceBackgroundColorModel markerServiceColorModel;
protected MarkerMarginProvider markerMarginProvider;
protected MarkerOverviewProvider markerOverviewProvider;
@@ -573,28 +565,13 @@ public class DebuggerListingProvider extends CodeViewerProvider {
@AutoServiceConsumed
private void setMarkerService(MarkerService markerService) {
if (this.markerService != null) {
this.markerService.removeChangeListener(markerChangeListener);
removeMarginProvider(markerMarginProvider);
markerMarginProvider = null;
removeOverviewProvider(markerOverviewProvider);
markerOverviewProvider = null;
}
ListingPanel listingPanel = getListingPanel();
listingPanel.setMarkerService(markerService);
removeOldStaticTrackingMarker();
this.markerService = markerService;
createNewStaticTrackingMarker();
updateMarkerServiceColorModel();
if (this.markerService != null && !isMainListing()) {
// NOTE: Connected provider marker listener is taken care of by CodeBrowserPlugin
this.markerService.addChangeListener(markerChangeListener);
}
if (this.markerService != null) {
markerMarginProvider = markerService.createMarginProvider();
addMarginProvider(markerMarginProvider);
markerOverviewProvider = markerService.createOverviewProvider();
addOverviewProvider(markerOverviewProvider);
}
}
@AutoServiceConsumed
@@ -24,7 +24,7 @@ import javax.swing.*;
import docking.action.DockingActionIf;
import ghidra.app.nav.Navigatable;
import ghidra.app.util.viewer.listingpanel.OverviewProvider;
import ghidra.app.util.viewer.listingpanel.ListingOverviewProvider;
import ghidra.app.util.viewer.util.AddressIndexMap;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.listing.Program;
@@ -35,7 +35,7 @@ import ghidra.util.task.SwingUpdateManager;
* Overview bar component. Uses color to indicate various snap-based properties for a program.
* Uses an {@link TimeOverviewColorService} to get the appropriate color for a snaps.
*/
public class TimeOverviewColorComponent extends JPanel implements OverviewProvider {
public class TimeOverviewColorComponent extends JPanel implements ListingOverviewProvider {
private static final Color DEFAULT_COLOR = Color.GRAY;
protected TimeOverviewColorService service;
private Color[] colorsByPixel = new Color[0];
@@ -101,7 +101,7 @@ public class TimeOverviewColorComponent extends JPanel implements OverviewProvid
stop = start;
start = tmp;
}
span = Lifespan.span(start, stop);
span = Lifespan.span(start, stop);
}
plugin.setLifespan(span);
enableDrag = false;
@@ -113,6 +113,11 @@ public class TimeOverviewColorComponent extends JPanel implements OverviewProvid
actions = service.getActions();
}
@Override
public void dispose() {
uninstallActions();
}
/**
* Installs actions for this component
*/
@@ -233,13 +238,13 @@ public class TimeOverviewColorComponent extends JPanel implements OverviewProvid
public Lifespan getLifespan() {
return service.getBounds();
}
public void setLifespan(Lifespan bounds) {
service.setBounds(bounds);
}
@Override
public void setProgram(Program program, AddressIndexMap map) {
public void screenDataChanged(Program program, AddressIndexMap map) {
// Ignored
}
@@ -221,8 +221,8 @@ public class TimeOverviewColorPlugin extends AbstractDebuggerPlugin {
private void uninstallOverview(TimeOverviewColorService overviewColorService) {
TimeOverviewColorComponent overviewComponent = activeServices.get(overviewColorService);
overviewComponent.uninstallActions();
listingService.removeOverviewProvider(overviewComponent);
overviewComponent.dispose();
activeServices.remove(overviewColorService);
overviewColorService.setTrace(null);
}
@@ -97,22 +97,21 @@ public class CodeBrowserPlugin extends AbstractCodeBrowserPlugin<CodeViewerProvi
}
@Override
public void highlightChanged(CodeViewerProvider provider, ProgramSelection highlight) {
MarkerSet highlightMarkers = getHighlightMarkers(currentProgram);
if (highlightMarkers != null) {
highlightMarkers.clearAll();
}
if (highlight != null && currentProgram != null) {
if (highlightMarkers != null) {
highlightMarkers.add(highlight);
}
}
public void broadcastHighlightChanged(CodeViewerProvider provider, ProgramSelection highlight) {
if (provider == connectedProvider) {
tool.firePluginEvent(new ProgramHighlightPluginEvent(getName(), highlight,
connectedProvider.getProgram()));
}
}
@Override
public void broadcastLocationChanged(CodeViewerProvider provider, ProgramLocation location) {
if (provider == connectedProvider) {
tool.firePluginEvent(new ProgramLocationPluginEvent(getName(), location,
connectedProvider.getProgram()));
}
}
@Override
public void processEvent(PluginEvent event) {
if (event instanceof ProgramClosedPluginEvent) {
@@ -125,7 +124,7 @@ public class CodeBrowserPlugin extends AbstractCodeBrowserPlugin<CodeViewerProvi
currentProgram.removeListener(this);
}
ProgramActivatedPluginEvent evt = (ProgramActivatedPluginEvent) event;
clearMarkers(currentProgram); // do this just before changing the program
connectedProvider.clearMarkers(currentProgram); // do this before changing the program
currentProgram = evt.getActiveProgram();
if (currentProgram != null) {
@@ -135,12 +134,13 @@ public class CodeBrowserPlugin extends AbstractCodeBrowserPlugin<CodeViewerProvi
else {
currentView = new AddressSet();
}
connectedProvider.doSetProgram(currentProgram);
updateHighlightProvider();
updateBackgroundColorModel();
setHighlight(new FieldSelection());
setSelection(new ProgramSelection());
connectedProvider.updateHighlightProvider();
updateBackgroundColorModel(connectedProvider);
setConnectedProviderHighlight(new FieldSelection());
setConnectedProviderSelection(new ProgramSelection());
}
else if (event instanceof ProgramLocationPluginEvent) {
ProgramLocationPluginEvent evt = (ProgramLocationPluginEvent) event;
@@ -156,12 +156,12 @@ public class CodeBrowserPlugin extends AbstractCodeBrowserPlugin<CodeViewerProvi
}
else if (event instanceof ProgramSelectionPluginEvent) {
ProgramSelectionPluginEvent evt = (ProgramSelectionPluginEvent) event;
setSelection(evt.getSelection());
setConnectedProviderSelection(evt.getSelection());
}
else if (event instanceof ProgramHighlightPluginEvent) {
ProgramHighlightPluginEvent evt = (ProgramHighlightPluginEvent) event;
if (evt.getProgram() == currentProgram) {
setHighlight(evt.getHighlight());
connectedProvider.setHighlight(evt.getHighlight());
}
}
else if (event instanceof ViewChangedPluginEvent) {
@@ -206,10 +206,13 @@ public class CodeBrowserPlugin extends AbstractCodeBrowserPlugin<CodeViewerProvi
if (location != null) {
connectedProvider.setLocation(location);
}
setHighlight(highlight);
connectedProvider.setHighlight(highlight);
if (selection != null) {
connectedProvider.setSelection(selection);
}
if (vp != null) {
FieldPanel fieldPanel = connectedProvider.getListingPanel().getFieldPanel();
fieldPanel.setViewerPosition(vp.getIndex(), vp.getXOffset(), vp.getYOffset());
@@ -268,7 +271,7 @@ public class CodeBrowserPlugin extends AbstractCodeBrowserPlugin<CodeViewerProvi
FieldSelection highlight = new FieldSelection();
highlight.load(saveState);
if (!highlight.isEmpty()) {
setHighlight(highlight);
setConnectedProviderHighlight(highlight);
}
}
@@ -286,19 +289,6 @@ public class CodeBrowserPlugin extends AbstractCodeBrowserPlugin<CodeViewerProvi
connectedProvider.readState(saveState);
}
@Override
public void locationChanged(CodeViewerProvider provider, ProgramLocation location) {
if (provider == connectedProvider) {
MarkerSet cursorMarkers = getCursorMarkers(currentProgram);
if (cursorMarkers != null) {
cursorMarkers.clearAll();
cursorMarkers.add(location.getAddress());
}
tool.firePluginEvent(new ProgramLocationPluginEvent(getName(), location,
connectedProvider.getProgram()));
}
}
@Override
public ViewManagerService getViewManager(CodeViewerProvider codeViewerProvider) {
if (codeViewerProvider == connectedProvider) {
@@ -1,13 +1,12 @@
/* ###
* 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.
* 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.
@@ -23,22 +22,21 @@ import ghidra.program.util.ProgramSelection;
public interface CodeBrowserPluginInterface {
PluginTool getTool();
public PluginTool getTool();
String getName();
public String getName();
void providerClosed(CodeViewerProvider codeViewerProvider);
public boolean isDisposed();
boolean isDisposed();
public void providerClosed(CodeViewerProvider provider);
void locationChanged(CodeViewerProvider codeViewerProvider, ProgramLocation loc);
public void broadcastLocationChanged(CodeViewerProvider provider, ProgramLocation loc);
void selectionChanged(CodeViewerProvider codeViewerProvider, ProgramSelection currentSelection);
public void broadcastSelectionChanged(CodeViewerProvider provider, ProgramSelection selection);
void highlightChanged(CodeViewerProvider codeViewerProvider, ProgramSelection highlight);
public void broadcastHighlightChanged(CodeViewerProvider provider, ProgramSelection highlight);
ViewManagerService getViewManager(CodeViewerProvider codeViewerProvider);
CodeViewerProvider createNewDisconnectedProvider();
public ViewManagerService getViewManager(CodeViewerProvider provider);
public CodeViewerProvider createNewDisconnectedProvider();
}
@@ -20,7 +20,6 @@ import java.awt.Point;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.*;
@@ -112,7 +111,6 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
liveSelection = selection;
updateSubTitle();
};
private FocusingMouseListener focusingMouseListener;
private CodeBrowserClipboardProvider codeViewerClipboardProvider;
private ClipboardService clipboardService;
@@ -151,6 +149,11 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
setDefaultWindowPosition(WindowPosition.RIGHT);
listingPanel = new ListingPanel(formatMgr);
if (!isConnected) {
// update the marker set names to be unique so that each listing can have its own
listingPanel.setUseMarkerNameSuffix(true);
}
listingPanel.enablePropertyBasedColorModel(true);
decorationPanel = new ListingPanelContainer(listingPanel, isConnected);
@@ -253,6 +256,8 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
public void dispose() {
super.dispose();
clearMarkers(program);
tool.removePopupActionProvider(this);
if (clipboardService != null) {
@@ -324,8 +329,8 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
private Object getContextForMarginPanels(ListingPanel lp, MouseEvent event) {
Object source = event.getSource();
List<MarginProvider> marginProviders = lp.getMarginProviders();
for (MarginProvider marginProvider : marginProviders) {
List<ListingMarginProvider> marginProviders = lp.getMarginProviders();
for (ListingMarginProvider marginProvider : marginProviders) {
JComponent c = marginProvider.getComponent();
if (c == source) {
MarkerLocation loc = marginProvider.getMarkerLocation(event.getX(), event.getY());
@@ -337,8 +342,8 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
}
}
}
List<OverviewProvider> overviewProviders = lp.getOverviewProviders();
for (OverviewProvider overviewProvider : overviewProviders) {
List<ListingOverviewProvider> overviewProviders = lp.getOverviewProviders();
for (ListingOverviewProvider overviewProvider : overviewProviders) {
JComponent c = overviewProvider.getComponent();
if (c == source) {
return source;
@@ -444,6 +449,10 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
contextChanged();
}
void clearMarkers(Program p) {
listingPanel.clearMarkers(p);
}
protected void updateTitle() {
String subTitle = program == null ? "" : ' ' + program.getDomainFile().getName();
String newTitle = TITLE + subTitle;
@@ -657,6 +666,7 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
}
}
// events coming from the ListingPanel
@Override
public void programLocationChanged(ProgramLocation loc, EventTrigger trigger) {
if (plugin.isDisposed()) {
@@ -665,7 +675,7 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
if (!loc.equals(currentLocation)) {
codeViewerClipboardProvider.setLocation(loc);
currentLocation = loc;
plugin.locationChanged(this, loc);
plugin.broadcastLocationChanged(this, loc);
contextChanged();
}
}
@@ -696,7 +706,7 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
currentSelection = selection;
codeViewerClipboardProvider.setSelection(currentSelection);
listingPanel.setSelection(currentSelection);
plugin.selectionChanged(this, currentSelection);
plugin.broadcastSelectionChanged(this, currentSelection);
contextChanged();
updateSubTitle();
}
@@ -792,7 +802,7 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
private void doSetHighlight(ProgramSelection highlight) {
listingPanel.setHighlight(highlight);
currentHighlight = highlight;
plugin.highlightChanged(this, highlight);
plugin.broadcastHighlightChanged(this, highlight);
contextChanged();
}
@@ -1161,45 +1171,51 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
listingPanel.removeDisplayListener(listener);
}
private synchronized void createFocusingMouseListener() {
if (focusingMouseListener == null) {
focusingMouseListener = new FocusingMouseListener();
}
}
public void addOverviewProvider(OverviewProvider overviewProvider) {
createFocusingMouseListener();
JComponent component = overviewProvider.getComponent();
// just in case we get repeated calls
component.removeMouseListener(focusingMouseListener);
component.addMouseListener(focusingMouseListener);
public void addOverviewProvider(ListingOverviewProvider overviewProvider) {
overviewProvider.setNavigatable(this);
getListingPanel().addOverviewProvider(overviewProvider);
}
public void addMarginProvider(MarginProvider marginProvider) {
createFocusingMouseListener();
JComponent component = marginProvider.getComponent();
// just in case we get repeated calls
component.removeMouseListener(focusingMouseListener);
component.addMouseListener(focusingMouseListener);
getListingPanel().addMarginProvider(marginProvider);
}
public void removeOverviewProvider(OverviewProvider overviewProvider) {
JComponent component = overviewProvider.getComponent();
component.removeMouseListener(focusingMouseListener);
public void removeOverviewProvider(ListingOverviewProvider overviewProvider) {
getListingPanel().removeOverviewProvider(overviewProvider);
}
public void removeMarginProvider(MarginProvider marginProvider) {
JComponent component = marginProvider.getComponent();
component.removeMouseListener(focusingMouseListener);
public void addMarginProvider(ListingMarginProvider marginProvider) {
getListingPanel().addMarginProvider(marginProvider);
}
public void removeMarginProvider(ListingMarginProvider marginProvider) {
getListingPanel().removeMarginProvider(marginProvider);
}
public void addMarginService(ListingMarginProviderService service) {
getListingPanel().addMarginService(service, isConnected());
}
public void addOverviewService(ListingOverviewProviderService service) {
getListingPanel().addOverviewService(service, this, isConnected());
}
public void removeOverviewService(ListingOverviewProviderService service) {
getListingPanel().removeOverviewService(service);
}
public void removeMarginService(ListingMarginProviderService service) {
getListingPanel().removeMarginService(service);
}
public void addHoverService(ListingHoverService hoverService) {
getListingPanel().addHoverService(hoverService);
}
public void removeHoverService(ListingHoverService hoverService) {
getListingPanel().removeHoverService(hoverService);
if (otherPanel != null) {
otherPanel.removeHoverService(hoverService);
}
}
//==================================================================================================
// Inner Classes
//==================================================================================================
@@ -1280,11 +1296,4 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
return list.toArray(new Highlight[list.size()]);
}
}
private class FocusingMouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
getListingPanel().getFieldPanel().requestFocus();
}
}
}
@@ -1,13 +1,12 @@
/* ###
* 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.
* 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.
@@ -16,11 +15,11 @@
*/
package ghidra.app.plugin.core.flowarrow;
import java.awt.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.symbol.RefType;
import java.awt.*;
class ConditionalFlowArrow extends FlowArrow {
private static final Stroke CONDITIONAL_STROKE = new BasicStroke(1, BasicStroke.CAP_SQUARE,
@@ -28,9 +27,9 @@ class ConditionalFlowArrow extends FlowArrow {
private static final Stroke NORMAL_ACTIVE_STROKE = new BasicStroke(2, BasicStroke.CAP_SQUARE,
BasicStroke.JOIN_MITER);
ConditionalFlowArrow(FlowArrowPlugin plugin, Component canvas, Address start, Address end,
RefType referenceType) {
super(plugin, canvas, start, end, referenceType);
ConditionalFlowArrow(FlowArrowMarginProvider provider, Component canvas, Address start,
Address end, RefType referenceType) {
super(provider, canvas, start, end, referenceType);
}
@Override
@@ -1,13 +1,12 @@
/* ###
* 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.
* 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.
@@ -16,11 +15,11 @@
*/
package ghidra.app.plugin.core.flowarrow;
import java.awt.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.symbol.RefType;
import java.awt.*;
class DefaultFlowArrow extends FlowArrow {
private static final Stroke NORMAL_STROKE = new BasicStroke(1, BasicStroke.CAP_SQUARE,
@@ -28,9 +27,9 @@ class DefaultFlowArrow extends FlowArrow {
private static final Stroke NORMAL_ACTIVE_STROKE = new BasicStroke(2, BasicStroke.CAP_SQUARE,
BasicStroke.JOIN_MITER);
DefaultFlowArrow(FlowArrowPlugin plugin, Component canvas, Address start, Address end,
DefaultFlowArrow(FlowArrowMarginProvider provider, Component canvas, Address start, Address end,
RefType referenceType) {
super(plugin, canvas, start, end, referenceType);
super(provider, canvas, start, end, referenceType);
}
@Override
@@ -1,13 +1,12 @@
/* ###
* 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.
* 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.
@@ -16,11 +15,11 @@
*/
package ghidra.app.plugin.core.flowarrow;
import java.awt.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.symbol.RefType;
import java.awt.*;
class FallthroughFlowArrow extends FlowArrow {
private static final Stroke FALLTHROUGH_STROKE = new BasicStroke(1, BasicStroke.CAP_SQUARE,
@@ -28,9 +27,9 @@ class FallthroughFlowArrow extends FlowArrow {
private static final Stroke FALLTHROUGH_ACTIVE_STROKE = new BasicStroke(2,
BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10, new float[] { 8, 3, 2, 3 }, 0);
FallthroughFlowArrow(FlowArrowPlugin plugin, Component canvas, Address start, Address end,
RefType referenceType) {
super(plugin, canvas, start, end, referenceType);
FallthroughFlowArrow(FlowArrowMarginProvider provider, Component canvas, Address start,
Address end, RefType referenceType) {
super(provider, canvas, start, end, referenceType);
}
@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.
@@ -15,6 +15,8 @@
*/
package ghidra.app.plugin.core.flowarrow;
import static ghidra.util.HTMLUtilities.*;
import java.awt.*;
import java.awt.geom.PathIterator;
import java.awt.geom.Rectangle2D;
@@ -23,7 +25,6 @@ import java.util.List;
import ghidra.program.model.address.*;
import ghidra.program.model.symbol.RefType;
import ghidra.util.HTMLUtilities;
import ghidra.util.exception.AssertException;
abstract class FlowArrow {
@@ -36,15 +37,16 @@ abstract class FlowArrow {
Address start;
Address end;
AddressSet addressSet;
int depth = -1;
AddressSet addresses;
int column = -1;
RefType refType;
private int maxColumn;
private boolean isUp;
boolean active;
boolean selected;
private FlowArrowPlugin plugin;
private FlowArrowMarginProvider provider;
private Component canvas;
protected Shape arrowBody;
protected Shape arrowHead;
@@ -52,15 +54,16 @@ abstract class FlowArrow {
/** The shape of the arrow body, but with added size */
private List<Shape> clickableShapes = new ArrayList<>();
FlowArrow(FlowArrowPlugin plugin, Component canvas, Address start, Address end,
FlowArrow(FlowArrowMarginProvider provider, Component canvas, Address start, Address end,
RefType referenceType) {
this.plugin = plugin;
this.provider = provider;
this.canvas = canvas;
this.start = start;
this.end = end;
this.refType = referenceType;
this.addressSet = new AddressSet(new AddressRangeImpl(start, end));
isUp = start.compareTo(end) > 0;
this.maxColumn = provider.getMaxColumn();
this.addresses = new AddressSet(new AddressRangeImpl(start, end));
this.isUp = start.compareTo(end) > 0;
}
abstract Stroke getSelectedStroke();
@@ -101,7 +104,7 @@ abstract class FlowArrow {
g2.setStroke(oldStroke);
}
/** True if this arrow points up instead of down */
/** {@return true if this arrow points up instead of down} */
boolean isUp() {
return isUp;
}
@@ -242,20 +245,20 @@ abstract class FlowArrow {
int displayWidth = canvas.getWidth();// - FlowArrowPlugin.LEFT_OFFSET;
int lineWidth = calculateLineWidth(displayWidth);
arrowBody = FlowArrowShapeFactory.createArrowBody(plugin, this, displayWidth, displayHeight,
lineWidth);
arrowBody =
FlowArrowShapeFactory.createArrowBody(provider, this, displayWidth, displayHeight,
lineWidth);
arrowHead = FlowArrowShapeFactory.createArrowHead(plugin, this, displayWidth, displayHeight,
lineWidth);
arrowHead =
FlowArrowShapeFactory.createArrowHead(provider, this, displayWidth, displayHeight,
lineWidth);
}
private int calculateLineWidth(int displayWidth) {
// Crunch or stretch spacing depending upon width and maximum depth
int lineWidth = DEFAULT_LINE_SPACING;
int maxDepth = plugin.getMaxDepth();
if (maxDepth >= 0) {
int availabeWidth = displayWidth - FlowArrowPlugin.LEFT_OFFSET;
if (maxColumn >= 0) {
int availabeWidth = displayWidth - FlowArrowMarginProvider.LEFT_OFFSET;
lineWidth = (int) (availabeWidth * ARROW_SPACING_RATIO);
}
if (lineWidth < MIN_LINE_SPACING) {
@@ -321,9 +324,17 @@ abstract class FlowArrow {
}
public String getDisplayString() {
return "<html><table><tr><td>start</td><td>" + HTMLUtilities.escapeHTML(start.toString()) +
"</td><tr><td>end</td><td>" + HTMLUtilities.escapeHTML(end.toString()) +
"</td><tr><td>ref type</td><td>" + refType + "</td></tr></table>";
//@formatter:off
return """
<html><table>
<tr><td>start</td><td>%s</td></tr>
<tr><td>end</td><td>%s</td></tr>
<tr><td>ref type</td><td>%s</td></tr>
</table>
""".formatted(escapeHTML(start.toString()),
escapeHTML(end.toString()),
refType).trim();
//@formatter:on
}
@Override
@@ -36,7 +36,7 @@ class FlowArrowPanel extends JPanel {
private Cursor clickCursor;
private Cursor defaultCursor;
private FlowArrowPlugin plugin;
private FlowArrowMarginProvider provider;
private Color foregroundColor;
private Color highlightColor;
private Color selectedColor;
@@ -44,8 +44,8 @@ class FlowArrowPanel extends JPanel {
private SwingUpdateManager mouseClickUpdater;
private Point pendingMouseClickPoint;
FlowArrowPanel(FlowArrowPlugin p) {
this.plugin = p;
FlowArrowPanel(FlowArrowMarginProvider provider) {
this.provider = provider;
setMinimumSize(new Dimension(0, 0));
setPreferredSize(new Dimension(32, 1));
@@ -110,18 +110,18 @@ class FlowArrowPanel extends JPanel {
}
private FlowArrow getArrow(Point p) {
FlowArrow arrow = getArrow(p, plugin.getFlowArrowIterator());
FlowArrow arrow = getArrow(p, provider.getFlowArrowIterator());
if (arrow != null) {
return arrow;
}
// try the arrows that hang around a bit
arrow = getArrow(p, plugin.getSelectedFlowArrows());
arrow = getArrow(p, provider.getSelectedFlowArrows());
if (arrow != null) {
return arrow;
}
return getArrow(p, plugin.getActiveArrows());
return getArrow(p, provider.getActiveArrows());
}
private FlowArrow getArrow(Point p, Iterator<FlowArrow> it) {
@@ -139,26 +139,24 @@ class FlowArrowPanel extends JPanel {
return;
}
// TODO to do this, we should probably have another concept of 'navigated'/'current' as to not
// confuse the concept of selecting arrows
// select any arrow we double-click
arrow.selected = true;
plugin.setArrowSelected(arrow, true);
provider.setArrowSelected(arrow, true);
Address end = arrow.end;
if (end.equals(plugin.getCurrentAddress())) {
if (end.equals(provider.getCurrentAddress())) {
// go back the other direction
end = arrow.start;
}
if (plugin.isOnScreen(end)) {
if (provider.isOnScreen(end)) {
// don't animate arrows completely on screen
plugin.goTo(end);
provider.goTo(end);
return;
}
// Start the animation at the edge of the screen
Address start = plugin.getLastAddressOnScreen(end, arrow.isUp());
Address start = provider.getLastAddressOnScreen(end, arrow.isUp());
ScrollingCallback callback = new ScrollingCallback(start, end);
Animator animator = AnimationUtils.executeSwingAnimationCallback(callback);
@@ -169,7 +167,7 @@ class FlowArrowPanel extends JPanel {
FlowArrow arrow = getArrow(point);
if (arrow != null) {
arrow.selected = !arrow.selected; // toggle
plugin.setArrowSelected(arrow, arrow.selected);
provider.setArrowSelected(arrow, arrow.selected);
repaint();
return; // only select one line at a time
}
@@ -179,13 +177,13 @@ class FlowArrowPanel extends JPanel {
public void setBounds(int x, int y, int width, int height) {
// note: this gets called as the user drags the divider pane
super.setBounds(x, y, width, height);
plugin.updateAndRepaint();
provider.updateAndRepaint();
}
@Override
public String getToolTipText(MouseEvent e) {
Point point = e.getPoint();
Iterator<FlowArrow> it = plugin.getFlowArrowIterator();
Iterator<FlowArrow> it = provider.getFlowArrowIterator();
while (it.hasNext()) {
FlowArrow arrow = it.next();
if (arrow.intersects(point)) {
@@ -223,7 +221,7 @@ class FlowArrowPanel extends JPanel {
super.paintComponent(g);
Address currentAddress = plugin.getCurrentAddress();
Address currentAddress = provider.getCurrentAddress();
if (currentAddress == null) {
return;
}
@@ -235,7 +233,7 @@ class FlowArrowPanel extends JPanel {
//
// Non-selected arrows
//
Iterator<FlowArrow> it = plugin.getFlowArrowIterator();
Iterator<FlowArrow> it = provider.getFlowArrowIterator();
while (it.hasNext()) {
FlowArrow arrow = it.next();
if (arrow.active || arrow.selected) {
@@ -251,7 +249,7 @@ class FlowArrowPanel extends JPanel {
//
// Active arrows--those at the selected address; paint on top of normal arrows
//
it = plugin.getActiveArrows();
it = provider.getActiveArrows();
while (it.hasNext()) {
FlowArrow arrow = it.next();
if (arrow.selected) {
@@ -266,7 +264,7 @@ class FlowArrowPanel extends JPanel {
// Selected arrows
//
fgColor = selectedColor;
it = plugin.getSelectedFlowArrows();
it = provider.getSelectedFlowArrows();
while (it.hasNext()) {
FlowArrow arrow = it.next();
paintJump(g2, arrow, fgColor);
@@ -274,7 +272,7 @@ class FlowArrowPanel extends JPanel {
}
private void paintJump(Graphics2D g2, FlowArrow arrow, Color fgColor) {
if (plugin.isOffscreen(arrow)) {
if (provider.isOffscreen(arrow)) {
return; // don't paint linger arrows, such as selected or active arrows
}
@@ -329,19 +327,19 @@ class FlowArrowPanel extends JPanel {
// System.err.printf("%1.3f%%\t", (percentComplete * 100));
// System.err.println("scrolling to: " + current);
plugin.scrollTo(current);
provider.scrollTo(current);
lastAddress = current; // let's us avoid multiple duplicate requests
}
@Override
public void done() {
// set the final position
// TODO This happens after the animation is finished, which is jarring. If we want this centered,
// then we need an entirely different way of animating the transition so that the centering
// is part of the animation.
// Note: This happens after the animation is finished, which is jarring. If we want this centered,
// then we need an entirely different way of animating the transition so that the centering
// is part of the animation.
// plugin.scrollToCenter(end);
plugin.goTo(end);
provider.goTo(end);
}
void setAnimator(Animator animator) {
@@ -392,7 +390,7 @@ class FlowArrowPanel extends JPanel {
private class FlowArrowPanelMouseWheelListener implements MouseWheelListener {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
plugin.forwardMouseEventToListing(e);
provider.forwardMouseEventToListing(e);
}
}
@@ -1,13 +1,12 @@
/* ###
* 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.
* 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.
@@ -28,26 +27,27 @@ class FlowArrowShapeFactory {
private static final int TRIANGLE_HEIGHT = 9;
private static final int TRIANGLE_WIDTH = 7;
static Shape createArrowBody(FlowArrowPlugin plugin, FlowArrow arrow, int width, int height,
static Shape createArrowBody(FlowArrowMarginProvider provider, FlowArrow arrow, int width,
int height,
int lineSpacing) {
GeneralPath linePath = new GeneralPath();
// Compute the start Y coordinate (place at proper offset, fix if off screen)
Integer startTop = plugin.getStartPos(arrow.start);
Integer startBottom = plugin.getEndPos(arrow.start);
Integer startTop = provider.getStartPos(arrow.start);
Integer startBottom = provider.getEndPos(arrow.start);
int startY = 0;
if (startTop != null && startBottom != null) {
int start = startTop;
int end = startBottom;
startY = (start + end) / 2;// middle of line
}
else if (plugin.isBelowScreen(arrow.start)) {
else if (provider.isBelowScreen(arrow.start)) {
startY = height;
}
Integer endTop = plugin.getStartPos(arrow.end);
Integer endBottom = plugin.getEndPos(arrow.end);
Integer endTop = provider.getStartPos(arrow.end);
Integer endBottom = provider.getEndPos(arrow.end);
int endY = 0;
if (endTop != null && endBottom != null) {
int start = endTop;
@@ -55,11 +55,11 @@ class FlowArrowShapeFactory {
endY = (start + end) / 2;
endY = Math.min(endY, height); // ensure on screen
}
else if (plugin.isBelowScreen(arrow.end)) {
else if (provider.isBelowScreen(arrow.end)) {
endY = height;
}
int x = width - ((arrow.depth + 1) * lineSpacing);
int x = width - ((arrow.column + 1) * lineSpacing);
if (x < 3) {
x = 3;
}
@@ -126,12 +126,13 @@ class FlowArrowShapeFactory {
return linePath;
}
static Shape createArrowHead(FlowArrowPlugin plugin, FlowArrow arrow, int width, int height,
static Shape createArrowHead(FlowArrowMarginProvider provider, FlowArrow arrow, int width,
int height,
int lineSpacing) {
// Compute the start Y coordinate (place at proper offset, fix if off screen)
Integer addrStartInt = plugin.getStartPos(arrow.end);
Integer addrEndInt = plugin.getEndPos(arrow.end);
Integer addrStartInt = provider.getStartPos(arrow.end);
Integer addrEndInt = provider.getEndPos(arrow.end);
int endY = 0;
if (addrStartInt != null && addrEndInt != null) {
int start = addrStartInt;
@@ -139,11 +140,11 @@ class FlowArrowShapeFactory {
endY = (start + end) / 2;
endY = Math.min(endY, height); // ensure on screen
}
else if (plugin.isBelowScreen(arrow.end)) {
else if (provider.isBelowScreen(arrow.end)) {
endY = height;
}
int x = width - ((arrow.depth + 1) * lineSpacing);
int x = width - ((arrow.column + 1) * lineSpacing);
if (x < 0) {
x = 3;
}
@@ -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.
@@ -40,6 +40,7 @@ import ghidra.program.model.address.AddressSet;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
import ghidra.util.ColorUtils.ColorBlender;
import ghidra.util.UniversalID;
import ghidra.util.datastruct.*;
import ghidra.util.exception.AssertException;
import ghidra.util.task.SwingUpdateManager;
@@ -70,11 +71,9 @@ public class MarkerManager implements MarkerService {
private SwingUpdateManager updater;
private GoToService goToService;
private MarkerMarginProvider primaryMarginProvider;
private WeakSet<MarkerMarginProvider> marginProviders =
WeakDataStructureFactory.createCopyOnWriteWeakSet();
private MarkerOverviewProvider primaryOverviewProvider;
private WeakSet<MarkerOverviewProvider> overviewProviders =
WeakDataStructureFactory.createCopyOnWriteWeakSet();
@@ -101,9 +100,6 @@ public class MarkerManager implements MarkerService {
notifyListeners();
});
primaryMarginProvider = createMarginProvider();
primaryOverviewProvider = createOverviewProvider();
Gui.addThemeListener(themeListener);
}
@@ -220,8 +216,12 @@ public class MarkerManager implements MarkerService {
}
public MarkerMarginProvider getMarginProvider() {
return primaryMarginProvider;
public boolean contains(ListingMarginProvider provider) {
return marginProviders.contains(provider);
}
public boolean contains(ListingOverviewProvider provider) {
return overviewProviders.contains(provider);
}
@Override
@@ -231,8 +231,8 @@ public class MarkerManager implements MarkerService {
return provider;
}
public OverviewProvider getOverviewProvider() {
return primaryOverviewProvider;
public void removeProvider(MarkerMarginProvider provider) {
marginProviders.remove(provider);
}
@Override
@@ -246,7 +246,6 @@ public class MarkerManager implements MarkerService {
Gui.removeThemeListener(themeListener);
updater.dispose();
markerSetCache.clear();
overviewProviders.forEach(provider -> provider.dispose());
}
void navigateTo(Navigatable navigatable, Program program, int x, int y, int viewHeight,
@@ -276,13 +275,13 @@ public class MarkerManager implements MarkerService {
entry.paintNavigation(g, panel.getViewHeight(), panel.getWidth(), addrMap);
}
void paintMarkers(Program program, Graphics g, VerticalPixelAddressMap pixmap,
AddressIndexMap addrMap) {
void paintMarkers(UniversalID ownerId, Program program, Graphics g,
VerticalPixelAddressMap pixMap, AddressIndexMap addrMap) {
MarkerSetCacheEntry entry = markerSetCache.get(program);
if (entry == null) {
return;
}
entry.paintMarkers(g, pixmap, addrMap);
entry.paintMarkers(ownerId, g, pixMap, addrMap);
}
void showToolTipPopup(MouseEvent event, String tip) {
@@ -301,10 +300,6 @@ public class MarkerManager implements MarkerService {
popupWindow.showPopup(event);
}
/*testing*/ String generateToolTip(MouseEvent event) {
return primaryMarginProvider.generateToolTip(event);
}
List<String> getMarkerTooltipLines(Program program, int y, int x, Address minAddr,
Address maxAddr) {
MarkerSetCacheEntry entry = markerSetCache.get(program);
@@ -484,6 +479,7 @@ public class MarkerManager implements MarkerService {
if (program == null || program.isClosed()) {
return null;
}
MarkerSetCacheEntry entry = map.computeIfAbsent(program, this::newEntry);
if (program.isClosed()) {
map.remove(program);
@@ -571,13 +567,22 @@ public class MarkerManager implements MarkerService {
}
}
void paintMarkers(Graphics g, VerticalPixelAddressMap pixmap, AddressIndexMap addrMap) {
void paintMarkers(UniversalID ownerId, Graphics g, VerticalPixelAddressMap pixMap,
AddressIndexMap addrMap) {
int count = 0;
for (MarkerSetImpl markers : markerSets) {
count++;
if (markers.active) {
markers.paintMarkers(g, count++, pixmap, addrMap);
if (!markers.active) {
continue;
}
UniversalID markerId = markers.getOwnerId();
if (markerId != null && markerId != ownerId) {
// a non-global marker that does not match the owner being painted
continue;
}
markers.paintMarkers(g, count++, pixMap, addrMap);
}
}
@@ -638,4 +643,5 @@ public class MarkerManager implements MarkerService {
return new ArrayList<>(markerSets);
}
}
}
@@ -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.
@@ -20,6 +20,8 @@ import ghidra.app.CorePluginPackage;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.services.*;
import ghidra.app.util.HelpTopics;
import ghidra.app.util.viewer.listingpanel.ListingMarginProvider;
import ghidra.app.util.viewer.listingpanel.ListingOverviewProvider;
import ghidra.framework.options.Options;
import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.PluginStatus;
@@ -39,17 +41,17 @@ import ghidra.util.HelpLocation;
"supported; point markers and area markers. Area markers are used to indicate a range " +
"value such as selection. Point markers are used to represent individual addresses such " +
"as bookmarks.",
servicesRequired = { CodeViewerService.class, GoToService.class },
servicesProvided = { MarkerService.class },
servicesRequired = { GoToService.class },
servicesProvided = { MarkerService.class, ListingMarginProviderService.class, ListingOverviewProviderService.class },
eventsConsumed = {}
)
//@formatter:on
/**
* Plugin to manage marker and navigation panels.
*/
public class MarkerManagerPlugin extends Plugin {
public class MarkerManagerPlugin extends Plugin
implements ListingMarginProviderService, ListingOverviewProviderService {
private CodeViewerService codeViewerService;
private MarkerManager markerManager;
public MarkerManagerPlugin(PluginTool tool) {
@@ -65,17 +67,26 @@ public class MarkerManagerPlugin extends Plugin {
@Override
protected void dispose() {
if (codeViewerService != null) {
codeViewerService.removeMarginProvider(markerManager.getMarginProvider());
codeViewerService.removeOverviewProvider(markerManager.getOverviewProvider());
}
markerManager.dispose();
}
@Override
protected void init() {
codeViewerService = tool.getService(CodeViewerService.class);
codeViewerService.addMarginProvider(markerManager.getMarginProvider());
codeViewerService.addOverviewProvider(markerManager.getOverviewProvider());
public ListingMarginProvider createMarginProvider() {
return markerManager.createMarginProvider();
}
@Override
public boolean isOwner(ListingMarginProvider provider) {
return markerManager.contains(provider);
}
@Override
public ListingOverviewProvider createOverviewProvider() {
return markerManager.createOverviewProvider();
}
@Override
public boolean isOwner(ListingOverviewProvider provider) {
return markerManager.contains(provider);
}
}
@@ -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.
@@ -28,6 +28,8 @@ import ghidra.app.util.viewer.util.AddressIndexMap;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.util.MarkerLocation;
import ghidra.program.util.ProgramLocation;
import ghidra.util.UniversalID;
/**
* The provider which renders the marker margin, usually placed to the left of listing
@@ -37,7 +39,7 @@ import ghidra.program.util.MarkerLocation;
* These are managed by a {@link MarkerManager}. Obtain one via
* {@link MarkerService#createMarginProvider()}.
*/
public class MarkerMarginProvider implements MarginProvider {
public class MarkerMarginProvider implements ListingMarginProvider {
private final MarkerManager markerManager;
private final MarkerPanel markerPanel;
@@ -62,6 +64,22 @@ public class MarkerMarginProvider implements MarginProvider {
});
}
@Override
public void setOwnerId(UniversalID ownerId) {
markerPanel.setOwnerId(ownerId);
}
@Override
public void setLocation(ProgramLocation location) {
// we don't use locations
}
@Override
public void dispose() {
markerManager.removeProvider(this);
markerPanel.dispose();
}
void repaintPanel() {
markerPanel.repaint();
}
@@ -95,12 +113,11 @@ public class MarkerMarginProvider implements MarginProvider {
}
@Override
public void setProgram(Program program, AddressIndexMap addrMap,
VerticalPixelAddressMap pixmap) {
this.program = program;
this.pixmap = pixmap;
this.markerPanel.setProgram(program, addrMap, pixmap);
public void screenDataChanged(ListingPanel listing, AddressIndexMap addrMap,
VerticalPixelAddressMap pixMap) {
this.program = listing.getProgram();
this.pixmap = pixMap;
this.markerPanel.listingUpdated(listing, addrMap, pixMap);
markerManager.updateMarkerSets(program, true, false, true);
}
@@ -30,7 +30,7 @@ import ghidra.GhidraOptions;
import ghidra.app.nav.Navigatable;
import ghidra.app.services.MarkerService;
import ghidra.app.util.HelpTopics;
import ghidra.app.util.viewer.listingpanel.OverviewProvider;
import ghidra.app.util.viewer.listingpanel.ListingOverviewProvider;
import ghidra.app.util.viewer.util.AddressIndexMap;
import ghidra.framework.options.*;
import ghidra.framework.plugintool.PluginTool;
@@ -46,7 +46,7 @@ import ghidra.util.Swing;
* These are managed by a {@link MarkerManager}. Obtain one via
* {@link MarkerService#createOverviewProvider()}.
*/
public class MarkerOverviewProvider implements OverviewProvider {
public class MarkerOverviewProvider implements ListingOverviewProvider {
private final PluginTool tool;
private final String owner;
@@ -74,7 +74,8 @@ public class MarkerOverviewProvider implements OverviewProvider {
actionList = new MarkerActionList();
}
void dispose() {
@Override
public void dispose() {
actionList.dispose();
}
@@ -88,11 +89,11 @@ public class MarkerOverviewProvider implements OverviewProvider {
}
@Override
public void setProgram(Program program, AddressIndexMap map) {
this.program = program;
public void screenDataChanged(Program p, AddressIndexMap addressMap) {
this.program = p;
navigationPanel.setProgram(program, map);
markerManager.updateMarkerSets(program, true, true, false);
navigationPanel.setProgram(p, addressMap);
markerManager.updateMarkerSets(p, true, true, false);
actionList.refresh();
}
@@ -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.
@@ -24,10 +24,12 @@ import javax.swing.JPanel;
import javax.swing.ToolTipManager;
import docking.widgets.fieldpanel.FieldPanel;
import ghidra.app.util.viewer.listingpanel.ListingPanel;
import ghidra.app.util.viewer.listingpanel.VerticalPixelAddressMap;
import ghidra.app.util.viewer.util.AddressIndexMap;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.util.UniversalID;
/**
* Panel to display markers. Normally placed to the left hand side of the scrolled
@@ -36,29 +38,40 @@ import ghidra.program.model.listing.Program;
public class MarkerPanel extends JPanel {
private MarkerManager manager;
private Program program;
private AddressIndexMap addrMap;
private VerticalPixelAddressMap pixmap;
private VerticalPixelAddressMap pixMap;
private UniversalID ownerId;
MarkerPanel(MarkerManager manager) {
super();
this.manager = manager;
this.setPreferredSize(new Dimension(16, 1));
ToolTipManager.sharedInstance().registerComponent(this);
}
void setProgram(Program program, AddressIndexMap addrMap, VerticalPixelAddressMap pixmap) {
this.program = program;
this.addrMap = addrMap;
this.pixmap = pixmap;
void setOwnerId(UniversalID ownerId) {
this.ownerId = ownerId;
}
void dispose() {
this.program = null;
this.addrMap = null;
this.pixMap = null;
ToolTipManager.sharedInstance().unregisterComponent(this);
}
void listingUpdated(ListingPanel listingPanel, AddressIndexMap addressMap,
VerticalPixelAddressMap pixelMap) {
this.program = listingPanel.getProgram();
this.addrMap = addressMap;
this.pixMap = pixelMap;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
manager.paintMarkers(program, g, pixmap, addrMap);
manager.paintMarkers(ownerId, program, g, pixMap, addrMap);
}
@Override
@@ -81,14 +94,14 @@ public class MarkerPanel extends JPanel {
}
String generateToolTip(MouseEvent event) {
if (pixmap == null) {
if (pixMap == null) {
return null;
}
int y = event.getY();
int x = event.getX();
int layoutIndex = pixmap.findLayoutAt(y);
Address layoutAddress = pixmap.getLayoutAddress(layoutIndex);
int layoutIndex = pixMap.findLayoutAt(y);
Address layoutAddress = pixMap.getLayoutAddress(layoutIndex);
if (layoutAddress == null) {
return null;
}
@@ -99,7 +112,8 @@ public class MarkerPanel extends JPanel {
private List<String> getMarkerTooltipLines(int y, int x, int layoutIndex,
Address layoutAddress) {
Address endAddr = pixmap.getLayoutEndAddress(layoutIndex);
Address endAddr = pixMap.getLayoutEndAddress(layoutIndex);
return manager.getMarkerTooltipLines(program, y, layoutIndex, layoutAddress, endAddr);
}
}
@@ -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.
@@ -35,8 +35,7 @@ import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.program.util.MarkerLocation;
import ghidra.program.util.ProgramLocation;
import ghidra.util.ColorUtils;
import ghidra.util.Swing;
import ghidra.util.*;
import ghidra.util.datastruct.SortedRangeList;
abstract class MarkerSetImpl implements MarkerSet {
@@ -52,7 +51,7 @@ abstract class MarkerSetImpl implements MarkerSet {
protected AddressSetCollection markers;
protected SortedRangeList overview = null;
protected VerticalPixelAddressMap activePixmap = null;
protected VerticalPixelAddressMap activePixMap = null;
protected List<Integer> activeLayouts = null;
protected Color markerColor;
@@ -72,9 +71,11 @@ abstract class MarkerSetImpl implements MarkerSet {
private boolean colorBackground;
private boolean isPreferred;
/** Optional owner ID. A null ID implies a global marker set. */
private UniversalID ownerId;
MarkerSetImpl(MarkerManager mgr, Program program, String name, String desc, int priority,
boolean showMarkers,
boolean showNavigation, boolean colorBackground, Color markerColor,
boolean showMarkers, boolean showNavigation, boolean colorBackground, Color markerColor,
boolean isPreferred) {
this.mgr = mgr;
@@ -93,6 +94,16 @@ abstract class MarkerSetImpl implements MarkerSet {
markers = new ModifiableAddressSetCollection();
}
@Override
public void setOwnerId(UniversalID ownerId) {
this.ownerId = ownerId;
}
@Override
public UniversalID getOwnerId() {
return ownerId;
}
protected abstract void doPaintMarkers(Graphics g, VerticalPixelAddressMap pixmap, int index,
AddressIndexMap map, List<Integer> layouts);
@@ -244,11 +255,11 @@ abstract class MarkerSetImpl implements MarkerSet {
}
}
public final void paintMarkers(Graphics g, int index, VerticalPixelAddressMap pixmap,
public final void paintMarkers(Graphics g, int index, VerticalPixelAddressMap pixMap,
AddressIndexMap map) {
if (showMarkers) {
List<Integer> layouts = computeActiveLayouts(pixmap, map);
doPaintMarkers(g, pixmap, index, map, layouts);
List<Integer> layouts = computeActiveLayouts(pixMap, map);
doPaintMarkers(g, pixMap, index, map, layouts);
}
}
@@ -289,32 +300,32 @@ abstract class MarkerSetImpl implements MarkerSet {
return markers.contains(addr);
}
private List<Integer> computeActiveLayouts(VerticalPixelAddressMap pixmap,
private List<Integer> computeActiveLayouts(VerticalPixelAddressMap pixMap,
AddressIndexMap map) {
if (pixmap == null) {
if (pixMap == null) {
return null;
}
if (activeLayouts != null && activePixmap == pixmap) {
if (activeLayouts != null && activePixMap == pixMap) {
return activeLayouts; // use cache
}
List<Integer> newLayouts = new ArrayList<>();
int n = pixmap.getNumLayouts();
int n = pixMap.getNumLayouts();
for (int i = 0; i < n; i++) {
Address addr = pixmap.getLayoutAddress(i);
Address addr = pixMap.getLayoutAddress(i);
if (addr == null) {
continue;
}
Address end = pixmap.getLayoutEndAddress(i);
Address end = pixMap.getLayoutEndAddress(i);
if (markers.intersects(addr, end)) {
newLayouts.add(i);
}
}
activePixmap = pixmap;
activePixMap = pixMap;
activeLayouts = newLayouts;
return newLayouts;
}
@@ -536,6 +547,6 @@ abstract class MarkerSetImpl implements MarkerSet {
@Override
public String toString() {
return Json.toString(this, "active", "colorBackground", "markers");
return Json.toString(this, "name", "active", "colorBackground", "markers");
}
}
@@ -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.
@@ -95,7 +95,7 @@ class PointMarkerSet extends MarkerSetImpl {
}
@Override
protected void doPaintMarkers(Graphics g, VerticalPixelAddressMap pixmap, int index,
protected void doPaintMarkers(Graphics g, VerticalPixelAddressMap pixMap, int index,
AddressIndexMap map, List<Integer> layouts) {
if (layouts == null) {
@@ -105,20 +105,20 @@ class PointMarkerSet extends MarkerSetImpl {
Iterator<Integer> it = layouts.iterator();
while (it.hasNext()) {
int i = it.next().intValue();
int yStart = pixmap.getMarkPosition(i);
int yStart = pixMap.getMarkPosition(i);
Image curImage = getMarkerImage(pixmap, i, yStart);
Image curImage = getMarkerImage(pixMap, i, yStart);
g.drawImage(curImage, 0, yStart, imageObserver);
}
}
private Image getMarkerImage(VerticalPixelAddressMap pixmap, int i, int yStart) {
private Image getMarkerImage(VerticalPixelAddressMap pixMap, int i, int yStart) {
if (markerDescriptor == null) {
return image;
}
Address address = pixmap.getLayoutAddress(i);
Address address = pixMap.getLayoutAddress(i);
MarkerLocation loc = new MarkerLocation(this, program, address, 0, yStart);
ImageIcon icon = markerDescriptor.getIcon(loc);
if (icon != 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.
@@ -28,7 +28,7 @@ import docking.action.DockingActionIf;
import generic.theme.GColor;
import ghidra.app.nav.Navigatable;
import ghidra.app.services.GoToService;
import ghidra.app.util.viewer.listingpanel.OverviewProvider;
import ghidra.app.util.viewer.listingpanel.ListingOverviewProvider;
import ghidra.app.util.viewer.util.AddressIndexMap;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address;
@@ -40,13 +40,13 @@ import help.Help;
* Overview bar component. Uses color to indicate various address based properties for a program.
* Uses an {@link OverviewColorService} to get the appropriate color for an address.
*/
public class OverviewColorComponent extends JPanel implements OverviewProvider {
public class OverviewColorComponent extends JPanel implements ListingOverviewProvider {
private static final Color DEFAULT_COLOR = new GColor("color.bg.plugin.overview.defalt");
private OverviewColorService service;
private Color[] colors = new Color[0];
private final SwingUpdateManager refreshUpdater =
new SwingUpdateManager(100, 15000, () -> doRefresh());
private AddressIndexMap map;
private AddressIndexMap addressMap;
private Navigatable navigatable;
private PluginTool tool;
private List<DockingActionIf> actions;
@@ -76,6 +76,12 @@ public class OverviewColorComponent extends JPanel implements OverviewProvider {
actions = service.getActions();
}
@Override
public void dispose() {
service = null;
ToolTipManager.sharedInstance().unregisterComponent(this);
}
/**
* Installs actions for this component
*/
@@ -154,10 +160,10 @@ public class OverviewColorComponent extends JPanel implements OverviewProvider {
}
private void doRefresh() {
if (map == null) {
if (addressMap == null) {
return;
}
BigInteger indexCount = map.getIndexCount();
BigInteger indexCount = addressMap.getIndexCount();
if (indexCount.equals(BigInteger.ZERO)) {
Arrays.fill(colors, DEFAULT_COLOR);
repaint();
@@ -168,7 +174,7 @@ public class OverviewColorComponent extends JPanel implements OverviewProvider {
for (int i = 0; i < colors.length; i++) {
if (colors[i] == null) {
BigInteger index = indexCount.multiply(BigInteger.valueOf(i)).divide(bigTotal);
Address address = map.getAddress(index);
Address address = addressMap.getAddress(index);
colors[i] = service.getColor(address);
}
}
@@ -178,17 +184,17 @@ public class OverviewColorComponent extends JPanel implements OverviewProvider {
private Address getAddress(int pixelIndex) {
BigInteger bigHeight = BigInteger.valueOf(getOverviewPixelCount());
BigInteger bigPixelIndex = BigInteger.valueOf(pixelIndex);
BigInteger bigIndex = map.getIndexCount().multiply(bigPixelIndex).divide(bigHeight);
return map.getAddress(bigIndex);
BigInteger bigIndex = addressMap.getIndexCount().multiply(bigPixelIndex).divide(bigHeight);
return addressMap.getAddress(bigIndex);
}
private int getPixelIndex(Address address) {
BigInteger addressIndex = map.getIndex(address);
BigInteger addressIndex = addressMap.getIndex(address);
if (addressIndex == null) {
return -1;
}
BigInteger bigHeight = BigInteger.valueOf(getOverviewPixelCount());
BigInteger indexCount = map.getIndexCount();
BigInteger indexCount = addressMap.getIndexCount();
return addressIndex.multiply(bigHeight).divide(indexCount).intValue();
}
@@ -198,10 +204,10 @@ public class OverviewColorComponent extends JPanel implements OverviewProvider {
}
@Override
public void setProgram(Program program, AddressIndexMap map) {
this.map = map;
colors = new Color[getOverviewPixelCount()];
refreshUpdater.updateLater();
public void screenDataChanged(Program program, AddressIndexMap map) {
this.addressMap = map;
this.colors = new Color[getOverviewPixelCount()];
this.refreshUpdater.updateLater();
}
@Override
@@ -248,5 +254,4 @@ public class OverviewColorComponent extends JPanel implements OverviewProvider {
public PluginTool getTool() {
return tool;
}
}
@@ -92,5 +92,4 @@ public interface OverviewColorService extends ExtensionPoint {
* @return the current program used by the service.
*/
public Program getProgram();
}
@@ -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.
@@ -143,6 +143,8 @@ public class AddressTypeOverviewColorService
@Override
public void setOverviewComponent(OverviewColorComponent component) {
this.overviewComponent = component;
this.overviewComponent.getAccessibleContext()
.setAccessibleName("Address Type Overview Component");
}
/**
@@ -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.
@@ -33,6 +33,7 @@ import ghidra.app.CorePluginPackage;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin;
import ghidra.app.services.CodeViewerService;
import ghidra.app.util.viewer.listingpanel.ListingPanel;
import ghidra.app.util.viewer.util.AddressIndexMap;
import ghidra.framework.plugintool.PluginInfo;
import ghidra.framework.plugintool.PluginTool;
@@ -147,7 +148,10 @@ public class PrintingPlugin extends ProgramPlugin {
format = job.defaultPage();
}
LayoutModel lm = cvService.getFieldPanel().getLayoutModel();
ListingPanel listingPanel = cvService.getListingPanel();
FieldPanel fp = listingPanel.getFieldPanel();
LayoutModel lm = fp.getLayoutModel();
//Scale everything down if appropriate to fit on the page
double scaleAmount =
format.getImageableWidth() / lm.getPreferredViewSize().width;
@@ -316,7 +320,8 @@ public class PrintingPlugin extends ProgramPlugin {
private void printVisibleContent(TaskMonitor monitor, Date startDate,
PrinterJob job, Book book, LayoutModel lm, double scaleAmount,
int maxPageHeight) {
FieldPanel fp = cvService.getFieldPanel();
ListingPanel listingPanel = cvService.getListingPanel();
FieldPanel fp = listingPanel.getFieldPanel();
List<AnchoredLayout> visibleLayouts = fp.getVisibleLayouts();
BigInteger startIndex = visibleLayouts.get(0).getIndex();
BigInteger endIndex = visibleLayouts.get(visibleLayouts.size() - 1).getIndex();
@@ -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.
@@ -34,39 +34,48 @@ import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
/**
* Service provided by a plugin that shows the listing from a Program, i.e., a
* Code Viewer. The service allows other plugins to add components and
* actions local to the Code Viewer.
*
*
* Service provided by a plugin that shows the Code Viewer listing for a Program. The service
* allows other plugins to add components and actions local to the Code Viewer.
*/
@ServiceInfo(defaultProvider = CodeBrowserPlugin.class)
public interface CodeViewerService {
/**
* Add a provider that shows an overview of the program.
* <p>
* Note: the provider passed here will only appear in the primary code viewer, not in any of the
* snapshot windows. to have an overview provider appear in all windows, you must create a
* {@link ListingOverviewProviderService} implementation instead of using this method.
*
* @param overviewProvider provider to add
*/
public void addOverviewProvider(OverviewProvider overviewProvider);
public void addOverviewProvider(ListingOverviewProvider overviewProvider);
/**
* Remove a provider that shows an overview of the program.
* @param overviewProvider provider to remove
* @see CodeViewerService#addOverviewProvider(ListingOverviewProvider)
*/
public void removeOverviewProvider(OverviewProvider overviewProvider);
public void removeOverviewProvider(ListingOverviewProvider overviewProvider);
/**
* Add a provider that shows markers in a program for the portion
* that is visible.
* @param marginProvider provider to add
* @deprecated clients that wish to be margin providers should now create a
* {@link ListingMarginProviderService}.
*/
public void addMarginProvider(MarginProvider marginProvider);
@Deprecated(since = "12.1", forRemoval = true)
public void addMarginProvider(ListingMarginProvider marginProvider);
/**
* Remove a provider that shows markers in a program for the portion
* that is visible.
* @param marginProvider provider to remove
* @deprecated clients that wish to be margin providers should now create a
* {@link ListingMarginProviderService}.
*/
public void removeMarginProvider(MarginProvider marginProvider);
@Deprecated(since = "12.1", forRemoval = true)
public void removeMarginProvider(ListingMarginProvider marginProvider);
/**
* Add an action that is local to the Code Viewer.
@@ -88,13 +97,13 @@ public interface CodeViewerService {
/**
* Add a listener that is notified when a mouse button is pressed.
* @param listener
* @param listener the listener
*/
public void addButtonPressedListener(ButtonPressedListener listener);
/**
* Remove the button pressed listener.
* @param listener
* @param listener the listener
*/
public void removeButtonPressedListener(ButtonPressedListener listener);
@@ -114,7 +123,8 @@ public interface CodeViewerService {
public void removeHighlightProvider(ListingHighlightProvider provider, Program program);
/**
* Set a listing panel on the code viewer.
* Set a listing panel on the code viewer. The given listing panel is a secondary listing panel
* to be displayed along with the primary listing panel.
* @param listingPanel the panel to add.
*/
public void setListingPanel(ListingPanel listingPanel);
@@ -127,11 +137,12 @@ public interface CodeViewerService {
/**
* Remove the given listing panel from the code viewer.
* @param listingPanel the listing panel
*/
public void removeListingPanel(ListingPanel listingPanel);
/**
* Get Current view that the CodeViewer is showing.
* @return the current set of addresses that the CodeViewer is showing.}
*/
public AddressSetView getView();
@@ -145,15 +156,21 @@ public interface CodeViewerService {
public boolean goTo(ProgramLocation loc, boolean centerOnScreen);
/**
* Return the fieldPanel.
* Returns the current field panel.
* @return the current field panel.
* @deprecated use {@link #getListingPanel()} to get the field panel
*/
@Deprecated(since = "12.1", forRemoval = true)
public FieldPanel getFieldPanel();
/**
* Returns the current address-index-map
* {@return the current address index map.}
*/
public AddressIndexMap getAddressIndexMap();
/**
* {@return the format manager.}
*/
public FormatManager getFormatManager();
/**
@@ -0,0 +1,37 @@
/* ###
* 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.services;
import ghidra.app.util.viewer.listingpanel.ListingMarginProvider;
/**
* A service to provide a widget that is designed to appear on the left-hand side of the Code Viewer
*/
public interface ListingMarginProviderService {
/**
* Creates a new margin provider.
* @return the provider
*/
public ListingMarginProvider createMarginProvider();
/**
* True if this service is the owner of the given provider.
* @param provider the provider to check
* @return true if the owner
*/
public boolean isOwner(ListingMarginProvider provider);
}
@@ -0,0 +1,34 @@
/* ###
* 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.services;
import ghidra.app.util.viewer.listingpanel.ListingOverviewProvider;
public interface ListingOverviewProviderService {
/**
* Creates a new overview provider.
* @return the provider
*/
public ListingOverviewProvider createOverviewProvider();
/**
* True if this service is the owner of the given provider.
* @param provider the provider to check
* @return true if the owner
*/
public boolean isOwner(ListingOverviewProvider provider);
}
@@ -18,6 +18,7 @@ package ghidra.app.services;
import java.awt.Color;
import ghidra.program.model.address.*;
import ghidra.util.UniversalID;
/**
* Defines methods for working with a set of addresses that correspond to markers.
@@ -25,6 +26,19 @@ import ghidra.program.model.address.*;
*/
public interface MarkerSet extends Comparable<MarkerSet> {
/**
* Sets an optional owner ID that signals when this marker set should be painted. A null ID
* means that this marker set is global and should always be painted. Otherwise, this marker
* set will be painted when its owner ID matches the owner ID being painted.
* @param ownerId the ID
*/
public void setOwnerId(UniversalID ownerId);
/**
* {@return the owner ID. See #setOwner(UniversalID).}
*/
public UniversalID getOwnerId();
/**
* Add a marker at the address
* @param addr the address
@@ -151,8 +165,9 @@ public interface MarkerSet extends Comparable<MarkerSet> {
public void setMarkerColor(Color color);
/**
* Set the marker manager listener to use for user interaction
* with markers owned by this manager.
* Set the marker set descriptor. This allows clients to control tooltip text and program
* location generation for individual markers on-the-fly.
*
* @param markerDescriptor the descriptor
*/
public void setMarkerDescriptor(MarkerDescriptor markerDescriptor);
@@ -965,7 +965,7 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
* A library that has not been processed by the loader yet
*
* @param name The name of the library
* @param depth The recursive load depth of the library (based on the original binary being
* @param column The recursive load depth of the library (based on the original binary being
* loaded)
* @param temporary True if the library is temporary and should be discarded prior to returning
* from the load
@@ -0,0 +1,88 @@
/* ###
* 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.util.viewer.listingpanel;
import javax.swing.JComponent;
import ghidra.app.util.viewer.util.AddressIndexMap;
import ghidra.program.util.MarkerLocation;
import ghidra.program.util.ProgramLocation;
import ghidra.util.UniversalID;
/**
* Interface for objects that want to add a component to the listing's left margin.
*/
public interface ListingMarginProvider {
/**
* Sets the optional owner ID to be used with this margin provider. Implementations may use
* this ID to determine when they should paint.
* @param ownerId the ID
*/
/**
* Sets an optional owner ID that signals when the markers for this provider should be painted.
* A null ID means that this provider is a non-snapshot provider and should paint all markers.
* A non-null ID means this provider's markers will be painted when the marker's owner ID
* this provider's ID
* .
* @param ownerId the ID
*/
public void setOwnerId(UniversalID ownerId);
/**
* Get the component to show the margin markers.
* @return the component
*/
public JComponent getComponent();
/**
* Return true if can be resized.
* @return true if can be resized.
*/
public boolean isResizeable();
/**
* Called to notify this margin provider that the current screen information has changed.
*
* @param listingPanel the listing panel.
* @param addressIndexMap the address index map to use.
* @param pixelMap the vertical pixel map to use.
*/
public void screenDataChanged(ListingPanel listingPanel, AddressIndexMap addressIndexMap,
VerticalPixelAddressMap pixelMap);
/**
* Called from the client when their location changes internally. This is different from a tool
* location event, which is considered a global event.
* @param location the location
*/
public void setLocation(ProgramLocation location);
/**
* Get the marker location for the given x, y point.
*
* @param x the horizontal coordinate.
* @param y the vertical coordinate.
* @return the location
*/
public MarkerLocation getMarkerLocation(int x, int y);
/**
* Called when the client is done with this provider.
*/
public void dispose();
}
@@ -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.
@@ -22,28 +22,32 @@ import ghidra.app.util.viewer.util.AddressIndexMap;
import ghidra.program.model.listing.Program;
/**
* Interface implemented by classes that provide overview components to the right side of the
* listing.
* An overview component that will be placed to the right side of the listing.
*/
public interface OverviewProvider {
public interface ListingOverviewProvider {
/**
* Returns the component to display in the right margin of the listing.
* @return the component
*/
JComponent getComponent();
public JComponent getComponent();
/**
* Sets the current program and associated address-index map
* Called to notify this margin provider that the current screen information has changed.
*
* @param program the program to use.
* @param map the address-index map to use.
* @param program the program to use
* @param map the address index map to use
*/
void setProgram(Program program, AddressIndexMap map);
public void screenDataChanged(Program program, AddressIndexMap map);
/**
* Set the component provider that this overview navigates
*
* @param navigatable the navigatable provider
*/
void setNavigatable(Navigatable navigatable);
public void setNavigatable(Navigatable navigatable);
/**
* Clients call this when they are done with this provider.
*/
public void dispose();
}
@@ -1,60 +0,0 @@
/* ###
* 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.util.viewer.listingpanel;
import javax.swing.JComponent;
import ghidra.app.util.viewer.util.AddressIndexMap;
import ghidra.program.model.listing.Program;
import ghidra.program.util.MarkerLocation;
/**
* Interface for objects that want to add a component to the listing's left margin.
*/
public interface MarginProvider {
/**
* Get the component to show the margin markers.
* @return the component
*/
JComponent getComponent();
/**
* Return true if can be resized.
* @return true if can be resized.
*/
boolean isResizeable();
/**
* Set the program and associated maps.
*
* @param program the program to use.
* @param addressIndexMap the address-index map to use.
* @param pixelMap the vertical pixel map to use.
*/
void setProgram(Program program, AddressIndexMap addressIndexMap,
VerticalPixelAddressMap pixelMap);
/**
* Get the marker location for the given x, y point.
*
* @param x the horizontal coordinate.
* @param y the vertical coordinate.
* @return the location
*/
public MarkerLocation getMarkerLocation(int x, int y);
}
@@ -394,8 +394,8 @@ public class ListingCodeComparisonView
public Object getContextObjectForMarginPanels(ListingPanel panel, MouseEvent event) {
Object source = event.getSource();
// Is event source a marker margin provider on the left side of the listing?
List<MarginProvider> marginProviders = panel.getMarginProviders();
for (MarginProvider marginProvider : marginProviders) {
List<ListingMarginProvider> marginProviders = panel.getMarginProviders();
for (ListingMarginProvider marginProvider : marginProviders) {
JComponent c = marginProvider.getComponent();
if (c == source) {
MarkerLocation loc = marginProvider.getMarkerLocation(event.getX(), event.getY());
@@ -406,8 +406,8 @@ public class ListingCodeComparisonView
}
}
// Is event source an overview provider on the right side of the listing?
List<OverviewProvider> overviewProviders = panel.getOverviewProviders();
for (OverviewProvider overviewProvider : overviewProviders) {
List<ListingOverviewProvider> overviewProviders = panel.getOverviewProviders();
for (ListingOverviewProvider overviewProvider : overviewProviders) {
JComponent c = overviewProvider.getComponent();
if (c == source) {
return source; // Return the overview provider that was clicked.
@@ -623,8 +623,8 @@ public class ListingCodeComparisonView
private Object getContextForMarginPanels(ListingPanel lp, MouseEvent event) {
Object source = event.getSource();
List<MarginProvider> marginProvidersForLP = lp.getMarginProviders();
for (MarginProvider marginProvider : marginProvidersForLP) {
List<ListingMarginProvider> marginProvidersForLP = lp.getMarginProviders();
for (ListingMarginProvider marginProvider : marginProvidersForLP) {
JComponent c = marginProvider.getComponent();
if (c == source) {
MarkerLocation loc = marginProvider.getMarkerLocation(event.getX(), event.getY());
@@ -634,8 +634,8 @@ public class ListingCodeComparisonView
return source;
}
}
List<OverviewProvider> overviewProvidersForLP = lp.getOverviewProviders();
for (OverviewProvider overviewProvider : overviewProvidersForLP) {
List<ListingOverviewProvider> overviewProvidersForLP = lp.getOverviewProviders();
for (ListingOverviewProvider overviewProvider : overviewProvidersForLP) {
JComponent c = overviewProvider.getComponent();
if (c == source) {
return source;
@@ -18,6 +18,7 @@ package ghidra.features.base.codecompare.listing;
import static ghidra.GhidraOptions.*;
import java.awt.Color;
import java.util.List;
import javax.swing.Icon;
@@ -94,9 +95,12 @@ public class ListingDisplay implements ListingDiffChangeListener {
private void createMarkerManager(String owner) {
markerManager = new ListingDisplayMarkerManager(tool, owner);
markerManager.addChangeListener(e -> listingPanel.repaint());
MarginProvider marginProvider = markerManager.getMarginProvider();
// Manually install our custom margin provider. We are not calling setMarginService(),
// which means that many of the listing markers will not work in the compare view.
ListingMarginProvider marginProvider = markerManager.createMarginProvider();
listingPanel.addMarginProvider(marginProvider);
OverviewProvider overviewProvider = markerManager.getOverviewProvider();
ListingOverviewProvider overviewProvider = markerManager.createOverviewProvider();
listingPanel.addOverviewProvider(overviewProvider);
}
@@ -171,7 +175,12 @@ public class ListingDisplay implements ListingDiffChangeListener {
markerManager.clearAll();
listingPanel.setView(view);
AddressIndexMap indexMap = listingPanel.getAddressIndexMap();
markerManager.getOverviewProvider().setProgram(program, indexMap);
List<ListingOverviewProvider> providers = listingPanel.getOverviewProviders();
for (ListingOverviewProvider provider : providers) {
provider.screenDataChanged(program, indexMap);
}
listingPanel.setBackgroundColorModel(
new MarkerServiceBackgroundColorModel(markerManager, program, indexMap));
setUpAreaMarkerSets(program, name);
@@ -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.
@@ -68,11 +68,11 @@ public class MarkerLocation implements Serializable {
}
/**
* Returns the Marker Manager.
* Returns the marker set.
*
* @return the marker manager
* @return the marker set
*/
public MarkerSet getMarkerManager() {
public MarkerSet getMarkerSet() {
return markers;
}
@@ -64,7 +64,7 @@ import ghidra.app.util.viewer.field.FieldFactory;
import ghidra.app.util.viewer.format.FieldFormatModel;
import ghidra.app.util.viewer.format.FormatManager;
import ghidra.app.util.viewer.listingpanel.ListingPanel;
import ghidra.app.util.viewer.listingpanel.MarginProvider;
import ghidra.app.util.viewer.listingpanel.ListingMarginProvider;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.framework.ToolUtils;
import ghidra.framework.plugintool.Plugin;
@@ -1247,9 +1247,9 @@ public abstract class AbstractScreenShotGenerator extends AbstractGhidraHeadedIn
CodeBrowserPlugin plugin = getPlugin(tool, CodeBrowserPlugin.class);
ListingPanel listingPanel = plugin.getListingPanel();
@SuppressWarnings("unchecked")
List<MarginProvider> list =
(List<MarginProvider>) getInstanceField("marginProviders", listingPanel);
for (MarginProvider marginProvider : list) {
List<ListingMarginProvider> list =
(List<ListingMarginProvider>) getInstanceField("marginProviders", listingPanel);
for (ListingMarginProvider marginProvider : list) {
listingPanel.removeMarginProvider(marginProvider);
}
});
@@ -669,6 +669,8 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
addReference(0x1001020, 0x1008294, RefType.DATA);
addReference(0x1001030, 0x1008394, RefType.DATA);
waitForProgram(program);
Address srcAddr = addr(0x01006990);
CodeUnit cu = program.getListing().getCodeUnitAt(srcAddr);
@@ -44,17 +44,15 @@ import ghidra.app.plugin.core.clear.ClearPlugin;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.highlight.SetHighlightPlugin;
import ghidra.app.services.*;
import ghidra.app.util.viewer.listingpanel.OverviewProvider;
import ghidra.app.util.viewer.util.AddressIndexMap;
import ghidra.framework.cmd.CompoundCmd;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.BookmarkType;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
import ghidra.test.*;
import ghidra.util.Msg;
import ghidra.util.datastruct.WeakSet;
public class MarkerTest extends AbstractGhidraHeadedIntegrationTest {
@@ -162,8 +160,13 @@ public class MarkerTest extends AbstractGhidraHeadedIntegrationTest {
setSelection(fp, sel);
MarkerManager mm = (MarkerManager) markerService;
OverviewProvider op = mm.getOverviewProvider();
JPanel navPanel = (JPanel) op.getComponent();
@SuppressWarnings("unchecked")
WeakSet<MarkerOverviewProvider> overviewProviders =
(WeakSet<MarkerOverviewProvider>) getInstanceField("overviewProviders", mm);
MarkerOverviewProvider provider = overviewProviders.iterator().next();
JPanel navPanel = (JPanel) provider.getComponent();
waitForProgram(program);
@@ -224,8 +227,13 @@ public class MarkerTest extends AbstractGhidraHeadedIntegrationTest {
assertTrue(addrSet.contains(addr("0xf000131b")));
MarkerManager mm = (MarkerManager) markerService;
OverviewProvider op = mm.getOverviewProvider();
JPanel navPanel = (JPanel) op.getComponent();
@SuppressWarnings("unchecked")
WeakSet<MarkerOverviewProvider> overviewProviders =
(WeakSet<MarkerOverviewProvider>) getInstanceField("overviewProviders", mm);
MarkerOverviewProvider provider = overviewProviders.iterator().next();
JPanel navPanel = (JPanel) provider.getComponent();
waitForProgram(program);
@@ -278,7 +286,12 @@ public class MarkerTest extends AbstractGhidraHeadedIntegrationTest {
MouseEvent dummyEvent =
new MouseEvent(cb.getFieldPanel(), (int) time, time, 0, x, y, 1, false);
MarkerManager mm = (MarkerManager) markerService;
String tooltip = runSwing(() -> mm.generateToolTip(dummyEvent));
@SuppressWarnings("unchecked")
WeakSet<MarkerMarginProvider> marginProviders =
(WeakSet<MarkerMarginProvider>) getInstanceField("marginProviders", mm);
MarkerMarginProvider provider = marginProviders.iterator().next();
String tooltip = runSwing(() -> provider.generateToolTip(dummyEvent));
assertEquals(
"<html><font size=\"4\">Cursor<BR>Note [TEST]: comment<BR>Changes: Unsaved<BR>",
tooltip);
@@ -316,11 +329,11 @@ public class MarkerTest extends AbstractGhidraHeadedIntegrationTest {
MouseEvent dummyEvent = new MouseEvent(cb.getFieldPanel(), (int) System.currentTimeMillis(),
System.currentTimeMillis(), 0, x, y, 1, false);
// debug
ProgramLocation location = cb.getListingPanel().getProgramLocation(dummyEvent.getPoint());
Msg.debug(this, "location for point: " + location + "; at " + location.getAddress());
String tooltip = runSwing(() -> mm.generateToolTip(dummyEvent));
@SuppressWarnings("unchecked")
WeakSet<MarkerMarginProvider> marginProviders =
(WeakSet<MarkerMarginProvider>) getInstanceField("marginProviders", mm);
MarkerMarginProvider provider = marginProviders.iterator().next();
String tooltip = runSwing(() -> provider.generateToolTip(dummyEvent));
assertNotNull("No tooltip for field: " + cb.getCurrentField() + "\n\tat address: " +
cb.getCurrentAddress(), tooltip);
@@ -83,9 +83,9 @@ public class FidPlugin extends ProgramPlugin implements ChangeListener {
}
@Override
protected void cleanup() {
protected void dispose() {
fidFileManager.removeChangeListener(this);
super.cleanup();
super.dispose();
}
/**
@@ -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.
@@ -133,7 +133,6 @@ public class ProgramDiffPlugin extends ProgramPlugin
private DiffController diffControl;
private Program primaryProgram;
private Program secondaryDiffProgram;
private AddressFactory p2AddressFactory;
private ProgramDiffDetails diffDetails;
private ProgramSelection p2DiffHighlight;
@@ -286,33 +285,39 @@ public class ProgramDiffPlugin extends ProgramPlugin
if (primaryProgram != null && !showingSecondProgram) {
return;
}
p1ViewAddrSet = p1AddressSet;
if (!showingSecondProgram) {
return;
}
if (showingSecondProgram) {
ProgramSelection previousP1Selection = currentSelection;
ProgramSelection previousP2DiffHighlight = p2DiffHighlight;
ProgramSelection previousP2Selection = p2Selection;
ProgramSelection previousP1Selection = currentSelection;
ProgramSelection previousP2DiffHighlight = p2DiffHighlight;
ProgramSelection previousP2Selection = p2Selection;
AddressSet p2ViewAddrSet =
DiffUtility.getCompatibleAddressSet(p1ViewAddrSet, secondaryDiffProgram);
diffListingPanel.setView(p2ViewAddrSet);
FieldPanel fp = diffListingPanel.getFieldPanel();
AddressSet p2ViewAddrSet =
DiffUtility.getCompatibleAddressSet(p1ViewAddrSet, secondaryDiffProgram);
diffListingPanel.setView(p2ViewAddrSet);
FieldPanel fp = diffListingPanel.getFieldPanel();
AddressSet p1AddressSetAsP2 =
DiffUtility.getCompatibleAddressSet(p1AddressSet, secondaryDiffProgram);
AddressIndexMap p2IndexMap = new AddressIndexMap(p1AddressSetAsP2);
markerManager.getOverviewProvider().setProgram(secondaryDiffProgram, p2IndexMap);
fp.setBackgroundColorModel(new MarkerServiceBackgroundColorModel(markerManager,
secondaryDiffProgram, p2IndexMap));
AddressSet p1AddressSetAsP2 =
DiffUtility.getCompatibleAddressSet(p1AddressSet, secondaryDiffProgram);
AddressIndexMap p2IndexMap = new AddressIndexMap(p1AddressSetAsP2);
List<ListingOverviewProvider> providers = diffListingPanel.getOverviewProviders();
for (ListingOverviewProvider provider : providers) {
provider.screenDataChanged(secondaryDiffProgram, p2IndexMap);
}
currentSelection = previousP1Selection;
p2DiffHighlight = previousP2DiffHighlight;
fp.setBackgroundColorModel(new MarkerServiceBackgroundColorModel(markerManager,
secondaryDiffProgram, p2IndexMap));
p2Selection = previousP2Selection;
setProgram2Selection(p2Selection);
if (p2DiffHighlight != null) {
setDiffHighlight(p2DiffHighlight);
}
currentSelection = previousP1Selection;
p2DiffHighlight = previousP2DiffHighlight;
p2Selection = previousP2Selection;
setProgram2Selection(p2Selection);
if (p2DiffHighlight != null) {
setDiffHighlight(p2DiffHighlight);
}
}
@@ -556,9 +561,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
return;
}
if (currentSelection == null) {
AddressFactory p1AddressFactory =
(primaryProgram != null) ? primaryProgram.getAddressFactory() : null;
currentSelection = new ProgramSelection(p1AddressFactory);
currentSelection = new ProgramSelection();
}
actionManager.setP1SelectToP2ActionEnabled(
secondaryDiffProgram != null && !currentSelection.isEmpty());
@@ -605,8 +608,13 @@ public class ProgramDiffPlugin extends ProgramPlugin
diffListingPanel.setProgramLocationListener(this);
diffListingPanel.setProgramSelectionListener(this);
diffListingPanel.getFieldPanel().addFieldMouseListener(new MyFieldMouseListener());
diffListingPanel.addMarginProvider(markerManager.getMarginProvider());
diffListingPanel.addOverviewProvider(markerManager.getOverviewProvider());
// Manually install our custom margin provider. We are not calling setMarginService(),
// which means that many of the listing markers will not work in the diff view.
MarkerService markerService = tool.getService(MarkerService.class);
diffListingPanel.addMarginProvider(markerService.createMarginProvider());
diffListingPanel.addOverviewProvider(markerService.createOverviewProvider());
diffNavigatable = new DiffNavigatable(this, codeViewerService.getNavigatable());
diffFieldNavigator = new FieldNavigator(diffServiceProvider, diffNavigatable);
diffListingPanel.addButtonPressedListener(diffFieldNavigator);
@@ -678,9 +686,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
ProgramSelection getCurrentSelection() {
if (currentSelection == null) {
AddressFactory p1AddressFactory =
(primaryProgram != null) ? primaryProgram.getAddressFactory() : null;
currentSelection = new ProgramSelection(p1AddressFactory);
currentSelection = new ProgramSelection();
}
return currentSelection;
}
@@ -753,10 +759,8 @@ public class ProgramDiffPlugin extends ProgramPlugin
// Make sure that the Diff selection is to the code unit boundary.
ProgramSelection p2CodeUnitSelection =
new ProgramSelection(DiffUtility.getCodeUnitSet(newP2Selection, secondaryDiffProgram));
AddressFactory p1AddressFactory =
(primaryProgram != null) ? primaryProgram.getAddressFactory() : null;
ProgramSelection intersection =
new ProgramSelection(p2AddressFactory, p2CodeUnitSelection.intersect(p2DiffHighlight));
new ProgramSelection(p2CodeUnitSelection.intersect(p2DiffHighlight));
p2Selection = intersection;
AddressSet p2SelectionAsP1Set =
@@ -767,8 +771,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
// of the MultiListing Layout being used.
///////////////////////////////////////////
ProgramSelection p2SelectionAsP1 =
new ProgramSelection(p1AddressFactory, p2SelectionAsP1Set);
ProgramSelection p2SelectionAsP1 = new ProgramSelection(p2SelectionAsP1Set);
runSwing(() -> {
MarkerSet selectionMarkers = getSelectionMarkers();
selectionMarkers.clearAll();
@@ -783,7 +786,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
actionManager.setP1SelectToP2ActionEnabled(
(secondaryDiffProgram != null) && !currentSelection.isEmpty());
firePluginEvent(new ProgramSelectionPluginEvent(this.getName(),
new ProgramSelection(p1AddressFactory, currentSelection), primaryProgram));
new ProgramSelection(currentSelection), primaryProgram));
}
}
@@ -873,7 +876,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
}
AddressSet p2DiffSet = DiffUtility.getCompatibleAddressSet(p1DiffSet, secondaryDiffProgram);
ProgramSelection p2DiffSelection = new ProgramSelection(p2AddressFactory, p2DiffSet);
ProgramSelection p2DiffSelection = new ProgramSelection(p2DiffSet);
p2DiffHighlight = p2DiffSelection;
AddressSet p2DiffSetAsP1 = DiffUtility.getCompatibleAddressSet(p2DiffSet, primaryProgram);
@@ -918,7 +921,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
if (diffControl.hasNext()) {
diffControl.next();
}
setProgram2Selection(new ProgramSelection(p2AddressFactory, getDiffHighlightBlock()));
setProgram2Selection(new ProgramSelection(getDiffHighlightBlock()));
}
void previousDiff() {
@@ -926,7 +929,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
if (diffControl.hasPrevious()) {
diffControl.previous();
}
setProgram2Selection(new ProgramSelection(p2AddressFactory, getDiffHighlightBlock()));
setProgram2Selection(new ProgramSelection(getDiffHighlightBlock()));
}
private void clearDiff() {
@@ -992,8 +995,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
AddressSet p1IgnoreSet =
DiffUtility.getCompatibleAddressSet(p2IgnoreSet, primaryProgram);
diffControl.ignore(p1IgnoreSet, null);
p2DiffHighlight =
new ProgramSelection(p2AddressFactory, p2DiffHighlight.subtract(p2IgnoreSet));
p2DiffHighlight = new ProgramSelection(p2DiffHighlight.subtract(p2IgnoreSet));
adjustDiffDisplay();
@@ -1047,7 +1049,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
}
AddressSetView p2ViewAddrSet =
DiffUtility.getCompatibleAddressSet(adjustedView, secondaryDiffProgram);
setProgram2Selection(new ProgramSelection(p2AddressFactory, p2ViewAddrSet));
setProgram2Selection(new ProgramSelection(p2ViewAddrSet));
}
finally {
diffListingPanel.getFieldPanel().requestFocus();
@@ -1078,7 +1080,6 @@ public class ProgramDiffPlugin extends ProgramPlugin
primaryProgram.removeListener(this);
primaryProgram = null;
secondaryDiffProgram = null;
p2AddressFactory = null;
}
sameProgramContext = false;
updatePgm2Enablement();
@@ -1221,7 +1222,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
if (!currentSelection.isEmpty()) {
AddressSet p2SelectionSet =
DiffUtility.getCompatibleAddressSet(currentSelection, secondaryDiffProgram);
setProgram2Selection(new ProgramSelection(p2AddressFactory,
setProgram2Selection(new ProgramSelection(
DiffUtility.getCodeUnitSet(p2SelectionSet, secondaryDiffProgram)));
}
if (p2Selection.isEmpty()) {
@@ -1630,7 +1631,6 @@ public class ProgramDiffPlugin extends ProgramPlugin
primaryProgram = currentProgram;
secondaryDiffProgram = newProgram;
p2AddressFactory = secondaryDiffProgram.getAddressFactory();
applyFilter = applySettingsMgr.getDefaultApplyFilter();
diffDetails = new ProgramDiffDetails(primaryProgram, secondaryDiffProgram);
primaryProgram.addListener(this);
@@ -1884,14 +1884,14 @@ public class ProgramDiffPlugin extends ProgramPlugin
}
}
if (set.equals(p2Selection)) {
AddressSetView asView = p2Selection;
if (set.equals(asView)) {
return; // Selection is unchanged so do nothing.
}
MarkerSet selectionMarkers = getSelectionMarkers();
selectionMarkers.clearAll();
programSelectionChanged(new ProgramSelection(p2AddressFactory, set),
EventTrigger.GUI_ACTION);
programSelectionChanged(new ProgramSelection(set), EventTrigger.GUI_ACTION);
updatePgm2Enablement();
}
}
@@ -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.
@@ -762,7 +762,8 @@ public class VTSubToolManager implements VTControllerListener, OptionsChangeList
}
private boolean isCursorOnScreen(CodeViewerService service) {
FieldPanel fieldPanel = service.getFieldPanel();
ListingPanel listingPanel = service.getListingPanel();
FieldPanel fieldPanel = listingPanel.getFieldPanel();
int cursorOffset = fieldPanel.getCursorOffset();
return cursorOffset >= 0; // negative offset means offscreen
}
@@ -779,7 +780,10 @@ public class VTSubToolManager implements VTControllerListener, OptionsChangeList
if (service == null) {
return null;
}
FieldSelection selection = service.getFieldPanel().getSelection();
ListingPanel listingPanel = service.getListingPanel();
FieldPanel fieldPanel = listingPanel.getFieldPanel();
FieldSelection selection = fieldPanel.getSelection();
AddressIndexMap addressIndexMap = service.getListingPanel().getAddressIndexMap();
AddressSet addressSet = addressIndexMap.getAddressSet(selection);
return addressSet;
@@ -788,13 +792,11 @@ public class VTSubToolManager implements VTControllerListener, OptionsChangeList
/**
* Sets the address set to be the selection in the tool.
*
* @param tool
* the tool
* @param set
* the addressSet to use for the selection
* @param tool the tool
* @param addresses the addressSet to use for the selection
*/
private void setSelectionInTool(PluginTool tool, AddressSetView addressSet) {
ProgramSelection programSelection = new ProgramSelection(addressSet);
private void setSelectionInTool(PluginTool tool, AddressSetView addresses) {
ProgramSelection programSelection = new ProgramSelection(addresses);
CodeViewerService service = tool.getService(CodeViewerService.class);
if (service == null) {
return;
@@ -268,6 +268,10 @@ public abstract class Plugin implements ExtensionPoint, PluginEventListener, Ser
}
}
/**
* Called by the framework to dispose of this plugin and unregister for events and services.
* Subclasses should not override this method, but should instead override {@link #dispose()}.
*/
protected void cleanup() {
if (!disposed) {
Throwable thr = null;
@@ -15,7 +15,7 @@
*/
package ghidra.app.plugin.core.debug.gui.control;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*;
import java.util.*;
import java.util.stream.Collectors;
@@ -26,6 +26,7 @@ import org.junit.Test;
import db.Transaction;
import docking.action.DockingActionIf;
import ghidra.app.context.ProgramLocationActionContext;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerIntegrationTest;
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin;
@@ -50,6 +51,7 @@ public class DebuggerMethodActionsPluginTest extends AbstractGhidraHeadedDebugge
@Before
public void setUpMethodActionsTest() throws Exception {
addPlugin(tool, CodeBrowserPlugin.class);
listingPlugin = addPlugin(tool, DebuggerListingPlugin.class);
mappingService = addPlugin(tool, DebuggerStaticMappingServicePlugin.class);
methodsPlugin = addPlugin(tool, DebuggerMethodActionsPlugin.class);
@@ -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.
@@ -31,7 +31,7 @@ import ghidra.app.util.viewer.field.*;
import ghidra.app.util.viewer.format.FieldFormatModel;
import ghidra.app.util.viewer.format.FormatManager;
import ghidra.app.util.viewer.listingpanel.ListingPanel;
import ghidra.app.util.viewer.listingpanel.MarginProvider;
import ghidra.app.util.viewer.listingpanel.ListingMarginProvider;
import ghidra.framework.options.Options;
import ghidra.framework.options.ToolOptions;
import ghidra.program.model.address.Address;
@@ -138,11 +138,11 @@ public class BlockModelScreenShots extends GhidraScreenShotGenerator {
final ListingPanel lp = cb.getListingPanel();
@SuppressWarnings("unchecked")
final List<MarginProvider> list =
new ArrayList<>((List<MarginProvider>) getInstanceField("marginProviders", lp));
final List<ListingMarginProvider> list =
new ArrayList<>((List<ListingMarginProvider>) getInstanceField("marginProviders", lp));
runSwing(() -> {
invokeInstanceMethod("buildPanels", lp);
for (MarginProvider marginProvider : list) {
for (ListingMarginProvider marginProvider : list) {
lp.removeMarginProvider(marginProvider);
}
});
@@ -39,7 +39,7 @@ import ghidra.app.plugin.core.datamgr.DataTypesProvider;
import ghidra.app.plugin.core.programtree.ViewManagerComponentProvider;
import ghidra.app.util.viewer.field.*;
import ghidra.app.util.viewer.listingpanel.ListingPanel;
import ghidra.app.util.viewer.listingpanel.OverviewProvider;
import ghidra.app.util.viewer.listingpanel.ListingOverviewProvider;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.CommentType;
@@ -265,10 +265,10 @@ public class CodeBrowserPluginScreenShots extends GhidraScreenShotGenerator {
public void testCaptureMarkerPopup() {
setToolSize(1400, 1200);
ListingPanel listingPanel = plugin.getListingPanel();
List<OverviewProvider> overviewProviders = listingPanel.getOverviewProviders();
List<ListingOverviewProvider> overviewProviders = listingPanel.getOverviewProviders();
assertEquals(1, overviewProviders.size());
OverviewProvider provider = overviewProviders.get(0);
ListingOverviewProvider provider = overviewProviders.get(0);
rightClick(provider.getComponent(), 1, 1);
captureMenu();