GP-1433: Refactor Magin and Overview Providers. Add marker margin and overview to dynamic listings.

This commit is contained in:
Dan 2022-02-07 11:14:00 -05:00
parent c0b644b8b9
commit 25dd729323
23 changed files with 1264 additions and 875 deletions

View file

@ -484,9 +484,12 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin
private class ToggleBreakpointsMarkerClickedListener implements MarkerClickedListener { private class ToggleBreakpointsMarkerClickedListener implements MarkerClickedListener {
@Override @Override
public void markerDoubleClicked(MarkerLocation location) { public void markerDoubleClicked(MarkerLocation location) {
doToggleBreakpointsAt(ToggleBreakpointAction.NAME, ProgramLocationActionContext context =
new ProgramLocationActionContext(null, location.getProgram(), new ProgramLocationActionContext(null, location.getProgram(),
new ProgramLocation(location.getProgram(), location.getAddr()), null, null)); new ProgramLocation(location.getProgram(), location.getAddr()), null, null);
if (contextCanManipulateBreakpoints(context)) {
doToggleBreakpointsAt(ToggleBreakpointAction.NAME, context);
}
} }
} }
@ -895,8 +898,8 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin
if (mappingService == null || modelService == null) { if (mappingService == null || modelService == null) {
return Set.of(); return Set.of();
} }
ProgramLocation loc = getLocationFromContext(context); // must be static location ProgramLocation loc = getLocationFromContext(context);
if (loc == null) { if (loc == null || loc.getProgram() instanceof TraceProgramView) {
return Set.of(); return Set.of();
} }
Set<TraceRecorder> result = new HashSet<>(); Set<TraceRecorder> result = new HashSet<>();

View file

@ -52,6 +52,8 @@ import ghidra.app.plugin.core.debug.gui.action.*;
import ghidra.app.plugin.core.debug.gui.modules.DebuggerMissingModuleActionContext; import ghidra.app.plugin.core.debug.gui.modules.DebuggerMissingModuleActionContext;
import ghidra.app.plugin.core.debug.utils.ProgramLocationUtils; import ghidra.app.plugin.core.debug.utils.ProgramLocationUtils;
import ghidra.app.plugin.core.debug.utils.ProgramURLUtils; import ghidra.app.plugin.core.debug.utils.ProgramURLUtils;
import ghidra.app.plugin.core.marker.MarkerMarginProvider;
import ghidra.app.plugin.core.marker.MarkerOverviewProvider;
import ghidra.app.services.*; import ghidra.app.services.*;
import ghidra.app.services.DebuggerListingService.LocationTrackingSpecChangeListener; import ghidra.app.services.DebuggerListingService.LocationTrackingSpecChangeListener;
import ghidra.app.util.viewer.format.FormatManager; import ghidra.app.util.viewer.format.FormatManager;
@ -266,6 +268,8 @@ public class DebuggerListingProvider extends CodeViewerProvider {
protected final MultiBlendedListingBackgroundColorModel colorModel; protected final MultiBlendedListingBackgroundColorModel colorModel;
protected final MarkerSetChangeListener markerChangeListener = new MarkerSetChangeListener(); protected final MarkerSetChangeListener markerChangeListener = new MarkerSetChangeListener();
protected MarkerServiceBackgroundColorModel markerServiceColorModel; protected MarkerServiceBackgroundColorModel markerServiceColorModel;
protected MarkerMarginProvider markerMarginProvider;
protected MarkerOverviewProvider markerOverviewProvider;
private SuppressableCallback<ProgramLocation> cbGoTo = new SuppressableCallback<>(); private SuppressableCallback<ProgramLocation> cbGoTo = new SuppressableCallback<>();
@ -500,6 +504,10 @@ public class DebuggerListingProvider extends CodeViewerProvider {
private void setMarkerService(MarkerService markerService) { private void setMarkerService(MarkerService markerService) {
if (this.markerService != null) { if (this.markerService != null) {
this.markerService.removeChangeListener(markerChangeListener); this.markerService.removeChangeListener(markerChangeListener);
removeMarginProvider(markerMarginProvider);
markerMarginProvider = null;
removeOverviewProvider(markerOverviewProvider);
markerOverviewProvider = null;
} }
removeOldStaticTrackingMarker(); removeOldStaticTrackingMarker();
this.markerService = markerService; this.markerService = markerService;
@ -510,6 +518,12 @@ public class DebuggerListingProvider extends CodeViewerProvider {
// NOTE: Connected provider marker listener is taken care of by CodeBrowserPlugin // NOTE: Connected provider marker listener is taken care of by CodeBrowserPlugin
this.markerService.addChangeListener(markerChangeListener); this.markerService.addChangeListener(markerChangeListener);
} }
if (this.markerService != null) {
markerMarginProvider = markerService.createMarginProvider();
addMarginProvider(markerMarginProvider);
markerOverviewProvider = markerService.createOverviewProvider();
addOverviewProvider(markerOverviewProvider);
}
} }
@AutoServiceConsumed @AutoServiceConsumed

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,15 +15,15 @@
*/ */
package ghidra.app.plugin.core.bookmark; package ghidra.app.plugin.core.bookmark;
import ghidra.app.context.ListingActionContext;
import ghidra.program.model.address.Address;
import ghidra.program.util.MarkerLocation;
import java.awt.event.InputEvent; import java.awt.event.InputEvent;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import docking.ActionContext; import docking.ActionContext;
import docking.action.*; import docking.action.*;
import ghidra.app.context.ListingActionContext;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.util.MarkerLocation;
/** /**
* <CODE>AddBookmarkAction</CODE> allows the user to add a Note bookmark at the current location. * <CODE>AddBookmarkAction</CODE> allows the user to add a Note bookmark at the current location.
@ -34,8 +33,8 @@ class AddBookmarkAction extends DockingAction {
BookmarkPlugin plugin; BookmarkPlugin plugin;
/** /**
* Creates a new action with the given name and associated to the given * Creates a new action with the given name and associated to the given plugin.
* plugin. *
* @param name the name for this action. * @param name the name for this action.
* @param plugin the plugin this action is associated with. * @param plugin the plugin this action is associated with.
*/ */
@ -51,11 +50,12 @@ class AddBookmarkAction extends DockingAction {
/** /**
* Method called when the action is invoked. * Method called when the action is invoked.
*
* @param ActionEvent details regarding the invocation of this action * @param ActionEvent details regarding the invocation of this action
*/ */
@Override @Override
public void actionPerformed(ActionContext context) { public void actionPerformed(ActionContext context) {
plugin.showAddBookmarkDialog(getAddress(context)); plugin.showAddBookmarkDialog(getAddress(context), getProgram(context));
} }
/** /**
@ -67,7 +67,7 @@ class AddBookmarkAction extends DockingAction {
if (context == null) { if (context == null) {
return false; return false;
} }
return getAddress(context) != null; return getAddress(context) != null && getProgram(context) == plugin.getCurrentProgram();
} }
private Address getAddress(ActionContext context) { private Address getAddress(ActionContext context) {
@ -80,4 +80,15 @@ class AddBookmarkAction extends DockingAction {
} }
return null; return null;
} }
private Program getProgram(ActionContext context) {
Object contextObject = context.getContextObject();
if (MarkerLocation.class.isAssignableFrom(contextObject.getClass())) {
return ((MarkerLocation) contextObject).getProgram();
}
else if (context instanceof ListingActionContext) {
return ((ListingActionContext) context).getProgram();
}
return null;
}
} }

View file

@ -186,8 +186,7 @@ public class BookmarkPlugin extends ProgramPlugin
} }
/** /**
* Get rid of any resources this plugin is using * Get rid of any resources this plugin is using before the plugin is destroyed.
* before the plugin is destroyed.
*/ */
@Override @Override
public synchronized void dispose() { public synchronized void dispose() {
@ -276,6 +275,7 @@ public class BookmarkPlugin extends ProgramPlugin
/** /**
* Get or create a bookmark navigator for the specified bookmark type * Get or create a bookmark navigator for the specified bookmark type
*
* @param type the bookmark type * @param type the bookmark type
* @return bookmark navigator * @return bookmark navigator
*/ */
@ -432,9 +432,12 @@ public class BookmarkPlugin extends ProgramPlugin
bookmarkMgr = program.getBookmarkManager(); bookmarkMgr = program.getBookmarkManager();
} }
void showAddBookmarkDialog(Address location) { void showAddBookmarkDialog(Address address, Program program) {
if (program != currentProgram) {
return;
}
Listing listing = currentProgram.getListing(); Listing listing = currentProgram.getListing();
CodeUnit currCU = listing.getCodeUnitContaining(location); CodeUnit currCU = listing.getCodeUnitContaining(address);
if (currCU == null) { if (currCU == null) {
return; return;
} }
@ -446,8 +449,8 @@ public class BookmarkPlugin extends ProgramPlugin
/** /**
* Called when a new bookmark is to be added; called from the add bookmark dialog * Called when a new bookmark is to be added; called from the add bookmark dialog
* *
* @param addr bookmark address. If null a Note bookmark will set at the * @param addr bookmark address. If null a Note bookmark will set at the start address of each
* start address of each range in the current selection * range in the current selection
* @param category bookmark category * @param category bookmark category
* @param comment comment text * @param comment comment text
*/ */
@ -494,6 +497,9 @@ public class BookmarkPlugin extends ProgramPlugin
return null; return null;
} }
MarkerLocation loc = (MarkerLocation) contextObject; MarkerLocation loc = (MarkerLocation) contextObject;
if (loc.getProgram() != currentProgram) {
return null;
}
BookmarkManager mgr = currentProgram.getBookmarkManager(); BookmarkManager mgr = currentProgram.getBookmarkManager();
Address address = loc.getAddr(); Address address = loc.getAddr();
Bookmark[] bookmarks = mgr.getBookmarks(address); Bookmark[] bookmarks = mgr.getBookmarks(address);
@ -518,12 +524,13 @@ public class BookmarkPlugin extends ProgramPlugin
} }
/** /**
* Returns a list of actions to delete bookmarks that are in the code unit surrounding the * Returns a list of actions to delete bookmarks that are in the code unit surrounding the given
* given address. The list of actions will not exceed <tt>maxActionsCount</tt> * address. The list of actions will not exceed <tt>maxActionsCount</tt>
* @param primaryAddress The address required to find the containing code unit. *
* @param maxActionsCount The maximum number of actions to include in the returned list. * @param primaryAddress The address required to find the containing code unit.
* @return a list of actions to delete bookmarks that are in the code unit surrounding the * @param maxActionsCount The maximum number of actions to include in the returned list.
* given address. * @return a list of actions to delete bookmarks that are in the code unit surrounding the given
* address.
*/ */
private List<DockingActionIf> getActionsForCodeUnit(Address primaryAddress, private List<DockingActionIf> getActionsForCodeUnit(Address primaryAddress,
int maxActionsCount) { int maxActionsCount) {
@ -543,14 +550,15 @@ public class BookmarkPlugin extends ProgramPlugin
} }
/** /**
* Returns a list of actions to delete bookmarks that are in the code unit surrounding the * Returns a list of actions to delete bookmarks that are in the code unit surrounding the given
* given address <b>for the given <i>type</i> of bookmark</b>. * address <b>for the given <i>type</i> of bookmark</b>.
*
* @param primaryAddress The address required to find the containing code unit. * @param primaryAddress The address required to find the containing code unit.
* @param type The bookmark type to retrieve. * @param type The bookmark type to retrieve.
* @param navigator The BookmarkNavigator used to determine whether there are bookmarks * @param navigator The BookmarkNavigator used to determine whether there are bookmarks inside
* inside the code unit containing the given <tt>primaryAddress</tt>. * the code unit containing the given <tt>primaryAddress</tt>.
* @return a list of actions to delete bookmarks that are in the code unit surrounding the * @return a list of actions to delete bookmarks that are in the code unit surrounding the given
* given address <b>for the given <i>type</i> of bookmark</b>. * address <b>for the given <i>type</i> of bookmark</b>.
*/ */
private List<DockingActionIf> getActionsForCodeUnitAndType(Address primaryAddress, String type, private List<DockingActionIf> getActionsForCodeUnitAndType(Address primaryAddress, String type,
BookmarkNavigator navigator) { BookmarkNavigator navigator) {
@ -585,9 +593,10 @@ public class BookmarkPlugin extends ProgramPlugin
/** /**
* Adds the actions in <tt>newActionList</tt> to <tt>actionList</tt> while the size of * Adds the actions in <tt>newActionList</tt> to <tt>actionList</tt> while the size of
* <tt>actionList</tt> is less than the given {@link #MAX_DELETE_ACTIONS}. * <tt>actionList</tt> is less than the given {@link #MAX_DELETE_ACTIONS}.
*
* @param actionList The list to add to * @param actionList The list to add to
* @param newActionList The list containing items to add * @param newActionList The list containing items to add
* @param maxActionCount the maximum number of items that the actionList can contain * @param maxActionCount the maximum number of items that the actionList can contain
*/ */
private void addActionsToList(List<DockingActionIf> actionList, private void addActionsToList(List<DockingActionIf> actionList,
List<DockingActionIf> newActionList, int maxActionCount) { List<DockingActionIf> newActionList, int maxActionCount) {

View file

@ -16,8 +16,6 @@
package ghidra.app.plugin.core.codebrowser; package ghidra.app.plugin.core.codebrowser;
import java.awt.Color; import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -84,7 +82,6 @@ public abstract class AbstractCodeBrowserPlugin<P extends CodeViewerProvider> ex
private MarkerSet currentHighlightMarkers; private MarkerSet currentHighlightMarkers;
private MarkerSet currentCursorMarkers; private MarkerSet currentCursorMarkers;
private ChangeListener markerChangeListener; private ChangeListener markerChangeListener;
private FocusingMouseListener focusingMouseListener = new FocusingMouseListener();
private Color cursorHighlightColor; private Color cursorHighlightColor;
private boolean isHighlightCursorLine; private boolean isHighlightCursorLine;
@ -269,36 +266,22 @@ public abstract class AbstractCodeBrowserPlugin<P extends CodeViewerProvider> ex
@Override @Override
public void addOverviewProvider(OverviewProvider overviewProvider) { public void addOverviewProvider(OverviewProvider overviewProvider) {
JComponent component = overviewProvider.getComponent(); connectedProvider.addOverviewProvider(overviewProvider);
// just in case we get repeated calls
component.removeMouseListener(focusingMouseListener);
component.addMouseListener(focusingMouseListener);
connectedProvider.getListingPanel().addOverviewProvider(overviewProvider);
} }
@Override @Override
public void addMarginProvider(MarginProvider marginProvider) { public void addMarginProvider(MarginProvider marginProvider) {
JComponent component = marginProvider.getComponent(); connectedProvider.addMarginProvider(marginProvider);
// just in case we get repeated calls
component.removeMouseListener(focusingMouseListener);
component.addMouseListener(focusingMouseListener);
connectedProvider.getListingPanel().addMarginProvider(marginProvider);
} }
@Override @Override
public void removeOverviewProvider(OverviewProvider overviewProvider) { public void removeOverviewProvider(OverviewProvider overviewProvider) {
JComponent component = overviewProvider.getComponent(); connectedProvider.removeOverviewProvider(overviewProvider);
component.removeMouseListener(focusingMouseListener);
connectedProvider.getListingPanel().removeOverviewProvider(overviewProvider);
} }
@Override @Override
public void removeMarginProvider(MarginProvider marginProvider) { public void removeMarginProvider(MarginProvider marginProvider) {
JComponent component = marginProvider.getComponent(); connectedProvider.removeMarginProvider(marginProvider);
component.removeMouseListener(focusingMouseListener);
connectedProvider.getListingPanel().removeMarginProvider(marginProvider);
} }
@Override @Override
@ -927,12 +910,4 @@ public abstract class AbstractCodeBrowserPlugin<P extends CodeViewerProvider> ex
fieldPanel.repaint(); fieldPanel.repaint();
} }
} }
private class FocusingMouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
connectedProvider.getListingPanel().getFieldPanel().requestFocus();
}
}
} }

View file

@ -20,6 +20,7 @@ import java.awt.Point;
import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable; import java.awt.datatransfer.Transferable;
import java.awt.dnd.*; import java.awt.dnd.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.util.*; import java.util.*;
@ -100,6 +101,8 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
private FormatManager formatMgr; private FormatManager formatMgr;
private FieldPanelCoordinator coordinator; private FieldPanelCoordinator coordinator;
private FocusingMouseListener focusingMouseListener;
private CodeBrowserClipboardProvider codeViewerClipboardProvider; private CodeBrowserClipboardProvider codeViewerClipboardProvider;
private ClipboardService clipboardService; private ClipboardService clipboardService;
@ -1011,6 +1014,45 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
listingPanel.removeDisplayListener(listener); 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);
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);
getListingPanel().removeOverviewProvider(overviewProvider);
}
public void removeMarginProvider(MarginProvider marginProvider) {
JComponent component = marginProvider.getComponent();
component.removeMouseListener(focusingMouseListener);
getListingPanel().removeMarginProvider(marginProvider);
}
//================================================================================================== //==================================================================================================
// Inner Classes // Inner Classes
//================================================================================================== //==================================================================================================
@ -1092,4 +1134,11 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
return list.toArray(new Highlight[list.size()]); return list.toArray(new Highlight[list.size()]);
} }
} }
private class FocusingMouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
getListingPanel().getFieldPanel().requestFocus();
}
}
} }

View file

@ -52,10 +52,7 @@ public class MarkerServiceBackgroundColorModel implements ListingBackgroundColor
Address addr = indexMap.getAddress(index); Address addr = indexMap.getAddress(index);
Color color = null; Color color = null;
if (addr != null) { if (addr != null) {
if (program == null) { if (program != null) {
color = markerService.getBackgroundColor(addr);
}
else {
color = markerService.getBackgroundColor(program, addr); color = markerService.getBackgroundColor(program, addr);
} }
} }

View file

@ -30,6 +30,7 @@ import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.services.CodeViewerService; import ghidra.app.services.CodeViewerService;
import ghidra.app.util.viewer.listingpanel.*; import ghidra.app.util.viewer.listingpanel.*;
import ghidra.app.util.viewer.options.OptionsGui; import ghidra.app.util.viewer.options.OptionsGui;
import ghidra.app.util.viewer.util.AddressIndexMap;
import ghidra.framework.options.OptionsChangeListener; import ghidra.framework.options.OptionsChangeListener;
import ghidra.framework.options.ToolOptions; import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.*;
@ -138,7 +139,8 @@ public class FlowArrowPlugin extends Plugin implements MarginProvider, OptionsCh
} }
@Override @Override
public void setPixelMap(VerticalPixelAddressMap pixmap) { public void setProgram(Program program, AddressIndexMap addrMap,
VerticalPixelAddressMap pixmap) {
this.layoutToPixel = pixmap; this.layoutToPixel = pixmap;
validateState(); validateState();
updateFlowArrows(); updateFlowArrows();
@ -334,9 +336,10 @@ public class FlowArrowPlugin extends Plugin implements MarginProvider, OptionsCh
} }
} }
/** /**
* Iterate over each other FlowArrow object to check overlaps * Iterate over each other FlowArrow object to check overlaps
* @return FlowArrow objects that have a start/end address in common *
* @return FlowArrow objects that have a start/end address in common
*/ */
private List<FlowArrow> getArrowsAtSameDepth(FlowArrow jump, List<FlowArrow> allArrows) { private List<FlowArrow> getArrowsAtSameDepth(FlowArrow jump, List<FlowArrow> allArrows) {
@ -430,8 +433,9 @@ public class FlowArrowPlugin extends Plugin implements MarginProvider, OptionsCh
List<FlowArrow> results = new ArrayList<>(); List<FlowArrow> results = new ArrayList<>();
ArrowCache arrowCache = new ArrowCache(); ArrowCache arrowCache = new ArrowCache();
CodeUnitIterator it = program.getListing().getCodeUnitIterator( CodeUnitIterator it = program.getListing()
CodeUnit.INSTRUCTION_PROPERTY, screenAddresses, true); .getCodeUnitIterator(
CodeUnit.INSTRUCTION_PROPERTY, screenAddresses, true);
while (it.hasNext()) { while (it.hasNext()) {
CodeUnit cu = it.next(); CodeUnit cu = it.next();
@ -479,14 +483,12 @@ public class FlowArrowPlugin extends Plugin implements MarginProvider, OptionsCh
/** /**
* Unusual Code: We keep arrows in 3 sets: all arrows, selected arrows, and active arrows. * Unusual Code: We keep arrows in 3 sets: all arrows, selected arrows, and active arrows.
* Further, we rebuild arrows as the screen moves, causing the x coordinate * Further, we rebuild arrows as the screen moves, causing the x coordinate to change as arrows
* to change as arrows that are no longer on the screen are removed and * that are no longer on the screen are removed and as new arrows are added. We want to make
* as new arrows are added. We want to make sure that we don't end up * sure that we don't end up with an arrow in the selected/active sets that are the same as the
* with an arrow in the selected/active sets that are the same as the one * one in the 'all' set, but with a different width. This causes both arrows to become
* in the 'all' set, but with a different width. This causes both arrows * visible--basically, the selected arrows can become stale as their width changes. This code is
* to become visible--basically, the selected arrows can become stale as * meant to address this out-of-sync behavior.
* their width changes. This code is meant to address this out-of-sync
* behavior.
* *
* @param arrow the updated form of the arrow * @param arrow the updated form of the arrow
*/ */
@ -543,7 +545,8 @@ public class FlowArrowPlugin extends Plugin implements MarginProvider, OptionsCh
Address bottomAddr = layoutToPixel.getLayoutAddress(n - 1); Address bottomAddr = layoutToPixel.getLayoutAddress(n - 1);
if (bottomAddr != null) { if (bottomAddr != null) {
AddressSpace testSpace = bottomAddr.getAddressSpace(); AddressSpace testSpace = bottomAddr.getAddressSpace();
validState = (program.getAddressFactory().getAddressSpace( validState = (program.getAddressFactory()
.getAddressSpace(
testSpace.getSpaceID()) == testSpace); testSpace.getSpaceID()) == testSpace);
} }
} }

View file

@ -17,46 +17,37 @@ package ghidra.app.plugin.core.marker;
import ghidra.GhidraOptions; import ghidra.GhidraOptions;
import ghidra.app.CorePluginPackage; import ghidra.app.CorePluginPackage;
import ghidra.app.events.ProgramActivatedPluginEvent;
import ghidra.app.events.ProgramClosedPluginEvent;
import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.services.*; import ghidra.app.services.*;
import ghidra.app.util.HelpTopics; import ghidra.app.util.HelpTopics;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.PluginStatus; import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
/** /**
* Plugin to manage marker and navigation panels. * Plugin to manage marker and navigation panels.
*
*
*/ */
//@formatter:off
@PluginInfo( @PluginInfo(
status = PluginStatus.RELEASED, status = PluginStatus.RELEASED,
packageName = CorePluginPackage.NAME, packageName = CorePluginPackage.NAME,
category = PluginCategoryNames.SUPPORT, category = PluginCategoryNames.SUPPORT,
shortDescription = "Provides the marker display", shortDescription = "Provides the marker display",
description = "This plugin extends the code browser to include left and right marker" description = "This plugin extends the code browser to include left and right marker" +
+ "components. The left margin shows marks related to the address being shown at " "components. The left margin shows marks related to the address being shown at " +
+ "that location. The right margin shows marks at a position that is relative to " "that location. The right margin shows marks at a position that is relative to " +
+ "an addresses within the overall program (Overview). This plugin also provides " "an addresses within the overall program (Overview). This plugin also provides " +
+ "a service that other plugins can use to display markers. Two types of markers are " "a service that other plugins can use to display markers. Two types of markers are " +
+ "supported; point markers and area markers. Area markers are used to indicate a range " "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 " "value such as selection. Point markers are used to represent individual addresses such " +
+ "as bookmarks.", "as bookmarks.",
servicesRequired = { CodeViewerService.class, GoToService.class }, servicesRequired = { CodeViewerService.class, GoToService.class },
servicesProvided = { MarkerService.class }, servicesProvided = { MarkerService.class },
eventsConsumed = { ProgramActivatedPluginEvent.class, ProgramClosedPluginEvent.class } eventsConsumed = {})
)
//@formatter:on
public class MarkerManagerPlugin extends Plugin { public class MarkerManagerPlugin extends Plugin {
private CodeViewerService codeViewerService; private CodeViewerService codeViewerService;
private MarkerManager markerManager; private MarkerManager markerManager;
private Program program;
/** /**
* @param tool * @param tool
@ -87,23 +78,4 @@ public class MarkerManagerPlugin extends Plugin {
codeViewerService.addMarginProvider(markerManager.getMarginProvider()); codeViewerService.addMarginProvider(markerManager.getMarginProvider());
codeViewerService.addOverviewProvider(markerManager.getOverviewProvider()); codeViewerService.addOverviewProvider(markerManager.getOverviewProvider());
} }
@Override
public void processEvent(PluginEvent event) {
if (event instanceof ProgramActivatedPluginEvent) {
ProgramActivatedPluginEvent ev = (ProgramActivatedPluginEvent) event;
Program oldProgram = program;
program = ev.getActiveProgram();
if (oldProgram != null) {
markerManager.setProgram(null);
}
if (program != null) {
markerManager.setProgram(program);
}
}
else if (event instanceof ProgramClosedPluginEvent) {
markerManager.programClosed(((ProgramClosedPluginEvent) event).getProgram());
}
}
} }

View file

@ -0,0 +1,112 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.marker;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JComponent;
import docking.widgets.fieldpanel.FieldPanel;
import ghidra.app.services.MarkerService;
import ghidra.app.services.MarkerSet;
import ghidra.app.util.viewer.listingpanel.*;
import ghidra.app.util.viewer.util.AddressIndexMap;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.util.MarkerLocation;
/**
* The provider which renders the marker margin, usually placed to the left of listing
* {@link FieldPanel}s.
*
* <p>
* These are managed by a {@link MarkerManager}. Obtain one via
* {@link MarkerService#createMarginProvider()}.
*/
public class MarkerMarginProvider implements MarginProvider {
private final MarkerManager markerManager;
private final MarkerPanel markerPanel;
private Program program;
private VerticalPixelAddressMap pixmap;
MarkerMarginProvider(MarkerManager markerManager) {
this.markerManager = markerManager;
this.markerPanel = new MarkerPanel(markerManager);
this.markerPanel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
MarkerClickedListener markerClickedListener =
markerManager.getMarkerClickedListener();
if (e.getClickCount() != 2 || markerClickedListener == null) {
return;
}
MarkerLocation location = getMarkerLocation(e.getX(), e.getY());
markerClickedListener.markerDoubleClicked(location);
}
});
}
void repaintPanel() {
markerPanel.repaint();
}
@Override
public JComponent getComponent() {
return markerPanel;
}
private Address getAddress(int y) {
if (pixmap == null) {
return null;
}
int i = pixmap.findLayoutAt(y);
return pixmap.getLayoutAddress(i);
}
@Override
public MarkerLocation getMarkerLocation(int x, int y) {
Address addr = getAddress(y);
if (addr == null) {
return null;
}
MarkerSet marker = markerManager.getMarkerSet(program, addr);
return new MarkerLocation(marker, program, addr, x, y);
}
@Override
public boolean isResizeable() {
return false;
}
@Override
public void setProgram(Program program, AddressIndexMap addrMap,
VerticalPixelAddressMap pixmap) {
this.program = program;
this.pixmap = pixmap;
this.markerPanel.setProgram(program, addrMap, pixmap);
markerManager.updateMarkerSets(program, true, false, true);
}
/*testing*/ String generateToolTip(MouseEvent event) {
return markerPanel.generateToolTip(event);
}
}

View file

@ -0,0 +1,346 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.marker;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.*;
import java.util.Map.Entry;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import docking.ActionContext;
import docking.action.*;
import docking.widgets.fieldpanel.FieldPanel;
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.util.AddressIndexMap;
import ghidra.framework.options.*;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation;
import ghidra.util.Swing;
/**
* The provider which renders the overview margin, usually placed outside the scrollbar to the right
* of lisitng {@link FieldPanel}s.
*
* <p>
* These are managed by a {@link MarkerManager}. Obtain one via
* {@link MarkerService#createOverviewProvider()}.
*/
public class MarkerOverviewProvider implements OverviewProvider {
private final PluginTool tool;
private final String owner;
private final MarkerManager markerManager;
private final NavigationPanel navigationPanel;
private final MarkerActionList actionList;
private Program program;
MarkerOverviewProvider(String owner, PluginTool tool, MarkerManager markerManager) {
this.tool = tool;
this.owner = owner;
this.markerManager = markerManager;
this.navigationPanel = new NavigationPanel(markerManager);
this.navigationPanel.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
markerManager.updateMarkerSets(program, false, true, true);
}
});
actionList = new MarkerActionList();
}
void dispose() {
actionList.dispose();
}
public void repaintPanel() {
navigationPanel.repaint();
}
@Override
public JComponent getComponent() {
return navigationPanel;
}
@Override
public void setProgram(Program program, AddressIndexMap map) {
this.program = program;
navigationPanel.setProgram(program, map);
markerManager.updateMarkerSets(program, true, true, false);
actionList.refresh();
}
@Override
public void setNavigatable(Navigatable navigatable) {
navigationPanel.setNavigatable(navigatable);
}
void refreshActionList(Program p) {
if (this.program != p) {
return;
}
actionList.refresh();
}
//==================================================================================================
// Inner Classes
//==================================================================================================
/**
* Marker Option Menu - controls the visibility of the various markers.
*/
private class MarkerActionList implements OptionsChangeListener {
private final List<DockingAction> actions = new ArrayList<>();
private ToolOptions listOptions;
MarkerActionList() {
initOptions();
refresh();
}
private void initOptions() {
listOptions = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_NAVIGATION_MARKERS);
listOptions.removeOptionsChangeListener(this);
listOptions.addOptionsChangeListener(this);
}
@Override
public void optionsChanged(ToolOptions options, String name, Object oldValue,
Object newValue) {
for (DockingAction action : actions) {
if (action instanceof ActivateMarkerAction) {
((ActivateMarkerAction) action).optionsChanged();
}
if (action instanceof ActivateMarkerGroupAction) {
((ActivateMarkerGroupAction) action).optionsChanged();
}
}
}
void refresh() {
Swing.runLater(this::doRefresh);
}
private void doRefresh() {
if (program == null) {
return;
}
for (DockingAction action : actions) {
tool.removeAction(action);
}
actions.clear();
List<MarkerSetImpl> list = markerManager.copyMarkerSets(program);
// separate the marker sets into grouped and non-grouped
List<List<MarkerSetImpl>> groupsList = extractManagerGroups(list);
Collections.sort(groupsList,
(ms1, ms2) -> ms1.get(0).getName().compareTo(ms2.get(0).getName()));
for (List<MarkerSetImpl> group : groupsList) {
ActivateMarkerGroupAction action =
new ActivateMarkerGroupAction(owner, group, navigationPanel, listOptions);
actions.add(action);
tool.addAction(action);
}
Collections.sort(list, (ms1, ms2) -> ms1.getName().compareTo(ms2.getName()));
for (MarkerSetImpl mgr : list) {
ActivateMarkerAction action =
new ActivateMarkerAction(owner, mgr, navigationPanel, listOptions);
actions.add(action);
tool.addAction(action);
}
navigationPanel.repaint();
}
/**
* Creates a list of elements that are in the same logical group and removes those elements
* from the given list.
*/
private List<List<MarkerSetImpl>> extractManagerGroups(List<MarkerSetImpl> fromList) {
// empty the original list for grouping...
Map<String, List<MarkerSetImpl>> nameToManagerMap = new HashMap<>();
for (Iterator<MarkerSetImpl> iterator = fromList.iterator(); iterator.hasNext();) {
MarkerSetImpl markerSetImpl = iterator.next();
String name = markerSetImpl.getName();
List<MarkerSetImpl> subList = nameToManagerMap.get(name);
if (subList == null) {
subList = new ArrayList<>();
nameToManagerMap.put(name, subList);
}
subList.add(markerSetImpl);
iterator.remove();
}
// ...now repopulate the original list with all non-group managers and put the groups
// in their own list
List<List<MarkerSetImpl>> groupList = new ArrayList<>(fromList.size());
Set<Entry<String, List<MarkerSetImpl>>> entrySet = nameToManagerMap.entrySet();
for (Entry<String, List<MarkerSetImpl>> entry : entrySet) {
List<MarkerSetImpl> listValue = entry.getValue();
// non-group list
if (listValue.size() == 1) {
fromList.add(listValue.get(0));
}
// group list
else {
groupList.add(listValue);
}
}
return groupList;
}
void dispose() {
listOptions.removeOptionsChangeListener(this);
actions.forEach(a -> tool.removeAction(a));
}
}
private static class ActivateMarkerAction extends ToggleDockingAction {
private MarkerSetImpl markers;
private NavigationPanel panel;
private Options options;
ActivateMarkerAction(String owner, MarkerSetImpl markers, NavigationPanel panel,
Options options) {
super(markers.getName(), owner);
this.markers = markers;
this.panel = panel;
this.options = options;
HelpLocation helpLocation = new HelpLocation(HelpTopics.CODE_BROWSER, "Markers");
options.registerOption(markers.getName(), true, helpLocation,
"This options enables/disables the display of " + markers.getName() +
" marker types.");
setEnabled(true);
setSelected(markers.active);
setPopupMenuData(
new MenuData(new String[] { markers.getName() }, markers.getNavIcon(), null));
boolean isEnabled = isOptionEnabled();
setSelected(isEnabled);
markers.setActive(isEnabled);
HelpLocation location = new HelpLocation(HelpTopics.CODE_BROWSER, "Markers");
setHelpLocation(location);
}
@Override
public boolean isEnabledForContext(ActionContext context) {
Object contextObject = context.getContextObject();
return contextObject == panel;
}
void optionsChanged() {
boolean selected = isOptionEnabled();
if (selected != isSelected()) {
setSelected(selected);
markers.setActive(selected);
}
}
private boolean isOptionEnabled() {
return options.getBoolean(markers.getName(), true);
}
@Override
public void actionPerformed(ActionContext context) {
options.setBoolean(markers.getName(), isSelected());
markers.setActive(isSelected());
}
}
private static class ActivateMarkerGroupAction extends ToggleDockingAction {
private List<MarkerSetImpl> markerSets;
private NavigationPanel panel;
private Options options;
ActivateMarkerGroupAction(String owner, List<MarkerSetImpl> managerList,
NavigationPanel panel, Options options) {
super(managerList.get(0).getName(), owner);
this.markerSets = managerList;
this.panel = panel;
this.options = options;
HelpLocation helpLocation = new HelpLocation(HelpTopics.CODE_BROWSER, "Markers");
options.registerOption(getName(), true, helpLocation,
"This options enables/disables the display of " + getName() + " marker types.");
setEnabled(true);
setSelected(isActive());
ImageIcon icon = managerList.get(0).getNavIcon();
setPopupMenuData(new MenuData(new String[] { getName() }, icon));
boolean isEnabled = isOptionEnabled();
setSelected(isEnabled);
setActive(isEnabled);
setHelpLocation(helpLocation);
}
private void setActive(boolean active) {
for (MarkerSetImpl manager : markerSets) {
manager.setActive(active);
}
}
private boolean isActive() {
return markerSets.stream().anyMatch(markers -> markers.isActive());
}
@Override
public boolean isEnabledForContext(ActionContext context) {
Object contextObject = context.getContextObject();
return contextObject == panel;
}
void optionsChanged() {
boolean selected = isOptionEnabled();
if (selected != isSelected()) {
setSelected(selected);
setActive(selected);
}
}
private boolean isOptionEnabled() {
return options.getBoolean(getName(), true);
}
@Override
public void actionPerformed(ActionContext context) {
options.setBoolean(getName(), isSelected());
setActive(isSelected());
}
}
}

View file

@ -15,36 +15,91 @@
*/ */
package ghidra.app.plugin.core.marker; package ghidra.app.plugin.core.marker;
import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.util.List;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.ToolTipManager; import javax.swing.ToolTipManager;
import docking.widgets.fieldpanel.FieldPanel;
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;
/** /**
* Panel to display markers. Normally placed to the left hand side * Panel to display markers. Normally placed to the left hand side of the scrolled
* of the scrolled field panel. * {@link FieldPanel}.
*/ */
public class MarkerPanel extends JPanel { public class MarkerPanel extends JPanel {
private MarkerManager manager; private MarkerManager manager;
private Program program;
private AddressIndexMap addrMap;
private VerticalPixelAddressMap pixmap;
MarkerPanel(MarkerManager manager) { MarkerPanel(MarkerManager manager) {
super(); super();
this.manager = manager; this.manager = manager;
this.setPreferredSize(new Dimension(16, 1));
ToolTipManager.sharedInstance().registerComponent(this); ToolTipManager.sharedInstance().registerComponent(this);
} }
void setProgram(Program program, AddressIndexMap addrMap, VerticalPixelAddressMap pixmap) {
this.program = program;
this.addrMap = addrMap;
this.pixmap = pixmap;
}
@Override @Override
protected void paintComponent(Graphics g) { protected void paintComponent(Graphics g) {
super.paintComponent(g); super.paintComponent(g);
manager.paintMarkers(program, g, pixmap, addrMap);
manager.paintMarkers(g);
} }
@Override @Override
public String getToolTipText(MouseEvent event) { public String getToolTipText(MouseEvent event) {
return manager.getTooltip(event); String tip = generateToolTip(event);
manager.showToolTipPopup(event, tip);
return null; // signal not to show a Java tooltip
}
private static String toHTML(List<String> lines) {
if (lines.isEmpty()) {
return null;
}
StringBuilder buffy = new StringBuilder("<html><font size=\"" + 4 + "\">");
for (String string : lines) {
buffy.append(string).append("<BR>");
}
return buffy.toString();
}
String generateToolTip(MouseEvent event) {
if (pixmap == null) {
return null;
}
int y = event.getY();
int x = event.getX();
int layoutIndex = pixmap.findLayoutAt(y);
Address layoutAddress = pixmap.getLayoutAddress(layoutIndex);
if (layoutAddress == null) {
return null;
}
List<String> lines = getMarkerTooltipLines(y, x, layoutIndex, layoutAddress);
return toHTML(lines);
}
private List<String> getMarkerTooltipLines(int y, int x, int layoutIndex,
Address layoutAddress) {
Address endAddr = pixmap.getLayoutEndAddress(layoutIndex);
return manager.getMarkerTooltipLines(program, y, layoutIndex, layoutAddress, endAddr);
} }
} }

View file

@ -41,7 +41,7 @@ import ghidra.util.datastruct.SortedRangeList;
abstract class MarkerSetImpl implements MarkerSet { abstract class MarkerSetImpl implements MarkerSet {
protected MarkerManager mgr; protected MarkerManager mgr;
private Program program; protected Program program;
private String name; private String name;
protected String description; protected String description;
@ -50,6 +50,8 @@ abstract class MarkerSetImpl implements MarkerSet {
protected AddressSetCollection markers; protected AddressSetCollection markers;
protected SortedRangeList overview = null; protected SortedRangeList overview = null;
protected VerticalPixelAddressMap activePixmap = null;
protected List<Integer> activeLayouts = null; protected List<Integer> activeLayouts = null;
protected Color markerColor; protected Color markerColor;
@ -98,6 +100,7 @@ abstract class MarkerSetImpl implements MarkerSet {
/** /**
* Returns the Navigator Icon for this marker set * Returns the Navigator Icon for this marker set
*
* @return the Navigator Icon for this marker set * @return the Navigator Icon for this marker set
*/ */
public abstract ImageIcon getNavIcon(); public abstract ImageIcon getNavIcon();
@ -248,11 +251,10 @@ abstract class MarkerSetImpl implements MarkerSet {
} }
} }
public final void paintNavigation(Graphics g, int height, NavigationPanel panel, public final void paintNavigation(Graphics g, int height, int width, AddressIndexMap map) {
AddressIndexMap map) {
if (showNavigation) { if (showNavigation) {
SortedRangeList newOverview = computeNavigationIndexes(height, map); SortedRangeList newOverview = computeNavigationIndices(height, map);
doPaintNavigation(g, height, panel.getWidth(), newOverview); doPaintNavigation(g, height, width, newOverview);
} }
} }
@ -293,7 +295,7 @@ abstract class MarkerSetImpl implements MarkerSet {
return null; return null;
} }
if (activeLayouts != null) { if (activeLayouts != null && activePixmap == pixmap) {
return activeLayouts; // use cache return activeLayouts; // use cache
} }
@ -311,19 +313,19 @@ abstract class MarkerSetImpl implements MarkerSet {
} }
} }
activePixmap = pixmap;
activeLayouts = newLayouts; activeLayouts = newLayouts;
return newLayouts; return newLayouts;
} }
private SortedRangeList computeNavigationIndexes(int height, AddressIndexMap map) { private SortedRangeList computeNavigationIndices(int height, AddressIndexMap map) {
lastHeight = height;
double numIndexes = map.getIndexCount().doubleValue(); double numIndexes = map.getIndexCount().doubleValue();
if (markers.isEmpty() || height == 0 || numIndexes == 0) { if (markers.isEmpty() || height == 0 || numIndexes == 0) {
return null; return null;
} }
if (overview != null) { if (overview != null && lastHeight == height) {
return overview; // use cache return overview; // use cache
} }
@ -376,6 +378,7 @@ abstract class MarkerSetImpl implements MarkerSet {
} }
} }
lastHeight = height;
overview = newOverview; overview = newOverview;
return newOverview; return newOverview;
} }
@ -391,7 +394,7 @@ abstract class MarkerSetImpl implements MarkerSet {
*/ */
public String getTooltip(Address addr, int x, int y) { public String getTooltip(Address addr, int x, int y) {
if (markerDescriptor != null) { if (markerDescriptor != null) {
MarkerLocation loc = new MarkerLocation(this, mgr.getProgram(), addr, x, y); MarkerLocation loc = new MarkerLocation(this, program, addr, x, y);
return markerDescriptor.getTooltip(loc); return markerDescriptor.getTooltip(loc);
} }
return null; return null;
@ -421,7 +424,10 @@ abstract class MarkerSetImpl implements MarkerSet {
public ProgramLocation getProgramLocation(int y, int height, AddressIndexMap map, int x) { public ProgramLocation getProgramLocation(int y, int height, AddressIndexMap map, int x) {
assertSwing(); assertSwing();
if (overview == null) { // Many overview panels can be rendering this marker set, each having its own height.
// If the height does not match that from the last-computed indices, we need to recompute.
computeNavigationIndices(height, map);
if (overview == null || lastHeight != height) {
return null; return null;
} }
@ -455,12 +461,12 @@ abstract class MarkerSetImpl implements MarkerSet {
addr = set.getMinAddress(); addr = set.getMinAddress();
} }
if (markerDescriptor != null) { if (markerDescriptor != null) {
MarkerLocation ml = new MarkerLocation(this, mgr.getProgram(), addr, x, y); MarkerLocation ml = new MarkerLocation(this, program, addr, x, y);
loc = markerDescriptor.getProgramLocation(ml); loc = markerDescriptor.getProgramLocation(ml);
} }
if (loc == null) { if (loc == null) {
loc = new ProgramLocation(mgr.getProgram(), addr); loc = new ProgramLocation(program, addr);
} }
} }
return loc; return loc;

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,23 +15,35 @@
*/ */
package ghidra.app.plugin.core.marker; package ghidra.app.plugin.core.marker;
import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.event.*; import java.awt.event.*;
import javax.swing.JPanel; import javax.swing.JPanel;
import docking.widgets.fieldpanel.FieldPanel;
import ghidra.app.nav.Navigatable;
import ghidra.app.util.viewer.util.AddressIndexMap;
import ghidra.program.model.listing.Program;
/** /**
* Panel to display an overview of all markers placed within a scrolled * Panel to display an overview of all markers placed within a scrolled {@link FieldPanel}. Normally
* FieldPanel. * placed to the right of the scrolled panel.
* Normally placed to the right of the scrolled panel.
*/ */
public class NavigationPanel extends JPanel { public class NavigationPanel extends JPanel {
private MarkerManager manager; private MarkerManager manager;
private Navigatable navigatable;
private Program program;
private AddressIndexMap addrMap;
NavigationPanel(MarkerManager manager) { NavigationPanel(MarkerManager manager) {
super(); super();
this.manager = manager; this.manager = manager;
this.setPreferredSize(new Dimension(16, 1));
init(); init();
} }
@ -41,12 +52,11 @@ public class NavigationPanel extends JPanel {
addMouseListener(new MouseAdapter() { addMouseListener(new MouseAdapter() {
@Override @Override
public void mousePressed(MouseEvent e) { public void mousePressed(MouseEvent e) {
if ((e.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0) {
if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) { manager.navigateTo(navigatable, program, e.getX(), e.getY(), getViewHeight(),
manager.navigateTo(e.getX(), e.getY()); addrMap);
} }
} }
}); });
} }
@ -56,7 +66,23 @@ public class NavigationPanel extends JPanel {
@Override @Override
protected void paintComponent(Graphics g) { protected void paintComponent(Graphics g) {
super.paintComponent(g); super.paintComponent(g);
manager.paintNavigation(g, this); paintNavigation(g);
} }
void paintNavigation(Graphics g) {
manager.paintNavigation(program, g, this, addrMap);
}
void setNavigatable(Navigatable navigatable) {
this.navigatable = navigatable;
}
void setProgram(Program program, AddressIndexMap map) {
this.program = program;
this.addrMap = map;
}
public int getViewHeight() {
return getHeight() - MarkerSetImpl.MARKER_HEIGHT;
}
} }

View file

@ -39,14 +39,15 @@ class PointMarkerSet extends MarkerSetImpl {
private Color fillColor; private Color fillColor;
/** /**
* @param navigationManager manager for these point markers * @param navigationManager manager for these point markers
* @param name the name for this point marker * @param name the name for this point marker
* @param desc the description associated with this point marker * @param desc the description associated with this point marker
* @param priority to sort out what displays on top, higher is more likely to be on top * @param priority to sort out what displays on top, higher is more likely to be on top
* @param showMarkers true indicates to show area markers (on the left side of the browser.) * @param showMarkers true indicates to show area markers (on the left side of the browser.)
* @param showNavigation true indicates to show area navigation markers (on the right side of the browser.) * @param showNavigation true indicates to show area navigation markers (on the right side of
* @param colorBackground colorBackground the color of marked areas in navigation bar * the browser.)
* If color is null, no results are displayed in the associated marker bar. * @param colorBackground colorBackground the color of marked areas in navigation bar If color
* is null, no results are displayed in the associated marker bar.
* @param markerColor the color of the marker * @param markerColor the color of the marker
* @param icon the icon used to represent the cursor in the marker margin * @param icon the icon used to represent the cursor in the marker margin
* @param isPreferred true indicates higher priority than all non-preferred MarkerSets * @param isPreferred true indicates higher priority than all non-preferred MarkerSets
@ -70,14 +71,15 @@ class PointMarkerSet extends MarkerSetImpl {
} }
/** /**
* @param navigationManager manager for these point markers * @param navigationManager manager for these point markers
* @param name the name for this point marker * @param name the name for this point marker
* @param desc the description associated with this point marker * @param desc the description associated with this point marker
* @param priority to sort out what displays on top, higher is more likely to be on top * @param priority to sort out what displays on top, higher is more likely to be on top
* @param showMarkers true indicates to show area markers (on the left side of the browser.) * @param showMarkers true indicates to show area markers (on the left side of the browser.)
* @param showNavigation true indicates to show area navigation markers (on the right side of the browser.) * @param showNavigation true indicates to show area navigation markers (on the right side of
* @param colorBackground colorBackground the color of marked areas in navigation bar * the browser.)
* If color is null, no results are displayed in the associated marker bar. * @param colorBackground colorBackground the color of marked areas in navigation bar If color
* is null, no results are displayed in the associated marker bar.
* @param markerColor the color of the marker * @param markerColor the color of the marker
* @param icon the icon used to represent the cursor in the marker margin * @param icon the icon used to represent the cursor in the marker margin
* @param program the program to which the markers apply * @param program the program to which the markers apply
@ -115,7 +117,6 @@ class PointMarkerSet extends MarkerSetImpl {
} }
Address address = pixmap.getLayoutAddress(i); Address address = pixmap.getLayoutAddress(i);
Program program = mgr.getProgram();
MarkerLocation loc = new MarkerLocation(this, program, address, 0, yStart); MarkerLocation loc = new MarkerLocation(this, program, address, 0, yStart);
ImageIcon icon = markerDescriptor.getIcon(loc); ImageIcon icon = markerDescriptor.getIcon(loc);
if (icon != null) { if (icon != null) {

View file

@ -26,15 +26,17 @@ import javax.swing.*;
import docking.action.DockingActionIf; import docking.action.DockingActionIf;
import docking.help.Help; import docking.help.Help;
import ghidra.app.nav.Navigatable;
import ghidra.app.services.GoToService; import ghidra.app.services.GoToService;
import ghidra.app.util.viewer.listingpanel.OverviewProvider; import ghidra.app.util.viewer.listingpanel.OverviewProvider;
import ghidra.app.util.viewer.util.AddressIndexMap; import ghidra.app.util.viewer.util.AddressIndexMap;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.util.task.SwingUpdateManager; import ghidra.util.task.SwingUpdateManager;
/** /**
* Overview bar component. Uses color to indicate various address based properties for a program. * 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. * 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 OverviewProvider {
@ -44,6 +46,7 @@ public class OverviewColorComponent extends JPanel implements OverviewProvider {
private final SwingUpdateManager refreshUpdater = private final SwingUpdateManager refreshUpdater =
new SwingUpdateManager(100, 15000, () -> doRefresh()); new SwingUpdateManager(100, 15000, () -> doRefresh());
private AddressIndexMap map; private AddressIndexMap map;
private Navigatable navigatable;
private PluginTool tool; private PluginTool tool;
private List<DockingActionIf> actions; private List<DockingActionIf> actions;
@ -52,7 +55,7 @@ public class OverviewColorComponent extends JPanel implements OverviewProvider {
* *
* @param tool the PluginTool * @param tool the PluginTool
* @param overviewColorService the {@link OverviewColorService} that provides colors for various * @param overviewColorService the {@link OverviewColorService} that provides colors for various
* addresses. * addresses.
*/ */
public OverviewColorComponent(PluginTool tool, OverviewColorService overviewColorService) { public OverviewColorComponent(PluginTool tool, OverviewColorService overviewColorService) {
this.tool = tool; this.tool = tool;
@ -104,7 +107,7 @@ public class OverviewColorComponent extends JPanel implements OverviewProvider {
protected void gotoAddress(Address address) { protected void gotoAddress(Address address) {
GoToService gotoService = tool.getService(GoToService.class); GoToService gotoService = tool.getService(GoToService.class);
if (gotoService != null) { if (gotoService != null) {
gotoService.goTo(address); gotoService.goTo(navigatable, address);
} }
} }
@ -194,12 +197,17 @@ public class OverviewColorComponent extends JPanel implements OverviewProvider {
} }
@Override @Override
public void setAddressIndexMap(AddressIndexMap map) { public void setProgram(Program program, AddressIndexMap map) {
this.map = map; this.map = map;
colors = new Color[getOverviewPixelCount()]; colors = new Color[getOverviewPixelCount()];
refreshUpdater.updateLater(); refreshUpdater.updateLater();
} }
@Override
public void setNavigatable(Navigatable n) {
this.navigatable = n;
}
/** /**
* Causes this component to completely compute the colors used to paint the overview bar. * Causes this component to completely compute the colors used to paint the overview bar.
*/ */
@ -210,6 +218,7 @@ public class OverviewColorComponent extends JPanel implements OverviewProvider {
/** /**
* Causes the component to refresh any colors for the given address range. * Causes the component to refresh any colors for the given address range.
*
* @param start the start of the address range to refresh. * @param start the start of the address range to refresh.
* @param end the end of the address range to refresh. * @param end the end of the address range to refresh.
*/ */
@ -232,6 +241,7 @@ public class OverviewColorComponent extends JPanel implements OverviewProvider {
/** /**
* Returns the PluginTool * Returns the PluginTool
*
* @return the PluginTool * @return the PluginTool
*/ */
public PluginTool getTool() { public PluginTool getTool() {

View file

@ -20,7 +20,7 @@ import java.awt.Color;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.event.ChangeListener; import javax.swing.event.ChangeListener;
import ghidra.app.plugin.core.marker.MarkerManagerPlugin; import ghidra.app.plugin.core.marker.*;
import ghidra.app.util.viewer.listingpanel.MarkerClickedListener; import ghidra.app.util.viewer.listingpanel.MarkerClickedListener;
import ghidra.framework.plugintool.ServiceInfo; import ghidra.framework.plugintool.ServiceInfo;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
@ -28,8 +28,8 @@ import ghidra.program.model.listing.Program;
/** /**
* <p> * <p>
* Service to manage navigation markers displayed around a scrollable window like the Listing. * Service to manage navigation markers displayed around a scrollable window like the Listing. The
* The navigation bar displays the general location of markers for the entire view. The marker bar * navigation bar displays the general location of markers for the entire view. The marker bar
* displays a marker at each marked address visible within the view. * displays a marker at each marked address visible within the view.
* </p> * </p>
* <p> * <p>
@ -39,16 +39,18 @@ import ghidra.program.model.listing.Program;
* </p> * </p>
* <a name="usage"></a> <u>Recommended Usage</u><br> * <a name="usage"></a> <u>Recommended Usage</u><br>
* <u>Recommended Usage</u><br> * <u>Recommended Usage</u><br>
* The service used to work independently of {@link Program}s. In order to work effectively this * The service used to work independently of {@link Program}s. In order to work effectively this
* service has been changed to associate created markers with individual programs. Thus, it is * service has been changed to associate created markers with individual programs. Thus, it is up to
* up to the clients of this class perform lifecycle management of markers created by this * the clients of this class perform lifecycle management of markers created by this service. For
* service. For example, a client that creates a marker from * example, a client that creates a marker from
* {@link #createAreaMarker(String, String, Program, int, boolean, boolean, boolean, Color)} should * {@link #createAreaMarker(String, String, Program, int, boolean, boolean, boolean, Color)} should
* call {@link #removeMarker(MarkerSet, Program)} when the markers are no longer used, such as when * call {@link #removeMarker(MarkerSet, Program)} when the markers are no longer used, such as when
* a program has become deactivated. In this example usage markers are added and removed as the * a program has become deactivated. In this example usage markers are added and removed as the user
* user tabs through open programs. * tabs through open programs.
*/ */
@ServiceInfo(defaultProvider = MarkerManagerPlugin.class, description = "Service to manage navigation markers displayed around a scrollable window.") @ServiceInfo(
defaultProvider = MarkerManagerPlugin.class,
description = "Service to manage navigation markers displayed around a scrollable window.")
public interface MarkerService { public interface MarkerService {
/** /**
@ -104,7 +106,7 @@ public interface MarkerService {
public final static int REFERENCE_PRIORITY = -10; public final static int REFERENCE_PRIORITY = -10;
/** /**
* A group name for highlights. This is intended to be used with * A group name for highlights. This is intended to be used with
* {@link #setMarkerForGroup(String, MarkerSet, Program)} and * {@link #setMarkerForGroup(String, MarkerSet, Program)} and
* {@link #removeMarkerForGroup(String, MarkerSet, Program)} * {@link #removeMarkerForGroup(String, MarkerSet, Program)}
*/ */
@ -118,7 +120,8 @@ public interface MarkerService {
* @param program The program with which the created markers will be associated. * @param program The program with which the created markers will be associated.
* @param priority to sort out what displays on top, higher is more likely to be on top * @param priority to sort out what displays on top, higher is more likely to be on top
* @param showMarkers true indicates to show area markers (on the left side of the browser.) * @param showMarkers true indicates to show area markers (on the left side of the browser.)
* @param showNavigation true indicates to show area navigation markers (on the right side of the browser.) * @param showNavigation true indicates to show area navigation markers (on the right side of
* the browser.)
* @param colorBackground if true, then the browser's background color will reflect the marker. * @param colorBackground if true, then the browser's background color will reflect the marker.
* @param color the color of marked areas. * @param color the color of marked areas.
* @return set of navigation markers * @return set of navigation markers
@ -135,7 +138,8 @@ public interface MarkerService {
* @param program The program with which the created markers will be associated. * @param program The program with which the created markers will be associated.
* @param priority to sort out what displays on top, higher is more likely to be on top * @param priority to sort out what displays on top, higher is more likely to be on top
* @param showMarkers true indicates to show area markers (on the left side of the browser.) * @param showMarkers true indicates to show area markers (on the left side of the browser.)
* @param showNavigation true indicates to show area navigation markers (on the right side of the browser.) * @param showNavigation true indicates to show area navigation markers (on the right side of
* the browser.)
* @param colorBackground if true, then the browser's background color will reflect the marker. * @param colorBackground if true, then the browser's background color will reflect the marker.
* @param color the color of marked areas. * @param color the color of marked areas.
* @param isPreferred true indicates higher priority than all non-preferred MarkerSets * @param isPreferred true indicates higher priority than all non-preferred MarkerSets
@ -153,7 +157,8 @@ public interface MarkerService {
* @param program The program with which the created markers will be associated. * @param program The program with which the created markers will be associated.
* @param priority to sort out what displays on top, higher is more likely to be on top * @param priority to sort out what displays on top, higher is more likely to be on top
* @param showMarkers true indicates to show area markers (on the left side of the browser.) * @param showMarkers true indicates to show area markers (on the left side of the browser.)
* @param showNavigation true indicates to show area navigation markers (on the right side of the browser.) * @param showNavigation true indicates to show area navigation markers (on the right side of
* the browser.)
* @param colorBackground if true, then the browser's background color will reflect the marker. * @param colorBackground if true, then the browser's background color will reflect the marker.
* @param color the color of marked areas in navigation bar * @param color the color of marked areas in navigation bar
* @param icon icon to display in marker bar * @param icon icon to display in marker bar
@ -171,7 +176,8 @@ public interface MarkerService {
* @param program The program with which the created markers will be associated. * @param program The program with which the created markers will be associated.
* @param priority to sort out what displays on top, higher is more likely to be on top * @param priority to sort out what displays on top, higher is more likely to be on top
* @param showMarkers true indicates to show area markers (on the left side of the browser.) * @param showMarkers true indicates to show area markers (on the left side of the browser.)
* @param showNavigation true indicates to show area navigation markers (on the right side of the browser.) * @param showNavigation true indicates to show area navigation markers (on the right side of
* the browser.)
* @param colorBackground if true, then the browser's background color will reflect the marker. * @param colorBackground if true, then the browser's background color will reflect the marker.
* @param color the color of marked areas in navigation bar * @param color the color of marked areas in navigation bar
* @param icon icon to display in marker bar * @param icon icon to display in marker bar
@ -200,9 +206,10 @@ public interface MarkerService {
public MarkerSet getMarkerSet(String name, Program program); public MarkerSet getMarkerSet(String name, Program program);
/** /**
* Sets a marker set for a given group name. Any previous marker set associated with the * Sets a marker set for a given group name. Any previous marker set associated with the given
* given group name will be removed from this marker service. This method is used to ensure * group name will be removed from this marker service. This method is used to ensure that only
* that only one marker set is used at any time for a give group. * one marker set is used at any time for a give group.
*
* @param groupName The name to associate the marker set with. * @param groupName The name to associate the marker set with.
* @param markerSet The marker set to add to this service * @param markerSet The marker set to add to this service
* @param program The program with which the markers are associated. * @param program The program with which the markers are associated.
@ -211,33 +218,22 @@ public interface MarkerService {
public void setMarkerForGroup(String groupName, MarkerSet markerSet, Program program); public void setMarkerForGroup(String groupName, MarkerSet markerSet, Program program);
/** /**
* Removes a marker set for a given group name. If the given marker set is not the marker * Removes a marker set for a given group name. If the given marker set is not the marker set
* set associated with the given group name, then no action will be taken. * associated with the given group name, then no action will be taken.
*
* @param groupName The name associated the marker set with. * @param groupName The name associated the marker set with.
* @param markerSet The marker set to add to this service * @param markerSet The marker set to add to this service
* @param program The program with which the markers are associated. May be null if the * @param program The program with which the markers are associated. May be null if the marker
* marker is * is
* @see #setMarkerForGroup(String, MarkerSet, Program) * @see #setMarkerForGroup(String, MarkerSet, Program)
*/ */
public void removeMarkerForGroup(String groupName, MarkerSet markerSet, Program program); public void removeMarkerForGroup(String groupName, MarkerSet markerSet, Program program);
/**
* Returns the background color associated with the given address. Each markerSet that supports
* background coloring is checked in priority order to see if it wants to specify a background
* color for the given address.
* @param address the address to check for a background color.
* @return the background color to use for that address or null if no markers contain that address.
*/
public Color getBackgroundColor(Address address);
/** /**
* Returns the background color associated with the given program and address. Each markerSet * Returns the background color associated with the given program and address. Each markerSet
* that supports background coloring is checked in priority order to see if it wants to specify * that supports background coloring is checked in priority order to see if it wants to specify
* a background color for the given address. * a background color for the given address.
* *
* If {@code program} is the current program, this is equivalent to
* {@link #getBackgroundColor(Address)}.
*
* @param program the program to check for a background color. * @param program the program to check for a background color.
* @param address the address to check for a background color. * @param address the address to check for a background color.
* @return the background color to use for that address or null if no markers contain that * @return the background color to use for that address or null if no markers contain that
@ -270,4 +266,21 @@ public interface MarkerService {
*/ */
public void setMarkerClickedListener(MarkerClickedListener listener); public void setMarkerClickedListener(MarkerClickedListener listener);
/**
* Create a new marker margin provider. The newly created provider is not added to the UI;
* clients must install the newly created provider themselves. Note that you must keep a strong
* reference to the provider, or it may not receive updates from the service.
*
* @return the new provider
*/
public MarkerMarginProvider createMarginProvider();
/**
* Create a new marker overview provider. The newly created provider is not added to the UI;
* clients must install the newly created provider themselves. Note that you must keep a strong
* reference to the provider, or it may not receive updates from the service.
*
* @return the new provider
*/
public MarkerOverviewProvider createOverviewProvider();
} }

View file

@ -154,6 +154,7 @@ public class ListingCodeComparisonPanel
/** /**
* Creates a comparison panel with two listings. * Creates a comparison panel with two listings.
*
* @param owner the owner of this panel * @param owner the owner of this panel
* @param tool the tool displaying this panel * @param tool the tool displaying this panel
*/ */
@ -208,9 +209,6 @@ public class ListingCodeComparisonPanel
Color diffCodeUnitsBackgroundColor = comparisonOptions.getDiffCodeUnitsBackgroundColor(); Color diffCodeUnitsBackgroundColor = comparisonOptions.getDiffCodeUnitsBackgroundColor();
diffMarkers[LEFT].setMarkerColor(diffCodeUnitsBackgroundColor); diffMarkers[LEFT].setMarkerColor(diffCodeUnitsBackgroundColor);
diffMarkers[RIGHT].setMarkerColor(diffCodeUnitsBackgroundColor); diffMarkers[RIGHT].setMarkerColor(diffCodeUnitsBackgroundColor);
// Force a refresh by setting the program. This updates the colors in the navigation popup.
markerManagers[LEFT].setProgram(getLeftProgram());
markerManagers[RIGHT].setProgram(getRightProgram());
} }
@Override @Override
@ -280,6 +278,7 @@ public class ListingCodeComparisonPanel
/** /**
* Sets the coordinator for the two listings within this code comparison panel. It coordinates * Sets the coordinator for the two listings within this code comparison panel. It coordinates
* their scrolling and location synchronization. * their scrolling and location synchronization.
*
* @param listingFieldPanelCoordinator the coordinator for the two listings * @param listingFieldPanelCoordinator the coordinator for the two listings
*/ */
@Override @Override
@ -303,6 +302,7 @@ public class ListingCodeComparisonPanel
/** /**
* Adds the indicated highlight providers for the left and right listing panels. * Adds the indicated highlight providers for the left and right listing panels.
*
* @param leftHighlightProvider the highlight provider for the left side's listing. * @param leftHighlightProvider the highlight provider for the left side's listing.
* @param rightHighlightProvider the highlight provider for the right side's listing. * @param rightHighlightProvider the highlight provider for the right side's listing.
*/ */
@ -322,6 +322,7 @@ public class ListingCodeComparisonPanel
/** /**
* Removes the indicated highlight providers from the left and right listing panels. * Removes the indicated highlight providers from the left and right listing panels.
*
* @param leftHighlightProvider the highlight provider for the left side's listing. * @param leftHighlightProvider the highlight provider for the left side's listing.
* @param rightHighlightProvider the highlight provider for the right side's listing. * @param rightHighlightProvider the highlight provider for the right side's listing.
*/ */
@ -425,6 +426,7 @@ public class ListingCodeComparisonPanel
/** /**
* Sets a listener for program location changes for the left side's listing panel. * Sets a listener for program location changes for the left side's listing panel.
*
* @param programLocationListener the listener * @param programLocationListener the listener
*/ */
public void setLeftProgramLocationListener(ProgramLocationListener programLocationListener) { public void setLeftProgramLocationListener(ProgramLocationListener programLocationListener) {
@ -433,6 +435,7 @@ public class ListingCodeComparisonPanel
/** /**
* Sets a listener for program location changes for the right side's listing panel. * Sets a listener for program location changes for the right side's listing panel.
*
* @param programLocationListener the listener * @param programLocationListener the listener
*/ */
public void setRightProgramLocationListener(ProgramLocationListener programLocationListener) { public void setRightProgramLocationListener(ProgramLocationListener programLocationListener) {
@ -830,10 +833,11 @@ public class ListingCodeComparisonPanel
} }
/** /**
* Sets whether or not the entire programs are displayed in the listings or only * Sets whether or not the entire programs are displayed in the listings or only the addresses
* the addresses in the limited set. * in the limited set.
* @param show if true, the entire program will be shown. Otherwise the listings will only *
* show the limited addresses. * @param show if true, the entire program will be shown. Otherwise the listings will only show
* the limited addresses.
*/ */
public void showEntireListing(boolean show) { public void showEntireListing(boolean show) {
try { try {
@ -863,6 +867,7 @@ public class ListingCodeComparisonPanel
/** /**
* Determines if the listing's layout field header is currently showing. * Determines if the listing's layout field header is currently showing.
*
* @return true if the header is showing. * @return true if the header is showing.
*/ */
public boolean isHeaderShowing() { public boolean isHeaderShowing() {
@ -871,6 +876,7 @@ public class ListingCodeComparisonPanel
/** /**
* Shows or hides the listing's layout field header. * Shows or hides the listing's layout field header.
*
* @param show true means show the field header. false means hide the header. * @param show true means show the field header. false means hide the header.
*/ */
public void setHeaderShowing(boolean show) { public void setHeaderShowing(boolean show) {
@ -889,6 +895,7 @@ public class ListingCodeComparisonPanel
/** /**
* Sets whether or not the listings are displayed side by side. * Sets whether or not the listings are displayed side by side.
*
* @param sideBySide if true, the listings are side by side, otherwise one is above the other. * @param sideBySide if true, the listings are side by side, otherwise one is above the other.
*/ */
public void showSideBySide(boolean sideBySide) { public void showSideBySide(boolean sideBySide) {
@ -932,6 +939,7 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the function loaded in the left listing panel. * Gets the function loaded in the left listing panel.
*
* @return the function or null * @return the function or null
*/ */
@Override @Override
@ -941,6 +949,7 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the function loaded in the right listing panel. * Gets the function loaded in the right listing panel.
*
* @return the function or null * @return the function or null
*/ */
@Override @Override
@ -989,8 +998,8 @@ public class ListingCodeComparisonPanel
} }
/** /**
* Establishes the location and display of the arrow cursor. This method should be called * Establishes the location and display of the arrow cursor. This method should be called after
* after the function comparison window is loaded with functions, data, etc. * the function comparison window is loaded with functions, data, etc.
*/ */
private void loadCursorArrow() { private void loadCursorArrow() {
int focusedSide = currProgramIndex; int focusedSide = currProgramIndex;
@ -1022,8 +1031,9 @@ public class ListingCodeComparisonPanel
/** /**
* Gets an equivalent left side program location when given a right side program location or * Gets an equivalent left side program location when given a right side program location or
* vice versa. The intent of this method is to translate a location from one side of the * vice versa. The intent of this method is to translate a location from one side of the dual
* dual listing to an equivalent location for the other side if possible. * listing to an equivalent location for the other side if possible.
*
* @param leftOrRight LEFT or RIGHT indicating which side's program location is needed. * @param leftOrRight LEFT or RIGHT indicating which side's program location is needed.
* @param programLocation the program location for the other side. * @param programLocation the program location for the other side.
* @return a program location for the desired side. Otherwise, null. * @return a program location for the desired side. Otherwise, null.
@ -1158,16 +1168,17 @@ public class ListingCodeComparisonPanel
} }
/** /**
* Infers a desired byte address based on the specified <code>byteAddress</code> as well * Infers a desired byte address based on the specified <code>byteAddress</code> as well as the
* as the <code>address</code> and <code>desiredAddress</code> that were matched. * <code>address</code> and <code>desiredAddress</code> that were matched.
*
* @param address matches up with the <code>desiredAddress</code> from the other function/data. * @param address matches up with the <code>desiredAddress</code> from the other function/data.
* @param desiredAddress matches up with the <code>address</code> from the other function/data. * @param desiredAddress matches up with the <code>address</code> from the other function/data.
* @param byteAddress the byte address that is associated with <code>address</code> * @param byteAddress the byte address that is associated with <code>address</code>
* @param program the program for the <code>address</code> and <code>byteAddress</code>. * @param program the program for the <code>address</code> and <code>byteAddress</code>.
* @param desiredProgram the program for the <code>desiredAddress</code> and * @param desiredProgram the program for the <code>desiredAddress</code> and
* <code>desiredByteAddress</code>. * <code>desiredByteAddress</code>.
* @return the desired byte address that matches up with the indicated <code>byteAddress</code> * @return the desired byte address that matches up with the indicated <code>byteAddress</code>
* or null if it can't be determined. * or null if it can't be determined.
*/ */
private Address inferDesiredByteAddress(Address address, Address desiredAddress, private Address inferDesiredByteAddress(Address address, Address desiredAddress,
Address byteAddress, Program program, Program desiredProgram) { Address byteAddress, Program program, Program desiredProgram) {
@ -1187,21 +1198,21 @@ public class ListingCodeComparisonPanel
} }
/** /**
* This infers the desired byte address within Data based on the code units at * This infers the desired byte address within Data based on the code units at
* <code>codeUnitAddress</code> and <code>desiredCodeUnitAddress</code>. * <code>codeUnitAddress</code> and <code>desiredCodeUnitAddress</code>. The inferred address
* The inferred address will be at an offset from the <code>desiredCodeUnitAddress</code> * will be at an offset from the <code>desiredCodeUnitAddress</code> that is the same distance
* that is the same distance the <code>byteAddress</code> is from the <code>codeUnitAddress</code>. * the <code>byteAddress</code> is from the <code>codeUnitAddress</code>.
* *
* @param codeUnitAddress matches up with the <code>desiredCodeUnitAddress</code> from * @param codeUnitAddress matches up with the <code>desiredCodeUnitAddress</code> from the other
* the other data. * data.
* @param desiredCodeUnitAddress matches up with the <code>codeUnitAddress</code> from * @param desiredCodeUnitAddress matches up with the <code>codeUnitAddress</code> from the other
* the other data. * data.
* @param byteAddress the byte address that is associated with <code>codeUnitAddress</code> * @param byteAddress the byte address that is associated with <code>codeUnitAddress</code>
* @param program the program for the <code>codeUnitAddress</code> and <code>byteAddress</code>. * @param program the program for the <code>codeUnitAddress</code> and <code>byteAddress</code>.
* @param desiredProgram the program for the <code>desiredCodeUnitAddress</code> and * @param desiredProgram the program for the <code>desiredCodeUnitAddress</code> and
* <code>desiredByteAddress</code>. * <code>desiredByteAddress</code>.
* @return the desired byte address within the data that matches up with the indicated * @return the desired byte address within the data that matches up with the indicated
* <code>byteAddress</code> or null if it can't be determined. * <code>byteAddress</code> or null if it can't be determined.
*/ */
private Address inferDesiredDataAddress(Address codeUnitAddress, Address desiredCodeUnitAddress, private Address inferDesiredDataAddress(Address codeUnitAddress, Address desiredCodeUnitAddress,
Address byteAddress, Program program, Program desiredProgram) { Address byteAddress, Program program, Program desiredProgram) {
@ -1227,19 +1238,19 @@ public class ListingCodeComparisonPanel
} }
/** /**
* This infers the desired byte address within a function based on the code units at * This infers the desired byte address within a function based on the code units at
* <code>address</code> and <code>desiredAddress</code>. * <code>address</code> and <code>desiredAddress</code>. If the inferred address would be beyond
* If the inferred address would be beyond the last byte of the code unit then it * the last byte of the code unit then it will get set to the last byte of the code unit at the
* will get set to the last byte of the code unit at the <code>desiredAddress</code>. * <code>desiredAddress</code>.
* *
* @param address matches up with the <code>desiredAddress</code> from the other function. * @param address matches up with the <code>desiredAddress</code> from the other function.
* @param desiredAddress matches up with the <code>address</code> from the other function. * @param desiredAddress matches up with the <code>address</code> from the other function.
* @param byteAddress the byte address that is associated with <code>address</code> * @param byteAddress the byte address that is associated with <code>address</code>
* @param program the program for the <code>address</code> and <code>byteAddress</code>. * @param program the program for the <code>address</code> and <code>byteAddress</code>.
* @param desiredProgram the program for the <code>desiredAddress</code> and * @param desiredProgram the program for the <code>desiredAddress</code> and
* <code>desiredByteAddress</code>. * <code>desiredByteAddress</code>.
* @return the desired byte address within the data that matches up with the indicated * @return the desired byte address within the data that matches up with the indicated
* <code>byteAddress</code> or null if it can't be determined. * <code>byteAddress</code> or null if it can't be determined.
*/ */
private Address inferDesiredFunctionAddress(Address address, Address desiredAddress, private Address inferDesiredFunctionAddress(Address address, Address desiredAddress,
Address byteAddress, Program program, Program desiredProgram) { Address byteAddress, Program program, Program desiredProgram) {
@ -1268,6 +1279,7 @@ public class ListingCodeComparisonPanel
* Gets an equivalent left side variable location when given a right side variable location or * Gets an equivalent left side variable location when given a right side variable location or
* vice versa. The intent of this method is to translate a variable location from one side of * vice versa. The intent of this method is to translate a variable location from one side of
* the dual listing to an equivalent variable location for the other side if possible. * the dual listing to an equivalent variable location for the other side if possible.
*
* @param leftOrRight LEFT or RIGHT indicating which side's variable location is needed. * @param leftOrRight LEFT or RIGHT indicating which side's variable location is needed.
* @param variableLocation the variable location for the other side. * @param variableLocation the variable location for the other side.
* @return a variable location for the desired side. Otherwise, null. * @return a variable location for the desired side. Otherwise, null.
@ -1549,7 +1561,6 @@ public class ListingCodeComparisonPanel
listingPanels[LEFT].getFieldPanel() listingPanels[LEFT].getFieldPanel()
.setBackgroundColorModel( .setBackgroundColorModel(
new MarkerServiceBackgroundColorModel(markerManagers[LEFT], indexMap)); new MarkerServiceBackgroundColorModel(markerManagers[LEFT], indexMap));
markerManagers[LEFT].setProgram(programs[LEFT]);
unmatchedCodeMarkers[LEFT] = unmatchedCodeMarkers[LEFT] =
markerManagers[LEFT].createAreaMarker("Listing1 Unmatched Code", markerManagers[LEFT].createAreaMarker("Listing1 Unmatched Code",
"Instructions that are not matched to an instruction in the other function.", "Instructions that are not matched to an instruction in the other function.",
@ -1565,7 +1576,6 @@ public class ListingCodeComparisonPanel
.setBackgroundColorModel( .setBackgroundColorModel(
new MarkerServiceBackgroundColorModel(markerManagers[RIGHT], new MarkerServiceBackgroundColorModel(markerManagers[RIGHT],
rightIndexMap)); rightIndexMap));
markerManagers[RIGHT].setProgram(programs[RIGHT]);
unmatchedCodeMarkers[RIGHT] = unmatchedCodeMarkers[RIGHT] =
markerManagers[RIGHT].createAreaMarker("Listing2 Unmatched Code", markerManagers[RIGHT].createAreaMarker("Listing2 Unmatched Code",
"Instructions that are not matched to an instruction in the other function.", "Instructions that are not matched to an instruction in the other function.",
@ -1663,7 +1673,7 @@ public class ListingCodeComparisonPanel
} }
indexMaps[LEFT] = new AddressIndexMap(addressSets[LEFT]); indexMaps[LEFT] = new AddressIndexMap(addressSets[LEFT]);
markerManagers[LEFT].getOverviewProvider().setAddressIndexMap(indexMaps[LEFT]); markerManagers[LEFT].getOverviewProvider().setProgram(getLeftProgram(), indexMaps[LEFT]);
listingPanels[LEFT].getFieldPanel() listingPanels[LEFT].getFieldPanel()
.setBackgroundColorModel( .setBackgroundColorModel(
new MarkerServiceBackgroundColorModel(markerManagers[LEFT], indexMaps[LEFT])); new MarkerServiceBackgroundColorModel(markerManagers[LEFT], indexMaps[LEFT]));
@ -1680,7 +1690,7 @@ public class ListingCodeComparisonPanel
} }
indexMaps[RIGHT] = new AddressIndexMap(addressSets[RIGHT]); indexMaps[RIGHT] = new AddressIndexMap(addressSets[RIGHT]);
markerManagers[RIGHT].getOverviewProvider().setAddressIndexMap(indexMaps[RIGHT]); markerManagers[RIGHT].getOverviewProvider().setProgram(getRightProgram(), indexMaps[RIGHT]);
listingPanels[RIGHT].getFieldPanel() listingPanels[RIGHT].getFieldPanel()
.setBackgroundColorModel( .setBackgroundColorModel(
new MarkerServiceBackgroundColorModel(markerManagers[RIGHT], indexMaps[RIGHT])); new MarkerServiceBackgroundColorModel(markerManagers[RIGHT], indexMaps[RIGHT]));
@ -1723,6 +1733,7 @@ public class ListingCodeComparisonPanel
/** /**
* Sets the cursor location in the left and right listing at the specified functions. * Sets the cursor location in the left and right listing at the specified functions.
*
* @param leftFunction the function in the left listing panel. * @param leftFunction the function in the left listing panel.
* @param rightFunction the function in the right listing panel. * @param rightFunction the function in the right listing panel.
*/ */
@ -1733,6 +1744,7 @@ public class ListingCodeComparisonPanel
/** /**
* Sets the cursor in the left side's listing to the specified location. * Sets the cursor in the left side's listing to the specified location.
*
* @param program the left side's program * @param program the left side's program
* @param location the location * @param location the location
*/ */
@ -1744,6 +1756,7 @@ public class ListingCodeComparisonPanel
/** /**
* Sets the cursor in the right side's listing to the specified location. * Sets the cursor in the right side's listing to the specified location.
*
* @param program the right side's program * @param program the right side's program
* @param location the location * @param location the location
*/ */
@ -1863,6 +1876,7 @@ public class ListingCodeComparisonPanel
/** /**
* Sets the title for the left side's listing. * Sets the title for the left side's listing.
*
* @param leftTitle the title * @param leftTitle the title
*/ */
public void setLeftTitle(String leftTitle) { public void setLeftTitle(String leftTitle) {
@ -1872,6 +1886,7 @@ public class ListingCodeComparisonPanel
/** /**
* Sets the title for the right side's listing. * Sets the title for the right side's listing.
*
* @param rightTitle the title * @param rightTitle the title
*/ */
public void setRightTitle(String rightTitle) { public void setRightTitle(String rightTitle) {
@ -1881,6 +1896,7 @@ public class ListingCodeComparisonPanel
/** /**
* Sets the component displayed in the top of this panel. * Sets the component displayed in the top of this panel.
*
* @param comp the component. * @param comp the component.
*/ */
public void setTopComponent(JComponent comp) { public void setTopComponent(JComponent comp) {
@ -1899,6 +1915,7 @@ public class ListingCodeComparisonPanel
/** /**
* Sets the component displayed in the bottom of this panel. * Sets the component displayed in the bottom of this panel.
*
* @param comp the component. * @param comp the component.
*/ */
public void setBottomComponent(JComponent comp) { public void setBottomComponent(JComponent comp) {
@ -1918,6 +1935,7 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the program from the left or right side that has or last had focus. * Gets the program from the left or right side that has or last had focus.
*
* @return the program from the side of this panel with focus or null * @return the program from the side of this panel with focus or null
*/ */
public Program getFocusedProgram() { public Program getFocusedProgram() {
@ -1926,6 +1944,7 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the program in the left listing panel. * Gets the program in the left listing panel.
*
* @return the left program or null * @return the left program or null
*/ */
@Override @Override
@ -1935,6 +1954,7 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the program in the right listing panel. * Gets the program in the right listing panel.
*
* @return the right program or null * @return the right program or null
*/ */
@Override @Override
@ -1944,6 +1964,7 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the addresses in the left listing panel. * Gets the addresses in the left listing panel.
*
* @return the addresses * @return the addresses
*/ */
@Override @Override
@ -1953,6 +1974,7 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the addresses in the right listing panel. * Gets the addresses in the right listing panel.
*
* @return the addresses * @return the addresses
*/ */
@Override @Override
@ -1962,6 +1984,7 @@ public class ListingCodeComparisonPanel
/** /**
* Get the left or right listing panel that has or last had focus. * Get the left or right listing panel that has or last had focus.
*
* @return the listing panel with focus. * @return the listing panel with focus.
*/ */
public ListingPanel getFocusedListingPanel() { public ListingPanel getFocusedListingPanel() {
@ -1970,6 +1993,7 @@ public class ListingCodeComparisonPanel
/** /**
* Get the left side's listing panel. * Get the left side's listing panel.
*
* @return the left panel * @return the left panel
*/ */
public ListingPanel getLeftPanel() { public ListingPanel getLeftPanel() {
@ -1978,6 +2002,7 @@ public class ListingCodeComparisonPanel
/** /**
* Get the right side's listing panel. * Get the right side's listing panel.
*
* @return the right panel * @return the right panel
*/ */
public ListingPanel getRightPanel() { public ListingPanel getRightPanel() {
@ -1986,6 +2011,7 @@ public class ListingCodeComparisonPanel
/** /**
* Go to the indicated address in the listing that last had focus. * Go to the indicated address in the listing that last had focus.
*
* @param addr the cursor should go to this address * @param addr the cursor should go to this address
* @return true if the location changed * @return true if the location changed
*/ */
@ -1995,9 +2021,10 @@ public class ListingCodeComparisonPanel
/** /**
* Go to the indicated location in the listing that last had focus. * Go to the indicated location in the listing that last had focus.
*
* @param loc the cursor should go to this location. * @param loc the cursor should go to this location.
* @param centerOnScreen true indicates that the location should be centered in the listing's * @param centerOnScreen true indicates that the location should be centered in the listing's
* viewport. * viewport.
* @return true if the location changed * @return true if the location changed
*/ */
public boolean goTo(ProgramLocation loc, boolean centerOnScreen) { public boolean goTo(ProgramLocation loc, boolean centerOnScreen) {
@ -2104,7 +2131,9 @@ public class ListingCodeComparisonPanel
} }
/** /**
* Adds the indicated button press listener to both listing panels in this code comparison panel. * Adds the indicated button press listener to both listing panels in this code comparison
* panel.
*
* @param listener the listener * @param listener the listener
*/ */
public void addButtonPressedListener(ButtonPressedListener listener) { public void addButtonPressedListener(ButtonPressedListener listener) {
@ -2127,11 +2156,13 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the indicated (LEFT or RIGHT) side's address that is equivalent to the other side's * Gets the indicated (LEFT or RIGHT) side's address that is equivalent to the other side's
* address. * address.
*
* @param leftOrRight LEFT or RIGHT indicating which side's address is needed. * @param leftOrRight LEFT or RIGHT indicating which side's address is needed.
* @param otherSidesAddress the address for the other side. If leftOrRight = LEFT, then this * @param otherSidesAddress the address for the other side. If leftOrRight = LEFT, then this
* should be a right side address. If leftOrRight = RIGHT, then this should be a left side address. * should be a right side address. If leftOrRight = RIGHT, then this should be a left
* side address.
* @return an address for the indicated side (LEFT or RIGHT) that is equivalent to the other * @return an address for the indicated side (LEFT or RIGHT) that is equivalent to the other
* side's address that is specified. Otherwise, null. * side's address that is specified. Otherwise, null.
*/ */
private Address getAddress(int leftOrRight, Address otherSidesAddress) { private Address getAddress(int leftOrRight, Address otherSidesAddress) {
if (isFunctionCompare()) { if (isFunctionCompare()) {
@ -2144,11 +2175,12 @@ public class ListingCodeComparisonPanel
} }
/** /**
* Gets an address in the program indicated by <code>leftOrRight</code> that matches the * Gets an address in the program indicated by <code>leftOrRight</code> that matches the
* <code>otherSidesAddress</code> that is an address in a function in the other program. * <code>otherSidesAddress</code> that is an address in a function in the other program.
*
* @param leftOrRight indicates whether to get the address from the LEFT or RIGHT program. * @param leftOrRight indicates whether to get the address from the LEFT or RIGHT program.
* @param otherSidesAddress address in the other program that is equivalent to the * @param otherSidesAddress address in the other program that is equivalent to the desired
* desired address. * address.
* @return the matching address in the indicated program or null. * @return the matching address in the indicated program or null.
*/ */
private Address getFunctionAddress(int leftOrRight, Address otherSidesAddress) { private Address getFunctionAddress(int leftOrRight, Address otherSidesAddress) {
@ -2196,6 +2228,7 @@ public class ListingCodeComparisonPanel
/** /**
* Is this panel currently comparing a function match? * Is this panel currently comparing a function match?
*
* @return true if comparing functions. * @return true if comparing functions.
*/ */
private boolean isFunctionCompare() { private boolean isFunctionCompare() {
@ -2206,6 +2239,7 @@ public class ListingCodeComparisonPanel
/** /**
* Is this panel currently comparing a data match? * Is this panel currently comparing a data match?
*
* @return true if comparing data. * @return true if comparing data.
*/ */
private boolean isDataCompare() { private boolean isDataCompare() {
@ -2216,6 +2250,7 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the left side address that is equivalent to the indicated right side address. * Gets the left side address that is equivalent to the indicated right side address.
*
* @param rightByteAddress the right side address * @param rightByteAddress the right side address
* @return the left side address or null. * @return the left side address or null.
*/ */
@ -2228,6 +2263,7 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the right side address that is equivalent to the indicated left side address. * Gets the right side address that is equivalent to the indicated left side address.
*
* @param leftByteAddress the left side address * @param leftByteAddress the left side address
* @return the right side address or null. * @return the right side address or null.
*/ */
@ -2240,6 +2276,7 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the left side function's entry point address. * Gets the left side function's entry point address.
*
* @return the left side function's entry point address or null. * @return the left side function's entry point address or null.
*/ */
private Address getLeftFunctionAddress() { private Address getLeftFunctionAddress() {
@ -2251,6 +2288,7 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the right side function's entry point address. * Gets the right side function's entry point address.
*
* @return the right side function's entry point address or null. * @return the right side function's entry point address or null.
*/ */
private Address getRightFunctionAddress() { private Address getRightFunctionAddress() {
@ -2262,6 +2300,7 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the left side data's minimum address. * Gets the left side data's minimum address.
*
* @return the left side data's minimum address or null. * @return the left side data's minimum address or null.
*/ */
private Address getLeftDataAddress() { private Address getLeftDataAddress() {
@ -2273,6 +2312,7 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the right side data's minimum address. * Gets the right side data's minimum address.
*
* @return the right side data's minimum address or null. * @return the right side data's minimum address or null.
*/ */
private Address getRightDataAddress() { private Address getRightDataAddress() {
@ -2381,6 +2421,7 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the left or right listing panel that contains the indicated field panel. * Gets the left or right listing panel that contains the indicated field panel.
*
* @param fieldPanel the field panel * @param fieldPanel the field panel
* @return the listing panel or null. * @return the listing panel or null.
*/ */
@ -2401,6 +2442,7 @@ public class ListingCodeComparisonPanel
/** /**
* Disable mouse navigation from within this dual listing panel. * Disable mouse navigation from within this dual listing panel.
*
* @param enabled false disables navigation * @param enabled false disables navigation
*/ */
@Override @Override
@ -2448,6 +2490,7 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the maximum offset based on the larger data that is passed to this method. * Gets the maximum offset based on the larger data that is passed to this method.
*
* @param leftData the left view's data * @param leftData the left view's data
* @param rightData the right view's data * @param rightData the right view's data
* @return the maximum offset (one less than the larger data item's size). * @return the maximum offset (one less than the larger data item's size).
@ -2466,10 +2509,11 @@ public class ListingCodeComparisonPanel
} }
/** /**
* Gets the ending address to be displayed. It tries to get an ending address that is * Gets the ending address to be displayed. It tries to get an ending address that is maxOffset
* maxOffset number of bytes beyond the minAddress without leaving the memory block * number of bytes beyond the minAddress without leaving the memory block that contains the
* that contains the minAddress. If the maxOffset is beyond the end of the block then * minAddress. If the maxOffset is beyond the end of the block then the end of the block is
* the end of the block is returned. For an externalAddress the minAddress is returned. * returned. For an externalAddress the minAddress is returned.
*
* @param program the program containing the data * @param program the program containing the data
* @param maxOffset the max offset * @param maxOffset the max offset
* @param minAddress the minimum address of the data * @param minAddress the minimum address of the data
@ -2495,8 +2539,8 @@ public class ListingCodeComparisonPanel
} }
/** /**
* Clears the address correlation being used with the ListingDiff and the dual listing * Clears the address correlation being used with the ListingDiff and the dual listing field
* field panel coordinator. * panel coordinator.
*/ */
private void clearCorrelation() { private void clearCorrelation() {
correlator = null; correlator = null;
@ -2516,6 +2560,7 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the data loaded in the left listing panel. * Gets the data loaded in the left listing panel.
*
* @return the data or null * @return the data or null
*/ */
@Override @Override
@ -2525,6 +2570,7 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the data loaded in the right listing panel. * Gets the data loaded in the right listing panel.
*
* @return the data or null * @return the data or null
*/ */
@Override @Override
@ -2560,6 +2606,7 @@ public class ListingCodeComparisonPanel
/** /**
* Displays the indicated text int the tool's status area. * Displays the indicated text int the tool's status area.
*
* @param text the message to display * @param text the message to display
*/ */
void setStatusInfo(String text) { void setStatusInfo(String text) {
@ -2621,8 +2668,9 @@ public class ListingCodeComparisonPanel
/** /**
* Gets the GoToService that is used for either the left listing or the right listing. * Gets the GoToService that is used for either the left listing or the right listing.
* @param isLeftSide true means get the GoToService for the left side listing. *
* false means get it for the right side listing. * @param isLeftSide true means get the GoToService for the left side listing. false means get
* it for the right side listing.
* @return the goToService * @return the goToService
*/ */
GoToService getGoToService(boolean isLeftSide) { GoToService getGoToService(boolean isLeftSide) {
@ -2661,9 +2709,10 @@ public class ListingCodeComparisonPanel
} }
/** /**
* Gets a marker margin or overview margin context object if the mouse event occurred on one * Gets a marker margin or overview margin context object if the mouse event occurred on one of
* of the GUI components for the indicated listing panel's marker margin (left edge of listing) * the GUI components for the indicated listing panel's marker margin (left edge of listing) or
* or overview margin (right edge of listing). * overview margin (right edge of listing).
*
* @param lp The listing panel to check * @param lp The listing panel to check
* @param event the mouse event * @param event the mouse event
* @return a marker margin context object if the event was on a margin. * @return a marker margin context object if the event was on a margin.
@ -2733,6 +2782,7 @@ public class ListingCodeComparisonPanel
/** /**
* Restores this panel to the indicated saved configuration state. * Restores this panel to the indicated saved configuration state.
*
* @param prefix identifier to prepend to any save state names to make them unique. * @param prefix identifier to prepend to any save state names to make them unique.
* @param saveState the configuration state to restore * @param saveState the configuration state to restore
*/ */
@ -2743,6 +2793,7 @@ public class ListingCodeComparisonPanel
/** /**
* Saves the current configuration state of this panel. * Saves the current configuration state of this panel.
*
* @param prefix identifier to prepend to any save state names to make them unique. * @param prefix identifier to prepend to any save state names to make them unique.
* @param saveState the new configuration state * @param saveState the new configuration state
*/ */

View file

@ -260,7 +260,7 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
private void updateProviders() { private void updateProviders() {
AddressIndexMap addressIndexMap = layoutModel.getAddressIndexMap(); AddressIndexMap addressIndexMap = layoutModel.getAddressIndexMap();
for (OverviewProvider element : overviewProviders) { for (OverviewProvider element : overviewProviders) {
element.setAddressIndexMap(addressIndexMap); element.setProgram(getProgram(), addressIndexMap);
} }
for (ChangeListener indexMapChangeListener : indexMapChangeListeners) { for (ChangeListener indexMapChangeListener : indexMapChangeListeners) {
indexMapChangeListener.stateChanged(null); indexMapChangeListener.stateChanged(null);
@ -294,7 +294,7 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
else { else {
marginProviders.add(provider); marginProviders.add(provider);
} }
provider.setPixelMap(pixmap); provider.setProgram(getProgram(), layoutModel.getAddressIndexMap(), pixmap);
buildPanels(); buildPanels();
} }
@ -408,7 +408,7 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
*/ */
public void addOverviewProvider(OverviewProvider provider) { public void addOverviewProvider(OverviewProvider provider) {
overviewProviders.add(provider); overviewProviders.add(provider);
provider.setAddressIndexMap(layoutModel.getAddressIndexMap()); provider.setProgram(getProgram(), layoutModel.getAddressIndexMap());
buildPanels(); buildPanels();
} }
@ -474,9 +474,10 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
@Override @Override
public void layoutsChanged(List<AnchoredLayout> layouts) { public void layoutsChanged(List<AnchoredLayout> layouts) {
this.pixmap = new VerticalPixelAddressMapImpl(layouts, layoutModel.getAddressIndexMap()); AddressIndexMap addrMap = layoutModel.getAddressIndexMap();
this.pixmap = new VerticalPixelAddressMapImpl(layouts, addrMap);
for (MarginProvider element : marginProviders) { for (MarginProvider element : marginProviders) {
element.setPixelMap(pixmap); element.setProgram(getProgram(), addrMap, pixmap);
} }
for (AddressSetDisplayListener listener : displayListeners) { for (AddressSetDisplayListener listener : displayListeners) {
@ -1061,7 +1062,7 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
} }
Layout layout2 = layoutModel.getLayout(loc2.getIndex()); Layout layout2 = layoutModel.getLayout(loc2.getIndex());
if (fieldNum1 >= 0 && layout2 != null) { if (fieldNum1 >= 0 && layout2 != null) {
BigInteger index2 = loc2.getIndex(); BigInteger index2 = loc2.getIndex();
int fieldNum2 = layout.getEndRowFieldNum(loc2.getFieldNum()); int fieldNum2 = layout.getEndRowFieldNum(loc2.getFieldNum());
@ -1122,8 +1123,9 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
} }
/** /**
* Returns the currently selected text. The value will only be non-null for selections within * Returns the currently selected text. The value will only be non-null for selections within a
* a single field. * single field.
*
* @return the selected text or null * @return the selected text or null
*/ */
public String getTextSelection() { public String getTextSelection() {

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,12 +15,14 @@
*/ */
package ghidra.app.util.viewer.listingpanel; package ghidra.app.util.viewer.listingpanel;
import ghidra.program.util.MarkerLocation;
import javax.swing.JComponent; 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 listings left margin. * Interface for objects that want to add a component to the listing's left margin.
*/ */
public interface MarginProvider { public interface MarginProvider {
@ -36,13 +37,18 @@ public interface MarginProvider {
boolean isResizeable(); boolean isResizeable();
/** /**
* Set the vertical pixel layout map. * Set the program and associated maps.
* @param pixmap the vertical pixel map to use. *
* @param program the program to use.
* @param addressIndexMap the address-index map to use.
* @param pixelMap the vertical pixel map to use.
*/ */
void setPixelMap(VerticalPixelAddressMap pixmap); void setProgram(Program program, AddressIndexMap addressIndexMap,
VerticalPixelAddressMap pixelMap);
/** /**
* Get the marker location for the given x, y point. * Get the marker location for the given x, y point.
*
* @param x the horizontal coordinate. * @param x the horizontal coordinate.
* @param y the vertical coordinate. * @param y the vertical coordinate.
*/ */

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,25 +15,34 @@
*/ */
package ghidra.app.util.viewer.listingpanel; package ghidra.app.util.viewer.listingpanel;
import ghidra.app.util.viewer.util.AddressIndexMap;
import javax.swing.JComponent; import javax.swing.JComponent;
import ghidra.app.nav.Navigatable;
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 * Interface implemented by classes that provide overview components to the right side of the
* of the listing. * listing.
*/ */
public interface OverviewProvider { public interface OverviewProvider {
/** /**
* Returns the component to diplay in the right margin of the listing. * Returns the component to diplay in the right margin of the listing.
*/ */
JComponent getComponent(); JComponent getComponent();
/**
* Sets the AddressIndexMap whenever it changes so that the overview provider has
* an current map.
* @param map the current AddressIndexMap of the ListingPanel
*/
void setAddressIndexMap(AddressIndexMap map);
/**
* Sets the current program and associated address-index map
*
* @param program the program to use.
* @param addressIndexMap the address-index map to use.
*/
void setProgram(Program program, AddressIndexMap map);
/**
* Set the component provider that this overview navigates
*
* @param navigatable the navigatable provider
*/
void setNavigatable(Navigatable navigatable);
} }

View file

@ -65,12 +65,11 @@ import ghidra.util.task.*;
import resources.ResourceManager; import resources.ResourceManager;
/** /**
* Plugin that shows the differences between two programs, and allows the * Plugin that shows the differences between two programs, and allows the user to apply differences
* user to apply differences to the currently open program. This allows only one * to the currently open program. This allows only one tabbed program to display a second program
* tabbed program to display a second program (possibly with an active Diff). * (possibly with an active Diff). It allows the active program to change without losing the current
* It allows the active program to change without losing the current Diff or * Diff or second program that is opened. De-activation of the first program for the Diff will
* second program that is opened. De-activation of the first program for the Diff * result in termination of the Diff or the Diff can be closed directly by the user.
* will result in termination of the Diff or the Diff can be closed directly by the user.
*/ */
//@formatter:off //@formatter:off
@PluginInfo( @PluginInfo(
@ -151,6 +150,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
/** /**
* Creates the plugin for indicating program differences to the user. * Creates the plugin for indicating program differences to the user.
*
* @param tool the tool that owns this plugin. * @param tool the tool that owns this plugin.
*/ */
public ProgramDiffPlugin(PluginTool tool) { public ProgramDiffPlugin(PluginTool tool) {
@ -282,7 +282,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
AddressSet p1AddressSetAsP2 = AddressSet p1AddressSetAsP2 =
DiffUtility.getCompatibleAddressSet(p1AddressSet, secondaryDiffProgram); DiffUtility.getCompatibleAddressSet(p1AddressSet, secondaryDiffProgram);
AddressIndexMap p2IndexMap = new AddressIndexMap(p1AddressSetAsP2); AddressIndexMap p2IndexMap = new AddressIndexMap(p1AddressSetAsP2);
markerManager.getOverviewProvider().setAddressIndexMap(p2IndexMap); markerManager.getOverviewProvider().setProgram(secondaryDiffProgram, p2IndexMap);
fp.setBackgroundColorModel( fp.setBackgroundColorModel(
new MarkerServiceBackgroundColorModel(markerManager, p2IndexMap)); new MarkerServiceBackgroundColorModel(markerManager, p2IndexMap));
@ -479,8 +479,9 @@ public class ProgramDiffPlugin extends ProgramPlugin
} }
/** /**
* Called when a program gets closed. * Called when a program gets closed. If the closed program is the first program of the Diff
* If the closed program is the first program of the Diff then we need to close the second program. * then we need to close the second program.
*
* @param program * @param program
*/ */
@Override @Override
@ -719,8 +720,8 @@ public class ProgramDiffPlugin extends ProgramPlugin
/** /**
* Callback when user changes selection in the program2 diff panel. * Callback when user changes selection in the program2 diff panel.
* *
* Note: A P2 selection is handed to this method when a selection is made in the diff * Note: A P2 selection is handed to this method when a selection is made in the diff listing
* listing which displays P2. * which displays P2.
*/ */
@Override @Override
public void programSelectionChanged(ProgramSelection newP2Selection) { public void programSelectionChanged(ProgramSelection newP2Selection) {
@ -838,8 +839,9 @@ public class ProgramDiffPlugin extends ProgramPlugin
} }
/** /**
* Set the highlight based on the current program differences, but * Set the highlight based on the current program differences, but do not set the highlight for
* do not set the highlight for set of addresses to be ignored. * set of addresses to be ignored.
*
* @param ignoreAddressSet the set of addresses to ignore. * @param ignoreAddressSet the set of addresses to ignore.
*/ */
private void setDiffHighlight() { private void setDiffHighlight() {
@ -849,7 +851,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
AddressSetView p1DiffSet = null; AddressSetView p1DiffSet = null;
try { try {
p1DiffSet = diffControl.getFilteredDifferences(TaskMonitorAdapter.DUMMY_MONITOR); p1DiffSet = diffControl.getFilteredDifferences(TaskMonitor.DUMMY);
} }
catch (CancelledException e) { catch (CancelledException e) {
// Shouldn't get this, since using a DUMMY_MONITOR. // Shouldn't get this, since using a DUMMY_MONITOR.
@ -940,16 +942,17 @@ public class ProgramDiffPlugin extends ProgramPlugin
} }
/** /**
* Computes the differences between program1 and program2 that are displayed * Computes the differences between program1 and program2 that are displayed in the browser
* in the browser using the current Limiting set. It allows the user to specify the Diff settings to use. * using the current Limiting set. It allows the user to specify the Diff settings to use.
*/ */
void diff() { void diff() {
diff(createLimitingSet()); diff(createLimitingSet());
} }
/** /**
* Computes the differences between program1 and program2 that are displayed * Computes the differences between program1 and program2 that are displayed in the browser. It
* in the browser. It allows the user to specify the Diff settings to use. * allows the user to specify the Diff settings to use.
*
* @param p1LimitSet an address set to use to limit the extent of the Diff. * @param p1LimitSet an address set to use to limit the extent of the Diff.
*/ */
void diff(AddressSetView p1LimitSet) { void diff(AddressSetView p1LimitSet) {
@ -1055,7 +1058,6 @@ public class ProgramDiffPlugin extends ProgramPlugin
setProgram2Selection(p2Selection); setProgram2Selection(p2Selection);
clearDiff(); clearDiff();
if (secondaryDiffProgram != null) { if (secondaryDiffProgram != null) {
markerManager.setProgram(null);
Iterator<BookmarkNavigator> iter = bookmarkMap.values().iterator(); Iterator<BookmarkNavigator> iter = bookmarkMap.values().iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
BookmarkNavigator nav = iter.next(); BookmarkNavigator nav = iter.next();
@ -1171,10 +1173,11 @@ public class ProgramDiffPlugin extends ProgramPlugin
} }
/** /**
* Get the first program for the current Diff. * Get the first program for the current Diff. <br>
* <br><b>Note</b>: This may not be the currently active program. * <b>Note</b>: This may not be the currently active program.
* @return the Diff's first program or null if don't currently have a *
* second program associated for a Diff. * @return the Diff's first program or null if don't currently have a second program associated
* for a Diff.
*/ */
Program getFirstProgram() { Program getFirstProgram() {
return primaryProgram; return primaryProgram;
@ -1182,8 +1185,9 @@ public class ProgramDiffPlugin extends ProgramPlugin
/** /**
* Get the second program for the current Diff. * Get the second program for the current Diff.
* @return the Diff's second program or null if don't currently have a *
* second program associated for a Diff. * @return the Diff's second program or null if don't currently have a second program associated
* for a Diff.
*/ */
Program getSecondProgram() { Program getSecondProgram() {
return secondaryDiffProgram; return secondaryDiffProgram;
@ -1238,10 +1242,11 @@ public class ProgramDiffPlugin extends ProgramPlugin
* Gets the address set where detailed differences will be determined for details at the * Gets the address set where detailed differences will be determined for details at the
* indicated address. An address set is returned since the indicated address may be in different * indicated address. An address set is returned since the indicated address may be in different
* sized code units in each of the two programs. * sized code units in each of the two programs.
*
* @param p1Address the current address from program1 where details are desired. * @param p1Address the current address from program1 where details are desired.
* @return the address set for code units containing that address within the programs being * @return the address set for code units containing that address within the programs being
* compared to determine differences. * compared to determine differences. Otherwise null if a diff of two programs isn't
* Otherwise null if a diff of two programs isn't being performed. * being performed.
*/ */
AddressSetView getDetailsAddressSet(Address p1Address) { AddressSetView getDetailsAddressSet(Address p1Address) {
if (diffDetails != null) { if (diffDetails != null) {
@ -1598,7 +1603,6 @@ public class ProgramDiffPlugin extends ProgramPlugin
finally { finally {
settingLocation = false; settingLocation = false;
} }
markerManager.setProgram(secondaryDiffProgram);
setupBookmarkNavigators(); setupBookmarkNavigators();
sameProgramContext = ProgramMemoryComparator.sameProgramContextRegisterNames(primaryProgram, sameProgramContext = ProgramMemoryComparator.sameProgramContextRegisterNames(primaryProgram,