diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointMarkerPlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointMarkerPlugin.java index 7ff8928bb6..746c280aa6 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointMarkerPlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointMarkerPlugin.java @@ -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 result = new HashSet<>(); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java index e9f70ac31b..05fd0842a2 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java @@ -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 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 diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/AddBookmarkAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/AddBookmarkAction.java index 1f571dd856..fd483ffdbf 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/AddBookmarkAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/AddBookmarkAction.java @@ -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; /** * AddBookmarkAction 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; + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java index 332096c47f..198519e00a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkPlugin.java @@ -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 maxActionsCount - * @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 maxActionsCount + * + * @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 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 for the given type of bookmark. + * Returns a list of actions to delete bookmarks that are in the code unit surrounding the given + * address for the given type of bookmark. + * * @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 primaryAddress. - * @return a list of actions to delete bookmarks that are in the code unit surrounding the - * given address for the given type of bookmark. + * @param navigator The BookmarkNavigator used to determine whether there are bookmarks inside + * the code unit containing the given primaryAddress. + * @return a list of actions to delete bookmarks that are in the code unit surrounding the given + * address for the given type of bookmark. */ private List getActionsForCodeUnitAndType(Address primaryAddress, String type, BookmarkNavigator navigator) { @@ -585,9 +593,10 @@ public class BookmarkPlugin extends ProgramPlugin /** * Adds the actions in newActionList to actionList while the size of * actionList 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 actionList, List newActionList, int maxActionCount) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AbstractCodeBrowserPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AbstractCodeBrowserPlugin.java index 241463af08..a2e47229dd 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AbstractCodeBrowserPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AbstractCodeBrowserPlugin.java @@ -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

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

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

ex fieldPanel.repaint(); } } - - private class FocusingMouseListener extends MouseAdapter { - @Override - public void mousePressed(MouseEvent e) { - connectedProvider.getListingPanel().getFieldPanel().requestFocus(); - } - } - } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeViewerProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeViewerProvider.java index 018cb50e94..a0bca264b6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeViewerProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeViewerProvider.java @@ -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(); + } + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/MarkerServiceBackgroundColorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/MarkerServiceBackgroundColorModel.java index c972b7a62e..3515975d23 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/MarkerServiceBackgroundColorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/MarkerServiceBackgroundColorModel.java @@ -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); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/flowarrow/FlowArrowPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/flowarrow/FlowArrowPlugin.java index 01911e1a6e..4a87ad48e8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/flowarrow/FlowArrowPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/flowarrow/FlowArrowPlugin.java @@ -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 getArrowsAtSameDepth(FlowArrow jump, List allArrows) { @@ -430,8 +433,9 @@ public class FlowArrowPlugin extends Plugin implements MarginProvider, OptionsCh List 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); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerManager.java index dbfb4d407c..48c6f85b2c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerManager.java @@ -15,143 +15,96 @@ */ package ghidra.app.plugin.core.marker; -import java.awt.*; -import java.awt.event.*; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.event.MouseEvent; import java.util.*; -import java.util.List; -import java.util.Map.Entry; -import javax.swing.*; +import javax.swing.ImageIcon; +import javax.swing.JToolTip; import javax.swing.event.ChangeListener; +import org.apache.commons.collections4.IterableUtils; import org.apache.commons.collections4.map.LazyMap; -import docking.ActionContext; -import docking.action.*; import docking.widgets.PopupWindow; -import ghidra.GhidraOptions; import ghidra.app.nav.Navigatable; import ghidra.app.services.*; -import ghidra.app.util.HelpTopics; import ghidra.app.util.viewer.listingpanel.*; import ghidra.app.util.viewer.util.AddressIndexMap; -import ghidra.framework.options.*; +import ghidra.framework.model.DomainObjectClosedListener; import ghidra.framework.plugintool.Plugin; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSet; import ghidra.program.model.listing.Program; -import ghidra.program.util.MarkerLocation; import ghidra.program.util.ProgramLocation; -import ghidra.util.HelpLocation; -import ghidra.util.SystemUtilities; -import ghidra.util.datastruct.FixedSizeHashMap; +import ghidra.util.datastruct.*; import ghidra.util.exception.AssertException; import ghidra.util.task.SwingUpdateManager; /** - * Manages markers on the marker panel (left side) and the overview - * panel (right side). + * Manages markers on the marker panel (left side) and the overview panel (right side). */ public class MarkerManager implements MarkerService { - private final static String POPUP_WINDOW_NAME = "Bookmark ToolTip Window"; - private final static int MAX_TOOLTIP_LINES = 10; - - private MarkerPanel markerPanel; - private NavigationPanel navigationPanel; - private MarkerActionList actionList; - private VerticalPixelAddressMap pixmap; - private AddressIndexMap addrMap; + final static String POPUP_WINDOW_NAME = "Marker ToolTip Window"; + final static int MAX_TOOLTIP_LINES = 10; /** - * For any given group name there can be any number of programs that have that group name - * mapped to a MarkerSet. This structure allows for a lookup of the marker set group to - * get a mapping of program->marker set. + * For any given group name there can be any number of programs that have that group name mapped + * to a MarkerSet. This structure allows for a lookup of the marker set group to get a mapping + * of program->marker set. */ private Map> programMarkersByGroup = LazyMap.lazyMap(new HashMap<>(), () -> new HashMap<>()); - private List currentMarkerSets = Collections.emptyList(); - /** * A cache of programs to marker sets so that clients can install marker sets on a * program-by-program basis */ - private Map> markerSetCache = - LazyMap.lazyMap(new HashMap<>(), () -> new ArrayList<>()); + private MarkerSetCache markerSetCache = new MarkerSetCache(); /** Buffers requests to repaint and notify of marker changes */ private SwingUpdateManager updater; private GoToService goToService; - private Navigatable navigatable; - private MarginProvider marginProvider; - private OverviewProvider overviewProvider; + private MarkerMarginProvider primaryMarginProvider; + private WeakSet marginProviders = + WeakDataStructureFactory.createCopyOnWriteWeakSet(); - private PluginTool tool; - private String owner; // owner of the actions - private Program currentProgram; + private MarkerOverviewProvider primaryOverviewProvider; + private WeakSet overviewProviders = + WeakDataStructureFactory.createCopyOnWriteWeakSet(); - private Map colorCache = - LazyMap.lazyMap(new HashMap<>(), () -> new AddressColorCache()); + private final PluginTool tool; + private final String owner; private PopupWindow popupWindow; private List listeners = new ArrayList<>(); private MarkerClickedListener markerClickedListener = null; - public MarkerManager(Plugin ownerPlugin) { - this(ownerPlugin.getName(), ownerPlugin.getTool()); + public MarkerManager(Plugin plugin) { + this(plugin.getName(), plugin.getTool()); } public MarkerManager(String owner, PluginTool tool) { - this.owner = owner; this.tool = tool; + this.owner = owner; updater = new SwingUpdateManager(100, 60000, () -> { - markerPanel.repaint(); - navigationPanel.repaint(); + marginProviders.forEach(provider -> provider.repaintPanel()); + overviewProviders.forEach(provider -> provider.repaintPanel()); notifyListeners(); }); - navigationPanel = new NavigationPanel(this); - navigationPanel.setPreferredSize(new Dimension(16, 1)); - navigationPanel.addComponentListener(new ComponentAdapter() { - @Override - public void componentResized(ComponentEvent e) { - updateMarkerSets(true, true, true); - } - }); - overviewProvider = new MyOverviewProvider(); + primaryMarginProvider = createMarginProvider(); + primaryOverviewProvider = createOverviewProvider(); - markerPanel = new MarkerPanel(this); - markerPanel.setPreferredSize(new Dimension(16, 1)); - marginProvider = new MyMarginProvider(); - - markerPanel.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() != 2 || markerClickedListener == null) { - return; - } - Address addr = getAddress(e.getY()); - if (addr == null) { - return; - } - MarkerSet marker = getMarkerSet(addr); - MarkerLocation location = - new MarkerLocation(marker, currentProgram, addr, e.getX(), e.getY()); - markerClickedListener.markerDoubleClicked(location); - } - }); - - actionList = new MarkerActionList(); } - void programClosed(Program program) { - markerSetCache.remove(program); - + private void programClosed(Program program) { Map> values = programMarkersByGroup; Collection> valueValues = values.values(); for (Map map : valueValues) { @@ -211,13 +164,7 @@ public class MarkerManager implements MarkerService { throw new NullPointerException("Program cannot be null."); } - List list = markerSetCache.get(program); - for (MarkerSetImpl set : list) { - if (name.equals(set.getName())) { - return set; - } - } - return null; + return markerSetCache.get(program).getByName(name); } @Override @@ -227,18 +174,22 @@ public class MarkerManager implements MarkerService { } doRemoveMarker(markers, program); - actionList.refresh(); + refreshActionList(program); markersChanged(program); } + private void refreshActionList(Program program) { + overviewProviders.forEach(provider -> provider.refreshActionList(program)); + } + private void doRemoveMarker(MarkerSet markers, Program program) { if (markers == null || program == null) { return; } // per-program list - List list = markerSetCache.get(program); - list.remove(markers); + MarkerSetCacheEntry entry = markerSetCache.get(program); + entry.removeSet(markers); // per-group list // We need to find the marker by searching through the map of maps (when used in a @@ -254,92 +205,70 @@ public class MarkerManager implements MarkerService { } - public MarginProvider getMarginProvider() { - return marginProvider; + public MarkerMarginProvider getMarginProvider() { + return primaryMarginProvider; + } + + @Override + public MarkerMarginProvider createMarginProvider() { + MarkerMarginProvider provider = new MarkerMarginProvider(this); + marginProviders.add(provider); + return provider; } public OverviewProvider getOverviewProvider() { - return overviewProvider; + return primaryOverviewProvider; } - /** - * Set the program for the marker sets. - * @param program may be null - */ - public void setProgram(Program program) { - this.currentProgram = program; - if (program == null) { - currentMarkerSets = Collections.emptyList(); - updater.update(); - return; - } - - colorCache.get(program).clear(); - setCurrentMarkerSets(program); - actionList.refresh(); - - updater.update(); + @Override + public MarkerOverviewProvider createOverviewProvider() { + MarkerOverviewProvider provider = new MarkerOverviewProvider(owner, tool, this); + overviewProviders.add(provider); + return provider; } public void dispose() { updater.dispose(); - actionList.dispose(); - currentMarkerSets.clear(); markerSetCache.clear(); - colorCache.clear(); + overviewProviders.forEach(provider -> provider.dispose()); } - void navigateTo(int x, int y) { - int viewHeight = navigationPanel.getHeight() - MarkerSetImpl.MARKER_HEIGHT; - for (int i = currentMarkerSets.size() - 1; i >= 0; i--) { - MarkerSetImpl markers = currentMarkerSets.get(i); - if (markers.isActive()) { - GoToService service = getGoToService(); - ProgramLocation loc = markers.getProgramLocation(y, viewHeight, addrMap, x); - if (loc != null && service != null) { - service.goTo(navigatable, loc, loc.getProgram()); - break; - } - } + void navigateTo(Navigatable navigatable, Program program, int x, int y, int viewHeight, + AddressIndexMap addrMap) { + MarkerSetCacheEntry entry = markerSetCache.get(program); + + ProgramLocation loc = entry.getProgramLocation(y, viewHeight, addrMap, x); + getGoToService(); + if (loc != null && goToService != null) { + goToService.goTo(navigatable, loc, loc.getProgram()); } } - void paintMarkers(Graphics g) { - Iterator it = currentMarkerSets.iterator(); - int count = 0; - while (it.hasNext()) { - MarkerSetImpl markers = it.next(); - if (markers.isActive()) { - markers.paintMarkers(g, count++, pixmap, addrMap); - } - } - } - - void paintNavigation(Graphics g, NavigationPanel panel) { + void paintNavigation(Program program, Graphics g, NavigationPanel panel, + AddressIndexMap addrMap) { if (addrMap == null) { return; } - int viewHeight = panel.getHeight() - MarkerSetImpl.MARKER_HEIGHT; - Iterator it = currentMarkerSets.iterator(); - while (it.hasNext()) { - MarkerSetImpl markers = it.next(); - if (markers.active) { - markers.paintNavigation(g, viewHeight, panel, addrMap); - } + MarkerSetCacheEntry entry = markerSetCache.get(program); + if (entry == null) { + return; } + entry.paintNavigation(g, panel.getViewHeight(), panel.getWidth(), addrMap); } - /** - * Method getTooltip for object under cursor - * @param event the event containing the cursor coordinates - * @return tool tip string for object under cursor - */ - String getTooltip(MouseEvent event) { + void paintMarkers(Program program, Graphics g, VerticalPixelAddressMap pixmap, + AddressIndexMap addrMap) { + MarkerSetCacheEntry entry = markerSetCache.get(program); + if (entry == null) { + return; + } + entry.paintMarkers(g, pixmap, addrMap); + } - String tip = generateToolTip(event); + void showToolTipPopup(MouseEvent event, String tip) { if (tip == null) { - return null; + return; } JToolTip toolTip = new JToolTip(); @@ -349,58 +278,21 @@ public class MarkerManager implements MarkerService { popupWindow.dispose(); } popupWindow = new PopupWindow(event.getComponent(), toolTip); - popupWindow.setWindowName(POPUP_WINDOW_NAME); + popupWindow.setWindowName(MarkerManager.POPUP_WINDOW_NAME); popupWindow.showPopup(event); - - return null; // signal not to show a Java tooltip } - 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 lines = getMarkerTooltipLines(y, x, layoutIndex, layoutAddress); - return toHTML(lines); + /*testing*/ String generateToolTip(MouseEvent event) { + return primaryMarginProvider.generateToolTip(event); } - private List getMarkerTooltipLines(int y, int x, int layoutIndex, - Address layoutAddress) { - Address endAddr = pixmap.getLayoutEndAddress(layoutIndex); - List lines = new ArrayList<>(); - for (int i = currentMarkerSets.size() - 1; i >= 0; i--) { - - MarkerSetImpl markers = currentMarkerSets.get(i); - if (!markers.displayInMarkerBar()) { - continue; - } - - AddressSet set = markers.getAddressSet(); - AddressSet intersection = set.intersect(new AddressSet(layoutAddress, endAddr)); - for (Address a : intersection.getAddresses(true)) { - lines.add(getMarkerToolTip(markers, a, x, y)); - - if (markers instanceof AreaMarkerSet) { - break; // no more tooltips from this area - } - if (lines.size() >= MAX_TOOLTIP_LINES) { - lines.add("..."); - return lines; - } - } - } - return lines; + List getMarkerTooltipLines(Program program, int y, int x, Address minAddr, + Address maxAddr) { + MarkerSetCacheEntry entry = markerSetCache.get(program); + return entry.getTooltipLines(y, x, minAddr, maxAddr); } - private String getMarkerToolTip(MarkerSetImpl marker, Address a, int x, int y) { + static String getMarkerToolTip(MarkerSetImpl marker, Address a, int x, int y) { String tip = marker.getTooltip(a, x, y); if (tip == null) { tip = marker.getName(); @@ -408,16 +300,8 @@ public class MarkerManager implements MarkerService { return tip; } - private String toHTML(List lines) { - if (lines.isEmpty()) { - return null; - } - - StringBuilder buffy = new StringBuilder(""); - for (String string : lines) { - buffy.append(string).append("
"); - } - return buffy.toString(); + List copyMarkerSets(Program program) { + return markerSetCache.get(program).copyList(); } /** @@ -427,7 +311,7 @@ public class MarkerManager implements MarkerService { * @param p the program associated with the markers */ void markersChanged(Program p) { - colorCache.get(p).clear(); + markerSetCache.get(p).colorCache.clear(); updater.update(); } @@ -436,48 +320,24 @@ public class MarkerManager implements MarkerService { throw new AssertException("Program cannot be null"); } - List markerSets = markerSetCache.get(program); - if (markerSets == null) { + MarkerSetCacheEntry entry = markerSetCache.get(program); + if (entry == null) { return; // no list means deprecated usage } - int index = Collections.binarySearch(markerSets, markers); - if (index < 0) { - index = -(index + 1); - } + entry.insertSet(markers); - markerSets.add(index, markers); - actionList.refresh(); + refreshActionList(program); } - private void setCurrentMarkerSets(Program program) { - List markerSets = markerSetCache.get(program); + void updateMarkerSets(Program program, boolean updateMarkers, boolean updateNavigation, + boolean updateNow) { - // determine if we are switching lists - boolean switchingLists = (markerSets != currentMarkerSets); - if (!switchingLists) { + MarkerSetCacheEntry entry = markerSetCache.get(program); + if (entry == null) { return; } - - currentMarkerSets = markerSets; - Collections.sort(currentMarkerSets); - } - - private Address getAddress(int y) { - if (pixmap == null) { - return null; - } - int i = pixmap.findLayoutAt(y); - return pixmap.getLayoutAddress(i); - } - - private void updateMarkerSets(boolean updateMarkers, boolean updateNavigation, - boolean updateNow) { - Iterator it = currentMarkerSets.iterator(); - while (it.hasNext()) { - MarkerSetImpl marker = it.next(); - marker.updateView(updateMarkers, updateNavigation); - } + entry.updateView(updateMarkers, updateNavigation); if (updateNow) { updater.updateNow(); @@ -504,18 +364,9 @@ public class MarkerManager implements MarkerService { } } - private MarkerSetImpl getMarkerSet(Address addr) { - for (int i = currentMarkerSets.size() - 1; i >= 0; i--) { - MarkerSetImpl markers = currentMarkerSets.get(i); - if (markers.displayInMarkerBar() && markers.contains(addr)) { - return markers; - } - } - return null; - } - - Program getProgram() { - return currentProgram; + MarkerSetImpl getMarkerSet(Program program, Address addr) { + MarkerSetCacheEntry entry = markerSetCache.get(program); + return entry.getMarkerSetAt(addr); } @Override @@ -547,34 +398,13 @@ public class MarkerManager implements MarkerService { } } - @Override - public Color getBackgroundColor(Address address) { - return getBackgroundColor(currentProgram, currentMarkerSets, address); - } - @Override public Color getBackgroundColor(Program program, Address address) { - Program markerProgram = program == null ? currentProgram : program; - return getBackgroundColor(markerProgram, markerSetCache.get(markerProgram), address); + return getBackgroundColor(program, markerSetCache.get(program), address); } - private Color getBackgroundColor(Program program, List markerSets, - Address address) { - - AddressColorCache addressColorCache = colorCache.get(program); - if (addressColorCache.containsKey(address)) { - return addressColorCache.get(address); - } - - for (int index = markerSets.size() - 1; index >= 0; index--) { - MarkerSet markers = markerSets.get(index); - if (markers.isActive() && markers.isColoringBackground() && markers.contains(address)) { - Color color = markers.getMarkerColor(); - addressColorCache.put(address, color); - return color; - } - } - return null; + private Color getBackgroundColor(Program program, MarkerSetCacheEntry entry, Address address) { + return entry.getBackgroundColor(address); } public GoToService getGoToService() { @@ -588,301 +418,6 @@ public class MarkerManager implements MarkerService { this.goToService = goToService; } - public void setNavigatable(Navigatable navigatable) { - this.navigatable = navigatable; - } - -//================================================================================================== -// Inner Classes -//================================================================================================== - - /** - * Marker Option Menu - controls the visibility of the various markers. - */ - class MarkerActionList implements OptionsChangeListener { - - private ArrayList 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() { - SystemUtilities.runSwingLater(() -> doRefresh()); - } - - private void doRefresh() { - if (tool == null || currentProgram == null) { - return; - } - - for (DockingAction action : actions) { - tool.removeAction(action); - } - actions.clear(); - - List list = new ArrayList<>(currentMarkerSets); - - // separate the marker sets into grouped and non-grouped - List> groupsList = extractManagerGroups(list); - Collections.sort(groupsList, - (ms1, ms2) -> ms1.get(0).getName().compareTo(ms2.get(0).getName())); - for (List 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> extractManagerGroups(List fromList) { - // empty the original list for grouping... - Map> nameToManagerMap = new HashMap<>(); - for (Iterator iterator = fromList.iterator(); iterator.hasNext();) { - MarkerSetImpl markerSetImpl = iterator.next(); - String name = markerSetImpl.getName(); - List 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> groupList = new ArrayList<>(fromList.size()); - Set>> entrySet = nameToManagerMap.entrySet(); - for (Entry> entry : entrySet) { - List 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 markerSets; - private NavigationPanel panel; - private Options options; - - ActivateMarkerGroupAction(String owner, List 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()); - } - } - - private class MyMarginProvider implements MarginProvider { - @Override - public JComponent getComponent() { - return markerPanel; - } - - @Override - public MarkerLocation getMarkerLocation(int x, int y) { - Address addr = getAddress(y); - if (addr == null) { - return null; - } - MarkerSet marker = getMarkerSet(addr); - return new MarkerLocation(marker, currentProgram, addr, x, y); - } - - @Override - public boolean isResizeable() { - return false; - } - - @Override - public void setPixelMap(VerticalPixelAddressMap pixmap) { - MarkerManager.this.pixmap = pixmap; - updateMarkerSets(true, false, true); - } - } - - private class MyOverviewProvider implements OverviewProvider { - - @Override - public JComponent getComponent() { - return navigationPanel; - } - - @Override - public void setAddressIndexMap(AddressIndexMap map) { - MarkerManager.this.addrMap = map; - updateMarkerSets(true, true, false); - } - - } - - /** - * A LRU map that maintains insertion-order iteration over the elements. As new items - * are added, the older items will be removed from this map the given plugin. - */ - static class AddressColorCache extends FixedSizeHashMap { - private final static int MAX_SIZE = 50; - - AddressColorCache() { - super(MAX_SIZE, MAX_SIZE); - } - } - @Override public void setMarkerClickedListener(MarkerClickedListener listener) { if (listener != null && markerClickedListener != null) { @@ -891,4 +426,185 @@ public class MarkerManager implements MarkerService { } markerClickedListener = listener; } + + public MarkerClickedListener getMarkerClickedListener() { + return markerClickedListener; + } + +//================================================================================================== +// Inner Classes +//================================================================================================== + + /** + * A LRU map that maintains insertion-order iteration over the elements. As new items are + * added, the older items will be removed from this map the given plugin. + */ + private static class AddressColorCache extends FixedSizeHashMap { + private final static int MAX_SIZE = 50; + + AddressColorCache() { + super(MAX_SIZE, MAX_SIZE); + } + } + + private class MarkerSetCache { + Map map = new HashMap<>(); + + MarkerSetCacheEntry get(Program program) { + if (program == null || program.isClosed()) { + return null; + } + MarkerSetCacheEntry entry = map.computeIfAbsent(program, this::newEntry); + if (program.isClosed()) { + map.remove(program); + return null; + } + return entry; + } + + public void clear() { + map.clear(); + } + + private MarkerSetCacheEntry newEntry(Program program) { + return new MarkerSetCacheEntry(this, program); + } + + private void programClosed(Program program) { + map.remove(program); + MarkerManager.this.programClosed(program); + } + } + + private static class MarkerSetCacheEntry { + private final List markerSets = new ArrayList<>(); + private final AddressColorCache colorCache = new AddressColorCache(); + + private final MarkerSetCache cache; + private final Program program; + private final DomainObjectClosedListener closeListener = this::programClosed; + + public MarkerSetCacheEntry(MarkerSetCache cache, Program program) { + this.cache = cache; + this.program = program; + /** + * Use this close listener approach instead of plugin events, since we don't get a + * ProgramClosedPluginEvent when a trace view is closed, but we can listen for its + * domain object closing, which works for plain programs, too. + */ + program.addCloseListener(closeListener); + } + + private void programClosed() { + program.removeCloseListener(closeListener); + cache.programClosed(program); + } + + MarkerSetImpl getByName(String name) { + for (MarkerSetImpl set : markerSets) { + if (name.equals(set.getName())) { + return set; + } + } + return null; + } + + void removeSet(MarkerSet set) { + markerSets.remove(set); + } + + void insertSet(MarkerSetImpl set) { + int index = Collections.binarySearch(markerSets, set); + if (index < 0) { + index = -(index + 1); + } + markerSets.add(index, set); + } + + ProgramLocation getProgramLocation(int y, int viewHeight, AddressIndexMap addrMap, int x) { + for (MarkerSetImpl markers : IterableUtils.reversedIterable(markerSets)) { + if (markers.isActive()) { + ProgramLocation loc = markers.getProgramLocation(y, viewHeight, addrMap, x); + if (loc != null) { + return loc; + } + } + } + return null; + } + + void paintNavigation(Graphics g, int viewHeight, int width, AddressIndexMap addrMap) { + for (MarkerSetImpl markers : markerSets) { + if (markers.active) { + markers.paintNavigation(g, viewHeight, width, addrMap); + } + } + } + + void paintMarkers(Graphics g, VerticalPixelAddressMap pixmap, AddressIndexMap addrMap) { + int count = 0; + for (MarkerSetImpl markers : markerSets) { + count++; + if (markers.active) { + markers.paintMarkers(g, count++, pixmap, addrMap); + } + } + } + + void updateView(boolean updateMakers, boolean updateNavigation) { + for (MarkerSetImpl markers : markerSets) { + markers.updateView(updateMakers, updateNavigation); + } + } + + MarkerSetImpl getMarkerSetAt(Address address) { + for (MarkerSetImpl markers : IterableUtils.reversedIterable(markerSets)) { + if (markers.displayInMarkerBar() && markers.contains(address)) { + return markers; + } + } + return null; + } + + Color getBackgroundColor(Address address) { + if (colorCache.containsKey(address)) { + return colorCache.get(address); + } + for (MarkerSetImpl markers : IterableUtils.reversedIterable(markerSets)) { + if (markers.isActive() && markers.isColoringBackground() && + markers.contains(address)) { + Color color = markers.getMarkerColor(); + colorCache.put(address, color); + return color; + } + } + return null; + } + + List getTooltipLines(int y, int x, Address minAddr, Address maxAddr) { + List lines = new ArrayList<>(); + for (MarkerSetImpl markers : IterableUtils.reversedIterable(markerSets)) { + if (!markers.displayInMarkerBar()) { + continue; + } + AddressSet set = markers.getAddressSet(); + AddressSet intersection = set.intersectRange(minAddr, maxAddr); + for (Address a : intersection.getAddresses(true)) { + lines.add(getMarkerToolTip(markers, a, x, y)); + if (markers instanceof AreaMarkerSet) { + break; // no more tooltips from this area + } + if (lines.size() >= MAX_TOOLTIP_LINES) { + lines.add("..."); + return lines; + } + } + } + return lines; + } + + List copyList() { + return new ArrayList<>(markerSets); + } + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerManagerPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerManagerPlugin.java index 1c33d09453..f47ec73f93 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerManagerPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerManagerPlugin.java @@ -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()); - } - } - } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerMarginProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerMarginProvider.java new file mode 100644 index 0000000000..bc32915f5d --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerMarginProvider.java @@ -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. + * + *

+ * 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); + } + +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerOverviewProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerOverviewProvider.java new file mode 100644 index 0000000000..5a42cd243d --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerOverviewProvider.java @@ -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. + * + *

+ * 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 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 list = markerManager.copyMarkerSets(program); + + // separate the marker sets into grouped and non-grouped + List> groupsList = extractManagerGroups(list); + Collections.sort(groupsList, + (ms1, ms2) -> ms1.get(0).getName().compareTo(ms2.get(0).getName())); + for (List 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> extractManagerGroups(List fromList) { + // empty the original list for grouping... + Map> nameToManagerMap = new HashMap<>(); + for (Iterator iterator = fromList.iterator(); iterator.hasNext();) { + MarkerSetImpl markerSetImpl = iterator.next(); + String name = markerSetImpl.getName(); + List 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> groupList = new ArrayList<>(fromList.size()); + Set>> entrySet = nameToManagerMap.entrySet(); + for (Entry> entry : entrySet) { + List 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 markerSets; + private NavigationPanel panel; + private Options options; + + ActivateMarkerGroupAction(String owner, List 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()); + } + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerPanel.java index 95af6d1ae5..7317d850ad 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerPanel.java @@ -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 lines) { + if (lines.isEmpty()) { + return null; + } + + StringBuilder buffy = new StringBuilder(""); + for (String string : lines) { + buffy.append(string).append("
"); + } + 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 lines = getMarkerTooltipLines(y, x, layoutIndex, layoutAddress); + return toHTML(lines); + } + + private List getMarkerTooltipLines(int y, int x, int layoutIndex, + Address layoutAddress) { + Address endAddr = pixmap.getLayoutEndAddress(layoutIndex); + return manager.getMarkerTooltipLines(program, y, layoutIndex, layoutAddress, endAddr); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerSetImpl.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerSetImpl.java index 1ead20b98b..1df241ba0f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerSetImpl.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/MarkerSetImpl.java @@ -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 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; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/NavigationPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/NavigationPanel.java index c0ba31881d..f07e0ac1ef 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/NavigationPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/NavigationPanel.java @@ -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; + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/PointMarkerSet.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/PointMarkerSet.java index 86153326c7..c8cbc2c4bb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/PointMarkerSet.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/marker/PointMarkerSet.java @@ -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) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/OverviewColorComponent.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/OverviewColorComponent.java index 2130af99e8..e6add5294e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/OverviewColorComponent.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/overview/OverviewColorComponent.java @@ -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 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() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/services/MarkerService.java b/Ghidra/Features/Base/src/main/java/ghidra/app/services/MarkerService.java index b330e76524..3a4bc250e8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/services/MarkerService.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/services/MarkerService.java @@ -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; /** *

- * 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. *

*

@@ -39,16 +39,18 @@ import ghidra.program.model.listing.Program; *

* Recommended Usage
* Recommended Usage
- * 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(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingCodeComparisonPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingCodeComparisonPanel.java index 73e8af14d3..5192bf79ec 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingCodeComparisonPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingCodeComparisonPanel.java @@ -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 byteAddress as well - * as the address and desiredAddress that were matched. + * Infers a desired byte address based on the specified byteAddress as well as the + * address and desiredAddress that were matched. + * * @param address matches up with the desiredAddress from the other function/data. * @param desiredAddress matches up with the address from the other function/data. * @param byteAddress the byte address that is associated with address * @param program the program for the address and byteAddress. - * @param desiredProgram the program for the desiredAddress and - * desiredByteAddress. + * @param desiredProgram the program for the desiredAddress and + * desiredByteAddress. * @return the desired byte address that matches up with the indicated byteAddress - * 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 - * codeUnitAddress and desiredCodeUnitAddress. - * The inferred address will be at an offset from the desiredCodeUnitAddress - * that is the same distance the byteAddress is from the codeUnitAddress. + * This infers the desired byte address within Data based on the code units at + * codeUnitAddress and desiredCodeUnitAddress. The inferred address + * will be at an offset from the desiredCodeUnitAddress that is the same distance + * the byteAddress is from the codeUnitAddress. * - * @param codeUnitAddress matches up with the desiredCodeUnitAddress from - * the other data. - * @param desiredCodeUnitAddress matches up with the codeUnitAddress from - * the other data. + * @param codeUnitAddress matches up with the desiredCodeUnitAddress from the other + * data. + * @param desiredCodeUnitAddress matches up with the codeUnitAddress from the other + * data. * @param byteAddress the byte address that is associated with codeUnitAddress * @param program the program for the codeUnitAddress and byteAddress. - * @param desiredProgram the program for the desiredCodeUnitAddress and - * desiredByteAddress. - * @return the desired byte address within the data that matches up with the indicated - * byteAddress or null if it can't be determined. + * @param desiredProgram the program for the desiredCodeUnitAddress and + * desiredByteAddress. + * @return the desired byte address within the data that matches up with the indicated + * byteAddress 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 - * address and desiredAddress. - * 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 desiredAddress. + * This infers the desired byte address within a function based on the code units at + * address and desiredAddress. 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 + * desiredAddress. * * @param address matches up with the desiredAddress from the other function. * @param desiredAddress matches up with the address from the other function. * @param byteAddress the byte address that is associated with address * @param program the program for the address and byteAddress. - * @param desiredProgram the program for the desiredAddress and - * desiredByteAddress. - * @return the desired byte address within the data that matches up with the indicated - * byteAddress or null if it can't be determined. + * @param desiredProgram the program for the desiredAddress and + * desiredByteAddress. + * @return the desired byte address within the data that matches up with the indicated + * byteAddress 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 leftOrRight that matches the + * Gets an address in the program indicated by leftOrRight that matches the * otherSidesAddress 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 */ diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingPanel.java index 0d54661b21..0602307088 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingPanel.java @@ -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 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() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/MarginProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/MarginProvider.java index 9cc3954d15..f60dad64eb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/MarginProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/MarginProvider.java @@ -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. */ diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/OverviewProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/OverviewProvider.java index 7aed0f952d..a885e7dadf 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/OverviewProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/OverviewProvider.java @@ -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); } diff --git a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java index c640013eab..1afe027395 100644 --- a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java +++ b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java @@ -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 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. - *
Note: 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.
+ * Note: 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,