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 {
@Override
public void markerDoubleClicked(MarkerLocation location) {
doToggleBreakpointsAt(ToggleBreakpointAction.NAME,
ProgramLocationActionContext context =
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) {
return Set.of();
}
ProgramLocation loc = getLocationFromContext(context); // must be static location
if (loc == null) {
ProgramLocation loc = getLocationFromContext(context);
if (loc == null || loc.getProgram() instanceof TraceProgramView) {
return Set.of();
}
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.utils.ProgramLocationUtils;
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.DebuggerListingService.LocationTrackingSpecChangeListener;
import ghidra.app.util.viewer.format.FormatManager;
@ -266,6 +268,8 @@ public class DebuggerListingProvider extends CodeViewerProvider {
protected final MultiBlendedListingBackgroundColorModel colorModel;
protected final MarkerSetChangeListener markerChangeListener = new MarkerSetChangeListener();
protected MarkerServiceBackgroundColorModel markerServiceColorModel;
protected MarkerMarginProvider markerMarginProvider;
protected MarkerOverviewProvider markerOverviewProvider;
private SuppressableCallback<ProgramLocation> cbGoTo = new SuppressableCallback<>();
@ -500,6 +504,10 @@ public class DebuggerListingProvider extends CodeViewerProvider {
private void setMarkerService(MarkerService markerService) {
if (this.markerService != null) {
this.markerService.removeChangeListener(markerChangeListener);
removeMarginProvider(markerMarginProvider);
markerMarginProvider = null;
removeOverviewProvider(markerOverviewProvider);
markerOverviewProvider = null;
}
removeOldStaticTrackingMarker();
this.markerService = markerService;
@ -510,6 +518,12 @@ public class DebuggerListingProvider extends CodeViewerProvider {
// NOTE: Connected provider marker listener is taken care of by CodeBrowserPlugin
this.markerService.addChangeListener(markerChangeListener);
}
if (this.markerService != null) {
markerMarginProvider = markerService.createMarginProvider();
addMarginProvider(markerMarginProvider);
markerOverviewProvider = markerService.createOverviewProvider();
addOverviewProvider(markerOverviewProvider);
}
}
@AutoServiceConsumed

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,15 +15,15 @@
*/
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.KeyEvent;
import docking.ActionContext;
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.
@ -34,8 +33,8 @@ class AddBookmarkAction extends DockingAction {
BookmarkPlugin plugin;
/**
* Creates a new action with the given name and associated to the given
* plugin.
* Creates a new action with the given name and associated to the given plugin.
*
* @param name the name for this action.
* @param plugin the plugin this action is associated with.
*/
@ -51,11 +50,12 @@ class AddBookmarkAction extends DockingAction {
/**
* Method called when the action is invoked.
*
* @param ActionEvent details regarding the invocation of this action
*/
@Override
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) {
return false;
}
return getAddress(context) != null;
return getAddress(context) != null && getProgram(context) == plugin.getCurrentProgram();
}
private Address getAddress(ActionContext context) {
@ -80,4 +80,15 @@ class AddBookmarkAction extends DockingAction {
}
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
* before the plugin is destroyed.
* Get rid of any resources this plugin is using before the plugin is destroyed.
*/
@Override
public synchronized void dispose() {
@ -276,6 +275,7 @@ public class BookmarkPlugin extends ProgramPlugin
/**
* Get or create a bookmark navigator for the specified bookmark type
*
* @param type the bookmark type
* @return bookmark navigator
*/
@ -432,9 +432,12 @@ public class BookmarkPlugin extends ProgramPlugin
bookmarkMgr = program.getBookmarkManager();
}
void showAddBookmarkDialog(Address location) {
void showAddBookmarkDialog(Address address, Program program) {
if (program != currentProgram) {
return;
}
Listing listing = currentProgram.getListing();
CodeUnit currCU = listing.getCodeUnitContaining(location);
CodeUnit currCU = listing.getCodeUnitContaining(address);
if (currCU == null) {
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
*
* @param addr bookmark address. If null a Note bookmark will set at the
* start address of each range in the current selection
* @param addr bookmark address. If null a Note bookmark will set at the start address of each
* range in the current selection
* @param category bookmark category
* @param comment comment text
*/
@ -494,6 +497,9 @@ public class BookmarkPlugin extends ProgramPlugin
return null;
}
MarkerLocation loc = (MarkerLocation) contextObject;
if (loc.getProgram() != currentProgram) {
return null;
}
BookmarkManager mgr = currentProgram.getBookmarkManager();
Address address = loc.getAddr();
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
* given 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.
* @return a list of actions to delete bookmarks that are in the code unit surrounding the
* given address.
* Returns a list of actions to delete bookmarks that are in the code unit surrounding the given
* 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.
* @return a list of actions to delete bookmarks that are in the code unit surrounding the given
* address.
*/
private List<DockingActionIf> getActionsForCodeUnit(Address primaryAddress,
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
* given address <b>for the given <i>type</i> of bookmark</b>.
* Returns a list of actions to delete bookmarks that are in the code unit surrounding the given
* address <b>for the given <i>type</i> of bookmark</b>.
*
* @param primaryAddress The address required to find the containing code unit.
* @param type The bookmark type to retrieve.
* @param navigator The BookmarkNavigator used to determine whether there are bookmarks
* inside 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
* given address <b>for the given <i>type</i> of bookmark</b>.
* @param navigator The BookmarkNavigator used to determine whether there are bookmarks inside
* 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 given
* address <b>for the given <i>type</i> of bookmark</b>.
*/
private List<DockingActionIf> getActionsForCodeUnitAndType(Address primaryAddress, String type,
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
* <tt>actionList</tt> is less than the given {@link #MAX_DELETE_ACTIONS}.
*
* @param actionList The list to add to
* @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,
List<DockingActionIf> newActionList, int maxActionCount) {

View File

@ -16,8 +16,6 @@
package ghidra.app.plugin.core.codebrowser;
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
@ -84,7 +82,6 @@ public abstract class AbstractCodeBrowserPlugin<P extends CodeViewerProvider> ex
private MarkerSet currentHighlightMarkers;
private MarkerSet currentCursorMarkers;
private ChangeListener markerChangeListener;
private FocusingMouseListener focusingMouseListener = new FocusingMouseListener();
private Color cursorHighlightColor;
private boolean isHighlightCursorLine;
@ -269,36 +266,22 @@ public abstract class AbstractCodeBrowserPlugin<P extends CodeViewerProvider> ex
@Override
public void addOverviewProvider(OverviewProvider overviewProvider) {
JComponent component = overviewProvider.getComponent();
// just in case we get repeated calls
component.removeMouseListener(focusingMouseListener);
component.addMouseListener(focusingMouseListener);
connectedProvider.getListingPanel().addOverviewProvider(overviewProvider);
connectedProvider.addOverviewProvider(overviewProvider);
}
@Override
public void addMarginProvider(MarginProvider marginProvider) {
JComponent component = marginProvider.getComponent();
// just in case we get repeated calls
component.removeMouseListener(focusingMouseListener);
component.addMouseListener(focusingMouseListener);
connectedProvider.getListingPanel().addMarginProvider(marginProvider);
connectedProvider.addMarginProvider(marginProvider);
}
@Override
public void removeOverviewProvider(OverviewProvider overviewProvider) {
JComponent component = overviewProvider.getComponent();
component.removeMouseListener(focusingMouseListener);
connectedProvider.getListingPanel().removeOverviewProvider(overviewProvider);
connectedProvider.removeOverviewProvider(overviewProvider);
}
@Override
public void removeMarginProvider(MarginProvider marginProvider) {
JComponent component = marginProvider.getComponent();
component.removeMouseListener(focusingMouseListener);
connectedProvider.getListingPanel().removeMarginProvider(marginProvider);
connectedProvider.removeMarginProvider(marginProvider);
}
@Override
@ -927,12 +910,4 @@ public abstract class AbstractCodeBrowserPlugin<P extends CodeViewerProvider> ex
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.Transferable;
import java.awt.dnd.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.*;
@ -100,6 +101,8 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
private FormatManager formatMgr;
private FieldPanelCoordinator coordinator;
private FocusingMouseListener focusingMouseListener;
private CodeBrowserClipboardProvider codeViewerClipboardProvider;
private ClipboardService clipboardService;
@ -1011,6 +1014,45 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
listingPanel.removeDisplayListener(listener);
}
private synchronized void createFocusingMouseListener() {
if (focusingMouseListener == null) {
focusingMouseListener = new FocusingMouseListener();
}
}
public void addOverviewProvider(OverviewProvider overviewProvider) {
createFocusingMouseListener();
JComponent component = overviewProvider.getComponent();
// just in case we get repeated calls
component.removeMouseListener(focusingMouseListener);
component.addMouseListener(focusingMouseListener);
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
//==================================================================================================
@ -1092,4 +1134,11 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
return list.toArray(new Highlight[list.size()]);
}
}
private class FocusingMouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
getListingPanel().getFieldPanel().requestFocus();
}
}
}

View File

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

View File

@ -30,6 +30,7 @@ import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.services.CodeViewerService;
import ghidra.app.util.viewer.listingpanel.*;
import ghidra.app.util.viewer.options.OptionsGui;
import ghidra.app.util.viewer.util.AddressIndexMap;
import ghidra.framework.options.OptionsChangeListener;
import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.*;
@ -138,7 +139,8 @@ public class FlowArrowPlugin extends Plugin implements MarginProvider, OptionsCh
}
@Override
public void setPixelMap(VerticalPixelAddressMap pixmap) {
public void setProgram(Program program, AddressIndexMap addrMap,
VerticalPixelAddressMap pixmap) {
this.layoutToPixel = pixmap;
validateState();
updateFlowArrows();
@ -334,9 +336,10 @@ public class FlowArrowPlugin extends Plugin implements MarginProvider, OptionsCh
}
}
/**
/**
* 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) {
@ -430,8 +433,9 @@ public class FlowArrowPlugin extends Plugin implements MarginProvider, OptionsCh
List<FlowArrow> results = new ArrayList<>();
ArrowCache arrowCache = new ArrowCache();
CodeUnitIterator it = program.getListing().getCodeUnitIterator(
CodeUnit.INSTRUCTION_PROPERTY, screenAddresses, true);
CodeUnitIterator it = program.getListing()
.getCodeUnitIterator(
CodeUnit.INSTRUCTION_PROPERTY, screenAddresses, true);
while (it.hasNext()) {
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.
* Further, we rebuild arrows as the screen moves, causing the x coordinate
* to change as arrows that are no longer on the screen are removed and
* as new arrows are added. We want to make sure that we don't end up
* with an arrow in the selected/active sets that are the same as the one
* in the 'all' set, but with a different width. This causes both arrows
* to become visible--basically, the selected arrows can become stale as
* their width changes. This code is meant to address this out-of-sync
* behavior.
* Further, we rebuild arrows as the screen moves, causing the x coordinate to change as arrows
* that are no longer on the screen are removed and as new arrows are added. We want to make
* sure that we don't end up with an arrow in the selected/active sets that are the same as the
* one in the 'all' set, but with a different width. This causes both arrows to become
* visible--basically, the selected arrows can become stale as their width changes. This code is
* meant to address this out-of-sync behavior.
*
* @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);
if (bottomAddr != null) {
AddressSpace testSpace = bottomAddr.getAddressSpace();
validState = (program.getAddressFactory().getAddressSpace(
validState = (program.getAddressFactory()
.getAddressSpace(
testSpace.getSpaceID()) == testSpace);
}
}

View File

@ -17,46 +17,37 @@ package ghidra.app.plugin.core.marker;
import ghidra.GhidraOptions;
import ghidra.app.CorePluginPackage;
import ghidra.app.events.ProgramActivatedPluginEvent;
import ghidra.app.events.ProgramClosedPluginEvent;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.services.*;
import ghidra.app.util.HelpTopics;
import ghidra.framework.options.Options;
import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation;
/**
* Plugin to manage marker and navigation panels.
*
*
*/
//@formatter:off
@PluginInfo(
status = PluginStatus.RELEASED,
packageName = CorePluginPackage.NAME,
category = PluginCategoryNames.SUPPORT,
shortDescription = "Provides the marker display",
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 "
+ "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 "
+ "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 "
+ "value such as selection. Point markers are used to represent individual addresses such "
+ "as bookmarks.",
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 " +
"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 " +
"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 " +
"value such as selection. Point markers are used to represent individual addresses such " +
"as bookmarks.",
servicesRequired = { CodeViewerService.class, GoToService.class },
servicesProvided = { MarkerService.class },
eventsConsumed = { ProgramActivatedPluginEvent.class, ProgramClosedPluginEvent.class }
)
//@formatter:on
eventsConsumed = {})
public class MarkerManagerPlugin extends Plugin {
private CodeViewerService codeViewerService;
private MarkerManager markerManager;
private Program program;
/**
* @param tool
@ -87,23 +78,4 @@ public class MarkerManagerPlugin extends Plugin {
codeViewerService.addMarginProvider(markerManager.getMarginProvider());
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;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.util.List;
import javax.swing.JPanel;
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
* of the scrolled field panel.
* Panel to display markers. Normally placed to the left hand side of the scrolled
* {@link FieldPanel}.
*/
public class MarkerPanel extends JPanel {
private MarkerManager manager;
private Program program;
private AddressIndexMap addrMap;
private VerticalPixelAddressMap pixmap;
MarkerPanel(MarkerManager manager) {
super();
this.manager = manager;
this.setPreferredSize(new Dimension(16, 1));
ToolTipManager.sharedInstance().registerComponent(this);
}
void setProgram(Program program, AddressIndexMap addrMap, VerticalPixelAddressMap pixmap) {
this.program = program;
this.addrMap = addrMap;
this.pixmap = pixmap;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
manager.paintMarkers(g);
manager.paintMarkers(program, g, pixmap, addrMap);
}
@Override
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 {
protected MarkerManager mgr;
private Program program;
protected Program program;
private String name;
protected String description;
@ -50,6 +50,8 @@ abstract class MarkerSetImpl implements MarkerSet {
protected AddressSetCollection markers;
protected SortedRangeList overview = null;
protected VerticalPixelAddressMap activePixmap = null;
protected List<Integer> activeLayouts = null;
protected Color markerColor;
@ -98,6 +100,7 @@ abstract class MarkerSetImpl implements MarkerSet {
/**
* Returns the Navigator Icon for this marker set
*
* @return the Navigator Icon for this marker set
*/
public abstract ImageIcon getNavIcon();
@ -248,11 +251,10 @@ abstract class MarkerSetImpl implements MarkerSet {
}
}
public final void paintNavigation(Graphics g, int height, NavigationPanel panel,
AddressIndexMap map) {
public final void paintNavigation(Graphics g, int height, int width, AddressIndexMap map) {
if (showNavigation) {
SortedRangeList newOverview = computeNavigationIndexes(height, map);
doPaintNavigation(g, height, panel.getWidth(), newOverview);
SortedRangeList newOverview = computeNavigationIndices(height, map);
doPaintNavigation(g, height, width, newOverview);
}
}
@ -293,7 +295,7 @@ abstract class MarkerSetImpl implements MarkerSet {
return null;
}
if (activeLayouts != null) {
if (activeLayouts != null && activePixmap == pixmap) {
return activeLayouts; // use cache
}
@ -311,19 +313,19 @@ abstract class MarkerSetImpl implements MarkerSet {
}
}
activePixmap = pixmap;
activeLayouts = newLayouts;
return newLayouts;
}
private SortedRangeList computeNavigationIndexes(int height, AddressIndexMap map) {
private SortedRangeList computeNavigationIndices(int height, AddressIndexMap map) {
lastHeight = height;
double numIndexes = map.getIndexCount().doubleValue();
if (markers.isEmpty() || height == 0 || numIndexes == 0) {
return null;
}
if (overview != null) {
if (overview != null && lastHeight == height) {
return overview; // use cache
}
@ -376,6 +378,7 @@ abstract class MarkerSetImpl implements MarkerSet {
}
}
lastHeight = height;
overview = newOverview;
return newOverview;
}
@ -391,7 +394,7 @@ abstract class MarkerSetImpl implements MarkerSet {
*/
public String getTooltip(Address addr, int x, int y) {
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 null;
@ -421,7 +424,10 @@ abstract class MarkerSetImpl implements MarkerSet {
public ProgramLocation getProgramLocation(int y, int height, AddressIndexMap map, int x) {
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;
}
@ -455,12 +461,12 @@ abstract class MarkerSetImpl implements MarkerSet {
addr = set.getMinAddress();
}
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);
}
if (loc == null) {
loc = new ProgramLocation(mgr.getProgram(), addr);
loc = new ProgramLocation(program, addr);
}
}
return loc;

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,23 +15,35 @@
*/
package ghidra.app.plugin.core.marker;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.*;
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
* FieldPanel.
* Normally placed to the right of the scrolled panel.
* Panel to display an overview of all markers placed within a scrolled {@link FieldPanel}. Normally
* placed to the right of the scrolled panel.
*/
public class NavigationPanel extends JPanel {
private MarkerManager manager;
private Navigatable navigatable;
private Program program;
private AddressIndexMap addrMap;
NavigationPanel(MarkerManager manager) {
super();
this.manager = manager;
this.setPreferredSize(new Dimension(16, 1));
init();
}
@ -41,12 +52,11 @@ public class NavigationPanel extends JPanel {
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) {
manager.navigateTo(e.getX(), e.getY());
if ((e.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0) {
manager.navigateTo(navigatable, program, e.getX(), e.getY(), getViewHeight(),
addrMap);
}
}
});
}
@ -56,7 +66,23 @@ public class NavigationPanel extends JPanel {
@Override
protected void paintComponent(Graphics 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;
/**
* @param navigationManager manager for these point markers
* @param navigationManager manager for these point markers
* @param name the name for 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 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 colorBackground colorBackground the color of marked areas in navigation bar
* If color is null, no results are displayed in the associated marker bar.
* @param showNavigation true indicates to show area navigation markers (on the right side of
* the browser.)
* @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 icon the icon used to represent the cursor in the marker margin
* @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 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 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 colorBackground colorBackground the color of marked areas in navigation bar
* If color is null, no results are displayed in the associated marker bar.
* @param showNavigation true indicates to show area navigation markers (on the right side of
* the browser.)
* @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 icon the icon used to represent the cursor in the marker margin
* @param program the program to which the markers apply
@ -115,7 +117,6 @@ class PointMarkerSet extends MarkerSetImpl {
}
Address address = pixmap.getLayoutAddress(i);
Program program = mgr.getProgram();
MarkerLocation loc = new MarkerLocation(this, program, address, 0, yStart);
ImageIcon icon = markerDescriptor.getIcon(loc);
if (icon != null) {

View File

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

View File

@ -20,7 +20,7 @@ import java.awt.Color;
import javax.swing.ImageIcon;
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.framework.plugintool.ServiceInfo;
import ghidra.program.model.address.Address;
@ -28,8 +28,8 @@ import ghidra.program.model.listing.Program;
/**
* <p>
* Service to manage navigation markers displayed around a scrollable window like the Listing.
* The navigation bar displays the general location of markers for the entire view. The marker bar
* Service to manage navigation markers displayed around a scrollable window like the Listing. The
* 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.
* </p>
* <p>
@ -39,16 +39,18 @@ import ghidra.program.model.listing.Program;
* </p>
* <a name="usage"></a> <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
* service has been changed to associate created markers with individual programs. Thus, it is
* up to the clients of this class perform lifecycle management of markers created by this
* service. For example, a client that creates a marker from
* {@link #createAreaMarker(String, String, Program, int, boolean, boolean, boolean, Color)} should
* 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 up to
* the clients of this class perform lifecycle management of markers created by this service. For
* example, a client that creates a marker from
* {@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
* a program has become deactivated. In this example usage markers are added and removed as the
* user tabs through open programs.
* a program has become deactivated. In this example usage markers are added and removed as the user
* 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 {
/**
@ -104,7 +106,7 @@ public interface MarkerService {
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 #removeMarkerForGroup(String, MarkerSet, Program)}
*/
@ -118,7 +120,8 @@ public interface MarkerService {
* @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 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 color the color of marked areas.
* @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 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 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 color the color of marked areas.
* @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 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 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 color the color of marked areas in navigation 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 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 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 color the color of marked areas in navigation bar
* @param icon icon to display in marker bar
@ -200,9 +206,10 @@ public interface MarkerService {
public MarkerSet getMarkerSet(String name, Program program);
/**
* Sets a marker set for a given group name. Any previous marker set associated with the
* given group name will be removed from this marker service. This method is used to ensure
* that only one marker set is used at any time for a give group.
* Sets a marker set for a given group name. Any previous marker set associated with the given
* group name will be removed from this marker service. This method is used to ensure that only
* one marker set is used at any time for a give group.
*
* @param groupName The name to associate the marker set with.
* @param markerSet The marker set to add to this service
* @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);
/**
* Removes a marker set for a given group name. If the given marker set is not the marker
* set associated with the given group name, then no action will be taken.
* Removes a marker set for a given group name. If the given marker set is not the marker set
* associated with the given group name, then no action will be taken.
*
* @param groupName The name associated the marker set with.
* @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
* marker is
* @param program The program with which the markers are associated. May be null if the marker
* is
* @see #setMarkerForGroup(String, MarkerSet, 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
* that supports background coloring is checked in priority order to see if it wants to specify
* 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 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
@ -270,4 +266,21 @@ public interface MarkerService {
*/
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.
*
* @param owner the owner of this panel
* @param tool the tool displaying this panel
*/
@ -208,9 +209,6 @@ public class ListingCodeComparisonPanel
Color diffCodeUnitsBackgroundColor = comparisonOptions.getDiffCodeUnitsBackgroundColor();
diffMarkers[LEFT].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
@ -280,6 +278,7 @@ public class ListingCodeComparisonPanel
/**
* Sets the coordinator for the two listings within this code comparison panel. It coordinates
* their scrolling and location synchronization.
*
* @param listingFieldPanelCoordinator the coordinator for the two listings
*/
@Override
@ -303,6 +302,7 @@ public class ListingCodeComparisonPanel
/**
* Adds the indicated highlight providers for the left and right listing panels.
*
* @param leftHighlightProvider the highlight provider for the left 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.
*
* @param leftHighlightProvider the highlight provider for the left 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.
*
* @param programLocationListener the listener
*/
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.
*
* @param programLocationListener the listener
*/
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
* the addresses in the limited set.
* @param show if true, the entire program will be shown. Otherwise the listings will only
* show the limited addresses.
* Sets whether or not the entire programs are displayed in the listings or only the addresses
* in the limited set.
*
* @param show if true, the entire program will be shown. Otherwise the listings will only show
* the limited addresses.
*/
public void showEntireListing(boolean show) {
try {
@ -863,6 +867,7 @@ public class ListingCodeComparisonPanel
/**
* Determines if the listing's layout field header is currently showing.
*
* @return true if the header is showing.
*/
public boolean isHeaderShowing() {
@ -871,6 +876,7 @@ public class ListingCodeComparisonPanel
/**
* Shows or hides the listing's layout field header.
*
* @param show true means show the field header. false means hide the header.
*/
public void setHeaderShowing(boolean show) {
@ -889,6 +895,7 @@ public class ListingCodeComparisonPanel
/**
* 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.
*/
public void showSideBySide(boolean sideBySide) {
@ -932,6 +939,7 @@ public class ListingCodeComparisonPanel
/**
* Gets the function loaded in the left listing panel.
*
* @return the function or null
*/
@Override
@ -941,6 +949,7 @@ public class ListingCodeComparisonPanel
/**
* Gets the function loaded in the right listing panel.
*
* @return the function or null
*/
@Override
@ -989,8 +998,8 @@ public class ListingCodeComparisonPanel
}
/**
* Establishes the location and display of the arrow cursor. This method should be called
* after the function comparison window is loaded with functions, data, etc.
* Establishes the location and display of the arrow cursor. This method should be called after
* the function comparison window is loaded with functions, data, etc.
*/
private void loadCursorArrow() {
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
* vice versa. The intent of this method is to translate a location from one side of the
* dual listing to an equivalent location for the other side if possible.
* vice versa. The intent of this method is to translate a location from one side of the dual
* 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 programLocation the program location for the other side.
* @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
* as the <code>address</code> and <code>desiredAddress</code> that were matched.
* Infers a desired byte address based on the specified <code>byteAddress</code> as well as the
* <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 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 program the program for the <code>address</code> and <code>byteAddress</code>.
* @param desiredProgram the program for the <code>desiredAddress</code> and
* <code>desiredByteAddress</code>.
* @param desiredProgram the program for the <code>desiredAddress</code> and
* <code>desiredByteAddress</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,
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
* <code>codeUnitAddress</code> and <code>desiredCodeUnitAddress</code>.
* The inferred address will be at an offset from the <code>desiredCodeUnitAddress</code>
* that is the same distance the <code>byteAddress</code> is from the <code>codeUnitAddress</code>.
* This infers the desired byte address within Data based on the code units at
* <code>codeUnitAddress</code> and <code>desiredCodeUnitAddress</code>. The inferred address
* will be at an offset from the <code>desiredCodeUnitAddress</code> that is the same distance
* the <code>byteAddress</code> is from the <code>codeUnitAddress</code>.
*
* @param codeUnitAddress matches up with the <code>desiredCodeUnitAddress</code> from
* the other data.
* @param desiredCodeUnitAddress matches up with the <code>codeUnitAddress</code> from
* the other data.
* @param codeUnitAddress matches up with the <code>desiredCodeUnitAddress</code> from the other
* data.
* @param desiredCodeUnitAddress matches up with the <code>codeUnitAddress</code> from the other
* data.
* @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 desiredProgram the program for the <code>desiredCodeUnitAddress</code> and
* <code>desiredByteAddress</code>.
* @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.
* @param desiredProgram the program for the <code>desiredCodeUnitAddress</code> and
* <code>desiredByteAddress</code>.
* @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.
*/
private Address inferDesiredDataAddress(Address codeUnitAddress, Address desiredCodeUnitAddress,
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
* <code>address</code> and <code>desiredAddress</code>.
* If the inferred address would be beyond the last byte of the code unit then it
* will get set to the last byte of the code unit at the <code>desiredAddress</code>.
* This infers the desired byte address within a function based on the code units at
* <code>address</code> and <code>desiredAddress</code>. If the inferred address would be beyond
* the last byte of the code unit then it will get set to the last byte of the code unit at the
* <code>desiredAddress</code>.
*
* @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 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 desiredProgram the program for the <code>desiredAddress</code> and
* <code>desiredByteAddress</code>.
* @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.
* @param desiredProgram the program for the <code>desiredAddress</code> and
* <code>desiredByteAddress</code>.
* @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.
*/
private Address inferDesiredFunctionAddress(Address address, Address desiredAddress,
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
* 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.
*
* @param leftOrRight LEFT or RIGHT indicating which side's variable location is needed.
* @param variableLocation the variable location for the other side.
* @return a variable location for the desired side. Otherwise, null.
@ -1549,7 +1561,6 @@ public class ListingCodeComparisonPanel
listingPanels[LEFT].getFieldPanel()
.setBackgroundColorModel(
new MarkerServiceBackgroundColorModel(markerManagers[LEFT], indexMap));
markerManagers[LEFT].setProgram(programs[LEFT]);
unmatchedCodeMarkers[LEFT] =
markerManagers[LEFT].createAreaMarker("Listing1 Unmatched Code",
"Instructions that are not matched to an instruction in the other function.",
@ -1565,7 +1576,6 @@ public class ListingCodeComparisonPanel
.setBackgroundColorModel(
new MarkerServiceBackgroundColorModel(markerManagers[RIGHT],
rightIndexMap));
markerManagers[RIGHT].setProgram(programs[RIGHT]);
unmatchedCodeMarkers[RIGHT] =
markerManagers[RIGHT].createAreaMarker("Listing2 Unmatched Code",
"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]);
markerManagers[LEFT].getOverviewProvider().setAddressIndexMap(indexMaps[LEFT]);
markerManagers[LEFT].getOverviewProvider().setProgram(getLeftProgram(), indexMaps[LEFT]);
listingPanels[LEFT].getFieldPanel()
.setBackgroundColorModel(
new MarkerServiceBackgroundColorModel(markerManagers[LEFT], indexMaps[LEFT]));
@ -1680,7 +1690,7 @@ public class ListingCodeComparisonPanel
}
indexMaps[RIGHT] = new AddressIndexMap(addressSets[RIGHT]);
markerManagers[RIGHT].getOverviewProvider().setAddressIndexMap(indexMaps[RIGHT]);
markerManagers[RIGHT].getOverviewProvider().setProgram(getRightProgram(), indexMaps[RIGHT]);
listingPanels[RIGHT].getFieldPanel()
.setBackgroundColorModel(
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.
*
* @param leftFunction the function in the left 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.
*
* @param program the left side's program
* @param location the location
*/
@ -1744,6 +1756,7 @@ public class ListingCodeComparisonPanel
/**
* Sets the cursor in the right side's listing to the specified location.
*
* @param program the right side's program
* @param location the location
*/
@ -1863,6 +1876,7 @@ public class ListingCodeComparisonPanel
/**
* Sets the title for the left side's listing.
*
* @param leftTitle the title
*/
public void setLeftTitle(String leftTitle) {
@ -1872,6 +1886,7 @@ public class ListingCodeComparisonPanel
/**
* Sets the title for the right side's listing.
*
* @param rightTitle the title
*/
public void setRightTitle(String rightTitle) {
@ -1881,6 +1896,7 @@ public class ListingCodeComparisonPanel
/**
* Sets the component displayed in the top of this panel.
*
* @param comp the component.
*/
public void setTopComponent(JComponent comp) {
@ -1899,6 +1915,7 @@ public class ListingCodeComparisonPanel
/**
* Sets the component displayed in the bottom of this panel.
*
* @param comp the component.
*/
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.
*
* @return the program from the side of this panel with focus or null
*/
public Program getFocusedProgram() {
@ -1926,6 +1944,7 @@ public class ListingCodeComparisonPanel
/**
* Gets the program in the left listing panel.
*
* @return the left program or null
*/
@Override
@ -1935,6 +1954,7 @@ public class ListingCodeComparisonPanel
/**
* Gets the program in the right listing panel.
*
* @return the right program or null
*/
@Override
@ -1944,6 +1964,7 @@ public class ListingCodeComparisonPanel
/**
* Gets the addresses in the left listing panel.
*
* @return the addresses
*/
@Override
@ -1953,6 +1974,7 @@ public class ListingCodeComparisonPanel
/**
* Gets the addresses in the right listing panel.
*
* @return the addresses
*/
@Override
@ -1962,6 +1984,7 @@ public class ListingCodeComparisonPanel
/**
* Get the left or right listing panel that has or last had focus.
*
* @return the listing panel with focus.
*/
public ListingPanel getFocusedListingPanel() {
@ -1970,6 +1993,7 @@ public class ListingCodeComparisonPanel
/**
* Get the left side's listing panel.
*
* @return the left panel
*/
public ListingPanel getLeftPanel() {
@ -1978,6 +2002,7 @@ public class ListingCodeComparisonPanel
/**
* Get the right side's listing panel.
*
* @return the right panel
*/
public ListingPanel getRightPanel() {
@ -1986,6 +2011,7 @@ public class ListingCodeComparisonPanel
/**
* Go to the indicated address in the listing that last had focus.
*
* @param addr the cursor should go to this address
* @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.
*
* @param loc the cursor should go to this location.
* @param centerOnScreen true indicates that the location should be centered in the listing's
* viewport.
* viewport.
* @return true if the location changed
*/
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
*/
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
* address.
*
* @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
* 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
* side's address that is specified. Otherwise, null.
* side's address that is specified. Otherwise, null.
*/
private Address getAddress(int leftOrRight, Address otherSidesAddress) {
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.
*
* @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
* desired address.
* @param otherSidesAddress address in the other program that is equivalent to the desired
* address.
* @return the matching address in the indicated program or null.
*/
private Address getFunctionAddress(int leftOrRight, Address otherSidesAddress) {
@ -2196,6 +2228,7 @@ public class ListingCodeComparisonPanel
/**
* Is this panel currently comparing a function match?
*
* @return true if comparing functions.
*/
private boolean isFunctionCompare() {
@ -2206,6 +2239,7 @@ public class ListingCodeComparisonPanel
/**
* Is this panel currently comparing a data match?
*
* @return true if comparing data.
*/
private boolean isDataCompare() {
@ -2216,6 +2250,7 @@ public class ListingCodeComparisonPanel
/**
* Gets the left side address that is equivalent to the indicated right side address.
*
* @param rightByteAddress the right side address
* @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.
*
* @param leftByteAddress the left side address
* @return the right side address or null.
*/
@ -2240,6 +2276,7 @@ public class ListingCodeComparisonPanel
/**
* Gets the left side function's entry point address.
*
* @return the left side function's entry point address or null.
*/
private Address getLeftFunctionAddress() {
@ -2251,6 +2288,7 @@ public class ListingCodeComparisonPanel
/**
* Gets the right side function's entry point address.
*
* @return the right side function's entry point address or null.
*/
private Address getRightFunctionAddress() {
@ -2262,6 +2300,7 @@ public class ListingCodeComparisonPanel
/**
* Gets the left side data's minimum address.
*
* @return the left side data's minimum address or null.
*/
private Address getLeftDataAddress() {
@ -2273,6 +2312,7 @@ public class ListingCodeComparisonPanel
/**
* Gets the right side data's minimum address.
*
* @return the right side data's minimum address or null.
*/
private Address getRightDataAddress() {
@ -2381,6 +2421,7 @@ public class ListingCodeComparisonPanel
/**
* Gets the left or right listing panel that contains the indicated field panel.
*
* @param fieldPanel the field panel
* @return the listing panel or null.
*/
@ -2401,6 +2442,7 @@ public class ListingCodeComparisonPanel
/**
* Disable mouse navigation from within this dual listing panel.
*
* @param enabled false disables navigation
*/
@Override
@ -2448,6 +2490,7 @@ public class ListingCodeComparisonPanel
/**
* Gets the maximum offset based on the larger data that is passed to this method.
*
* @param leftData the left view's data
* @param rightData the right view's data
* @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
* maxOffset number of bytes beyond the minAddress without leaving the memory block
* that contains the minAddress. If the maxOffset is beyond the end of the block then
* the end of the block is returned. For an externalAddress the minAddress is returned.
* Gets the ending address to be displayed. It tries to get an ending address that is maxOffset
* number of bytes beyond the minAddress without leaving the memory block that contains the
* minAddress. If the maxOffset is beyond the end of the block then the end of the block is
* returned. For an externalAddress the minAddress is returned.
*
* @param program the program containing the data
* @param maxOffset the max offset
* @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
* field panel coordinator.
* Clears the address correlation being used with the ListingDiff and the dual listing field
* panel coordinator.
*/
private void clearCorrelation() {
correlator = null;
@ -2516,6 +2560,7 @@ public class ListingCodeComparisonPanel
/**
* Gets the data loaded in the left listing panel.
*
* @return the data or null
*/
@Override
@ -2525,6 +2570,7 @@ public class ListingCodeComparisonPanel
/**
* Gets the data loaded in the right listing panel.
*
* @return the data or null
*/
@Override
@ -2560,6 +2606,7 @@ public class ListingCodeComparisonPanel
/**
* Displays the indicated text int the tool's status area.
*
* @param text the message to display
*/
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.
* @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
*/
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
* of the GUI components for the indicated listing panel's marker margin (left edge of listing)
* or overview margin (right edge of listing).
* Gets a marker margin or overview margin context object if the mouse event occurred on one of
* the GUI components for the indicated listing panel's marker margin (left edge of listing) or
* overview margin (right edge of listing).
*
* @param lp The listing panel to check
* @param event the mouse event
* @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.
*
* @param prefix identifier to prepend to any save state names to make them unique.
* @param saveState the configuration state to restore
*/
@ -2743,6 +2793,7 @@ public class ListingCodeComparisonPanel
/**
* Saves the current configuration state of this panel.
*
* @param prefix identifier to prepend to any save state names to make them unique.
* @param saveState the new configuration state
*/

View File

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

View File

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

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,25 +15,34 @@
*/
package ghidra.app.util.viewer.listingpanel;
import ghidra.app.util.viewer.util.AddressIndexMap;
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
* of the listing.
* Interface implemented by classes that provide overview components to the right side of the
* listing.
*/
public interface OverviewProvider {
/**
* Returns the component to diplay in the right margin of the listing.
*/
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;
/**
* Plugin that shows the differences between two programs, and allows the
* user to apply differences to the currently open program. This allows only one
* tabbed program to display a second program (possibly with an active Diff).
* It allows the active program to change without losing the current Diff or
* second program that is opened. De-activation of the first program for the Diff
* will result in termination of the Diff or the Diff can be closed directly by the user.
* Plugin that shows the differences between two programs, and allows the user to apply differences
* to the currently open program. This allows only one tabbed program to display a second program
* (possibly with an active Diff). It allows the active program to change without losing the current
* Diff or second program that is opened. De-activation of the first program for the Diff will
* result in termination of the Diff or the Diff can be closed directly by the user.
*/
//@formatter:off
@PluginInfo(
@ -151,6 +150,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
/**
* Creates the plugin for indicating program differences to the user.
*
* @param tool the tool that owns this plugin.
*/
public ProgramDiffPlugin(PluginTool tool) {
@ -282,7 +282,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
AddressSet p1AddressSetAsP2 =
DiffUtility.getCompatibleAddressSet(p1AddressSet, secondaryDiffProgram);
AddressIndexMap p2IndexMap = new AddressIndexMap(p1AddressSetAsP2);
markerManager.getOverviewProvider().setAddressIndexMap(p2IndexMap);
markerManager.getOverviewProvider().setProgram(secondaryDiffProgram, p2IndexMap);
fp.setBackgroundColorModel(
new MarkerServiceBackgroundColorModel(markerManager, p2IndexMap));
@ -479,8 +479,9 @@ public class ProgramDiffPlugin extends ProgramPlugin
}
/**
* Called when a program gets closed.
* If the closed program is the first program of the Diff then we need to close the second program.
* Called when a program gets closed. If the closed program is the first program of the Diff
* then we need to close the second program.
*
* @param program
*/
@Override
@ -719,8 +720,8 @@ public class ProgramDiffPlugin extends ProgramPlugin
/**
* 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
* listing which displays P2.
* Note: A P2 selection is handed to this method when a selection is made in the diff listing
* which displays P2.
*/
@Override
public void programSelectionChanged(ProgramSelection newP2Selection) {
@ -838,8 +839,9 @@ public class ProgramDiffPlugin extends ProgramPlugin
}
/**
* Set the highlight based on the current program differences, but
* do not set the highlight for set of addresses to be ignored.
* Set the highlight based on the current program differences, but do not set the highlight for
* set of addresses to be ignored.
*
* @param ignoreAddressSet the set of addresses to ignore.
*/
private void setDiffHighlight() {
@ -849,7 +851,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
AddressSetView p1DiffSet = null;
try {
p1DiffSet = diffControl.getFilteredDifferences(TaskMonitorAdapter.DUMMY_MONITOR);
p1DiffSet = diffControl.getFilteredDifferences(TaskMonitor.DUMMY);
}
catch (CancelledException e) {
// 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
* in the browser using the current Limiting set. It allows the user to specify the Diff settings to use.
* Computes the differences between program1 and program2 that are displayed in the browser
* using the current Limiting set. It allows the user to specify the Diff settings to use.
*/
void diff() {
diff(createLimitingSet());
}
/**
* Computes the differences between program1 and program2 that are displayed
* in the browser. It allows the user to specify the Diff settings to use.
* Computes the differences between program1 and program2 that are displayed in the browser. It
* allows the user to specify the Diff settings to use.
*
* @param p1LimitSet an address set to use to limit the extent of the Diff.
*/
void diff(AddressSetView p1LimitSet) {
@ -1055,7 +1058,6 @@ public class ProgramDiffPlugin extends ProgramPlugin
setProgram2Selection(p2Selection);
clearDiff();
if (secondaryDiffProgram != null) {
markerManager.setProgram(null);
Iterator<BookmarkNavigator> iter = bookmarkMap.values().iterator();
while (iter.hasNext()) {
BookmarkNavigator nav = iter.next();
@ -1171,10 +1173,11 @@ public class ProgramDiffPlugin extends ProgramPlugin
}
/**
* Get the first program for the current Diff.
* <br><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.
* Get the first program for the current Diff. <br>
* <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.
*/
Program getFirstProgram() {
return primaryProgram;
@ -1182,8 +1185,9 @@ public class ProgramDiffPlugin extends ProgramPlugin
/**
* 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() {
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
* indicated address. An address set is returned since the indicated address may be in different
* sized code units in each of the two programs.
*
* @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
* compared to determine differences.
* Otherwise null if a diff of two programs isn't being performed.
* compared to determine differences. Otherwise null if a diff of two programs isn't
* being performed.
*/
AddressSetView getDetailsAddressSet(Address p1Address) {
if (diffDetails != null) {
@ -1598,7 +1603,6 @@ public class ProgramDiffPlugin extends ProgramPlugin
finally {
settingLocation = false;
}
markerManager.setProgram(secondaryDiffProgram);
setupBookmarkNavigators();
sameProgramContext = ProgramMemoryComparator.sameProgramContextRegisterNames(primaryProgram,