GP-3648 - Add Function Graph to Function Comparison display

This commit is contained in:
dragonmacher 2025-08-18 17:14:26 -04:00
parent 6773801f6e
commit 3c90216365
116 changed files with 4228 additions and 1350 deletions

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -29,7 +29,7 @@ import ghidra.feature.vt.api.main.*;
import ghidra.feature.vt.api.markuptype.VTMarkupType;
import ghidra.feature.vt.gui.plugin.VTController;
import ghidra.feature.vt.gui.task.ApplyMarkupAtDestinationAddressTask;
import ghidra.features.base.codecompare.listing.ListingCodeComparisonPanel;
import ghidra.features.base.codecompare.listing.ListingCodeComparisonView;
import ghidra.program.model.address.Address;
import ghidra.program.util.ProgramLocation;
import ghidra.util.Msg;
@ -41,7 +41,7 @@ public class VTDualListingDragNDropHandler implements Draggable, Droppable {
private Duo<ListingPanel> listingPanels;
private VTController controller;
ListingCodeComparisonPanel dualListingPanel;
ListingCodeComparisonView dualListingProvider;
// Drag-N-Drop
private DragSource dragSource;
@ -53,11 +53,11 @@ public class VTDualListingDragNDropHandler implements Draggable, Droppable {
private DataFlavor[] acceptableFlavors; // data flavors that are valid.
public VTDualListingDragNDropHandler(VTController controller,
ListingCodeComparisonPanel dualListingPanel) {
ListingCodeComparisonView dualListingProvider) {
this.controller = controller;
this.dualListingPanel = dualListingPanel;
ListingPanel leftPanel = dualListingPanel.getListingPanel(LEFT);
ListingPanel rightPanel = dualListingPanel.getListingPanel(RIGHT);
this.dualListingProvider = dualListingProvider;
ListingPanel leftPanel = dualListingProvider.getListingPanel(LEFT);
ListingPanel rightPanel = dualListingProvider.getListingPanel(RIGHT);
listingPanels = new Duo<>(leftPanel, rightPanel);
setUpDragDrop();
}
@ -109,7 +109,7 @@ public class VTDualListingDragNDropHandler implements Draggable, Droppable {
ProgramLocation programLocation = listingPanels.get(LEFT).getProgramLocation(p);
VTMarkupItem markupItem =
controller.getCurrentMarkupForLocation(programLocation,
dualListingPanel.getProgram(LEFT));
dualListingProvider.getProgram(LEFT));
if (markupItem == null) {
return false;
}
@ -131,7 +131,7 @@ public class VTDualListingDragNDropHandler implements Draggable, Droppable {
ProgramLocation programLocation = listingPanels.get(LEFT).getProgramLocation(p);
VTMarkupItem markupItem = controller.getCurrentMarkupForLocation(programLocation,
dualListingPanel.getProgram(LEFT));
dualListingProvider.getProgram(LEFT));
if (markupItem == null) {
return null;
}
@ -151,16 +151,16 @@ public class VTDualListingDragNDropHandler implements Draggable, Droppable {
ProgramLocation loc = listingPanels.get(RIGHT).getProgramLocation(p);
Address newDestinationAddress =
markupType.getAddress(loc, dualListingPanel.getProgram(RIGHT));
markupType.getAddress(loc, dualListingProvider.getProgram(RIGHT));
if (newDestinationAddress == null) {
Msg.showInfo(getClass(), dualListingPanel, "Invalid Drop Location",
Msg.showInfo(getClass(), dualListingProvider, "Invalid Drop Location",
markupType.getDisplayName() + " was not dropped at a valid location.");
return;
}
if ((markupItem.getStatus() == VTMarkupItemStatus.SAME) &&
(SystemUtilities.isEqual(markupItem.getDestinationAddress(), newDestinationAddress))) {
// Dropped at expected address and already the same there.
Msg.showInfo(getClass(), dualListingPanel, "Already The Same", markupType
Msg.showInfo(getClass(), dualListingProvider, "Already The Same", markupType
.getDisplayName() +
" was dropped at its expected\ndestination where the value is already the same.");
return;

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -18,16 +18,16 @@ package ghidra.feature.vt.gui.duallisting;
import docking.ComponentProvider;
import ghidra.app.context.ListingActionContext;
import ghidra.app.nav.Navigatable;
import ghidra.features.base.codecompare.panel.CodeComparisonPanel;
import ghidra.features.base.codecompare.panel.CodeComparisonPanelActionContext;
import ghidra.features.base.codecompare.panel.CodeComparisonView;
import ghidra.features.base.codecompare.panel.CodeComparisonViewActionContext;
/**
* Action context for a version tracking listing.
*/
public class VTListingContext extends ListingActionContext
implements CodeComparisonPanelActionContext {
implements CodeComparisonViewActionContext {
private CodeComparisonPanel codeComparisonPanel = null;
private CodeComparisonView codeComparisonView = null;
/**
* Creates an action context for a VT listing.
@ -40,15 +40,14 @@ public class VTListingContext extends ListingActionContext
/**
* Sets the CodeComparisonPanel associated with this context.
* @param codeComparisonPanel the code comparison panel.
* @param codeComparisonView the code comparison panel.
*/
public void setCodeComparisonPanel(
CodeComparisonPanel codeComparisonPanel) {
this.codeComparisonPanel = codeComparisonPanel;
public void setCodeComparisonPanel(CodeComparisonView codeComparisonView) {
this.codeComparisonView = codeComparisonView;
}
@Override
public CodeComparisonPanel getCodeComparisonPanel() {
return codeComparisonPanel;
public CodeComparisonView getCodeComparisonView() {
return codeComparisonView;
}
}

View file

@ -20,7 +20,6 @@ import javax.swing.Icon;
import ghidra.app.nav.*;
import ghidra.app.util.ListingHighlightProvider;
import ghidra.app.util.viewer.listingpanel.ListingPanel;
import ghidra.features.base.codecompare.listing.ListingCodeComparisonPanel;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
@ -28,14 +27,11 @@ import ghidra.util.UniversalIdGenerator;
public class VTListingNavigator implements Navigatable {
private final ListingCodeComparisonPanel dualListingPanel;
private final ListingPanel listingPanel;
private long id;
public VTListingNavigator(ListingCodeComparisonPanel dualListingPanel,
ListingPanel listingPanel) {
public VTListingNavigator(ListingPanel listingPanel) {
this.dualListingPanel = dualListingPanel;
this.listingPanel = listingPanel;
id = UniversalIdGenerator.nextID().getValue();
}

View file

@ -87,9 +87,9 @@ public class VTPlugin extends Plugin {
private VTController controller;
// common resources
// destination-side resources
// plugins we have to add to our tool manually
private Set<String> additionalPluginNames = new HashSet<>(Set.of(
"ghidra.features.codecompare.plugin.FunctionComparisonPlugin"));
private VTMatchTableProvider matchesProvider;
private VTMarkupItemsTableProvider markupProvider;
@ -99,16 +99,15 @@ public class VTPlugin extends Plugin {
public VTPlugin(PluginTool tool) {
super(tool);
tool.setUnconfigurable();
OWNER = getName();
controller = new VTControllerImpl(this);
matchesProvider = new VTMatchTableProvider(controller);
markupProvider = new VTMarkupItemsTableProvider(controller);
impliedMatchesTable = new VTImpliedMatchesTableProvider(controller);
functionAssociationProvider = new VTFunctionAssociationProvider(controller);
registerServiceProvided(VTController.class, controller);
toolManager = new VTSubToolManager(this);
createActions();
registerServiceProvided(VTController.class, controller);
tool.setUnconfigurable();
DockingActionIf saveAs = getToolAction("Save Tool As");
tool.removeAction(saveAs);
@ -116,11 +115,7 @@ public class VTPlugin extends Plugin {
DockingActionIf export = getToolAction("Export Tool");
tool.removeAction(export);
new MatchStatusUpdaterAssociationHook(controller);
new ImpliedMatchAssociationHook(controller);
initializeOptions();
}
private DockingActionIf getToolAction(String actionName) {
@ -145,9 +140,16 @@ public class VTPlugin extends Plugin {
protected void init() {
removeUnwantedPlugins();
addCustomPlugins();
matchesProvider = new VTMatchTableProvider(controller);
markupProvider = new VTMarkupItemsTableProvider(controller);
impliedMatchesTable = new VTImpliedMatchesTableProvider(controller);
functionAssociationProvider = new VTFunctionAssociationProvider(controller);
new MatchStatusUpdaterAssociationHook(controller);
new ImpliedMatchAssociationHook(controller);
maybeShowHelp();
}
@ -161,11 +163,11 @@ public class VTPlugin extends Plugin {
private void addCustomPlugins() {
List<String> names =
new ArrayList<>(List.of("ghidra.features.codecompare.plugin.FunctionComparisonPlugin"));
List<Plugin> plugins = tool.getManagedPlugins();
Set<String> existingNames =
plugins.stream().map(c -> c.getName()).collect(Collectors.toSet());
Set<String> existingNames = new HashSet<>(
plugins.stream()
.map(c -> c.getName())
.collect(Collectors.toSet()));
// Note: we check to see if the plugins we want to add have already been added to the tool.
// We should not need to do this, but once the tool has been saved with the plugins added,
@ -173,7 +175,7 @@ public class VTPlugin extends Plugin {
// easier than modifying the default to file to load the plugins, since the amount of xml
// required for that is non-trivial.
try {
for (String className : names) {
for (String className : additionalPluginNames) {
if (!existingNames.contains(className)) {
tool.addPlugin(className);
}

View file

@ -39,6 +39,7 @@ import docking.widgets.label.GDLabel;
import docking.widgets.table.threaded.ThreadedTableModel;
import generic.theme.GIcon;
import generic.theme.GThemeDefaults.Colors;
import ghidra.app.services.FunctionComparisonService;
import ghidra.app.util.viewer.listingpanel.ListingPanel;
import ghidra.feature.vt.api.db.DeletedMatch;
import ghidra.feature.vt.api.impl.VTEvent;
@ -48,7 +49,7 @@ import ghidra.feature.vt.gui.actions.*;
import ghidra.feature.vt.gui.duallisting.VTListingNavigator;
import ghidra.feature.vt.gui.plugin.*;
import ghidra.feature.vt.gui.util.MatchInfo;
import ghidra.features.base.codecompare.listing.ListingCodeComparisonPanel;
import ghidra.features.base.codecompare.listing.ListingCodeComparisonView;
import ghidra.features.base.codecompare.panel.FunctionComparisonPanel;
import ghidra.framework.model.*;
import ghidra.framework.options.Options;
@ -218,10 +219,10 @@ public class VTFunctionAssociationProvider extends ComponentProviderAdapter
@Override
public List<DockingActionIf> getPopupActions(Tool t, ActionContext context) {
if (context.getComponentProvider() == this) {
ListingCodeComparisonPanel dualListingPanel =
functionComparisonPanel.getDualListingPanel();
if (dualListingPanel != null) {
ListingPanel leftPanel = dualListingPanel.getListingPanel(LEFT);
ListingCodeComparisonView dualListingProvider =
functionComparisonPanel.getDualListingView();
if (dualListingProvider != null) {
ListingPanel leftPanel = dualListingProvider.getListingPanel(LEFT);
return leftPanel.getHeaderActions(getOwner());
}
}
@ -247,22 +248,22 @@ public class VTFunctionAssociationProvider extends ComponentProviderAdapter
// Tool bar or function compare panel.
if (isToolbarButtonAction || functionComparisonPanel.isAncestorOf(sourceComponent)) {
ListingCodeComparisonPanel dualListingPanel =
functionComparisonPanel.getDualListingPanel();
ListingCodeComparisonView dualListingProvider =
functionComparisonPanel.getDualListingView();
boolean isShowingDualListing =
(dualListingPanel != null) && dualListingPanel.isVisible();
(dualListingProvider != null) && dualListingProvider.isVisible();
boolean sourceIsADualFieldPanel =
isShowingDualListing && dualListingPanel.isAncestorOf(sourceComponent) &&
isShowingDualListing && dualListingProvider.isAncestorOf(sourceComponent) &&
(sourceComponent instanceof FieldPanel);
ListingPanel listingPanel = null; // Default is don't create a function association listing context.
// Is the action being taken on the dual listing?
if (sourceIsADualFieldPanel) {
listingPanel = dualListingPanel.getListingPanel((FieldPanel) sourceComponent);
listingPanel = dualListingProvider.getListingPanel((FieldPanel) sourceComponent);
}
// Is the action being taken on a toolbar button while the dual listing is visible?
else if (isToolbarButtonAction && isShowingDualListing) {
listingPanel = dualListingPanel.getActiveListingPanel();
listingPanel = dualListingProvider.getActiveListingPanel();
}
// If the dual listing is showing and this is a toolbar action or the action is
// on one of the listings in the ListingCodeComparisonPanel
@ -270,14 +271,13 @@ public class VTFunctionAssociationProvider extends ComponentProviderAdapter
// popup actions for the ListingDiff and also the function association actions
// for the functions selected in the tables.
if (listingPanel != null) {
VTListingNavigator vtListingNavigator =
new VTListingNavigator(dualListingPanel, listingPanel);
VTListingNavigator vtListingNavigator = new VTListingNavigator(listingPanel);
VTFunctionAssociationCompareContext vtListingContext =
new VTFunctionAssociationCompareContext(this, vtListingNavigator, tool,
sourceFunction, destinationFunction,
getExistingMatch(sourceFunction, destinationFunction));
vtListingContext.setCodeComparisonPanel(dualListingPanel);
vtListingContext.setContextObject(dualListingPanel);
vtListingContext.setCodeComparisonPanel(dualListingProvider);
vtListingContext.setContextObject(dualListingProvider);
vtListingContext.setSourceObject(source);
return vtListingContext;
}
@ -334,6 +334,8 @@ public class VTFunctionAssociationProvider extends ComponentProviderAdapter
destinationFunctionsTable.dispose();
destinationTableFilterPanel.dispose();
functionComparisonPanel.dispose();
tool.removePopupActionProvider(this);
}
@ -368,9 +370,12 @@ public class VTFunctionAssociationProvider extends ComponentProviderAdapter
statusPanel.add(statusLabel, BorderLayout.CENTER);
dualTablePanel.add(statusPanel, BorderLayout.SOUTH);
functionComparisonPanel = new FunctionComparisonPanel(tool, getOwner());
// Note: this service should never be null, since it is added by the VTPlugin
FunctionComparisonService fcService = tool.getService(FunctionComparisonService.class);
functionComparisonPanel = fcService.createComparisonViewer();
addSpecificCodeComparisonActions();
functionComparisonPanel.setCurrentTabbedComponent(ListingCodeComparisonPanel.NAME);
functionComparisonPanel.setCurrentTabbedComponent(ListingCodeComparisonView.NAME);
functionComparisonPanel.setTitlePrefixes("Source:", "Destination:");
comparisonSplitPane =
@ -760,12 +765,9 @@ public class VTFunctionAssociationProvider extends ComponentProviderAdapter
sourceFunctionsModel.setFilterSettings(filterSettings);
destinationFunctionsModel.setFilterSettings(filterSettings);
reload();
functionComparisonPanel.readConfigState(getName(), saveState);
}
public void writeConfigState(SaveState saveState) {
// save config state here
functionComparisonPanel.writeConfigState(getName(), saveState);
saveState.putEnum(FILTER_SETTINGS_KEY, filterSettings);
}

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -19,17 +19,17 @@ import java.util.List;
import docking.DefaultActionContext;
import ghidra.feature.vt.api.main.VTMarkupItem;
import ghidra.features.base.codecompare.panel.CodeComparisonPanel;
import ghidra.features.base.codecompare.panel.CodeComparisonPanelActionContext;
import ghidra.features.base.codecompare.panel.CodeComparisonView;
import ghidra.features.base.codecompare.panel.CodeComparisonViewActionContext;
/**
* Action context for the version tracking markup item provider.
*/
public class VTMarkupItemContext extends DefaultActionContext
implements CodeComparisonPanelActionContext {
implements CodeComparisonViewActionContext {
private final List<VTMarkupItem> selectedItems;
private CodeComparisonPanel codeComparisonPanel = null;
private CodeComparisonView codeComparisonView;
/**
* Creates an action context for the VT markup item provider.
@ -50,16 +50,15 @@ public class VTMarkupItemContext extends DefaultActionContext
}
/**
* Sets the CodeComparisonPanel associated with this context.
* @param codeComparisonPanel the code comparison panel.
* Sets the comparison provider associated with this context.
* @param codeComparisonView the code comparison view.
*/
public void setCodeComparisonPanel(
CodeComparisonPanel codeComparisonPanel) {
this.codeComparisonPanel = codeComparisonPanel;
public void setCodeComparisonView(CodeComparisonView codeComparisonView) {
this.codeComparisonView = codeComparisonView;
}
@Override
public CodeComparisonPanel getCodeComparisonPanel() {
return codeComparisonPanel;
public CodeComparisonView getCodeComparisonView() {
return codeComparisonView;
}
}

View file

@ -39,6 +39,7 @@ import docking.widgets.table.GTable;
import docking.widgets.table.RowObjectTableModel;
import docking.widgets.table.threaded.ThreadedTableModel;
import generic.theme.GIcon;
import ghidra.app.services.FunctionComparisonService;
import ghidra.app.util.viewer.listingpanel.ListingPanel;
import ghidra.app.util.viewer.listingpanel.ProgramLocationListener;
import ghidra.feature.vt.api.main.*;
@ -51,8 +52,8 @@ import ghidra.feature.vt.gui.filters.Filter.FilterEditingStatus;
import ghidra.feature.vt.gui.plugin.*;
import ghidra.feature.vt.gui.provider.markuptable.VTMarkupItemsTableModel.AppliedDestinationAddressTableColumn;
import ghidra.feature.vt.gui.util.*;
import ghidra.features.base.codecompare.listing.ListingCodeComparisonPanel;
import ghidra.features.base.codecompare.panel.CodeComparisonPanel;
import ghidra.features.base.codecompare.listing.ListingCodeComparisonView;
import ghidra.features.base.codecompare.panel.CodeComparisonView;
import ghidra.features.base.codecompare.panel.FunctionComparisonPanel;
import ghidra.framework.model.DomainObjectChangedEvent;
import ghidra.framework.options.Options;
@ -154,28 +155,33 @@ public class VTMarkupItemsTableProvider extends ComponentProviderAdapter
markupItemsTablePanel.add(tablePanel, BorderLayout.CENTER);
markupItemsTablePanel.add(filterAreaPanel, BorderLayout.SOUTH);
functionComparisonPanel = new FunctionComparisonPanel(tool, getOwner());
// Note: this service should never be null, since it is added by the VTPlugin
FunctionComparisonService fcService = tool.getService(FunctionComparisonService.class);
functionComparisonPanel = fcService.createComparisonViewer();
addSpecificCodeComparisonActions();
functionComparisonPanel.setCurrentTabbedComponent(ListingCodeComparisonPanel.NAME);
functionComparisonPanel.setCurrentTabbedComponent(ListingCodeComparisonView.NAME);
functionComparisonPanel.getAccessibleContext().setAccessibleName("Function Comparison");
functionComparisonPanel.setTitlePrefixes("Source:", "Destination:");
ListingCodeComparisonPanel dualListingPanel = functionComparisonPanel.getDualListingPanel();
if (dualListingPanel != null) {
ListingCodeComparisonView dualListingProvider =
functionComparisonPanel.getDualListingView();
if (dualListingProvider != null) {
dualListingPanel.getListingPanel(LEFT)
dualListingProvider.getListingPanel(LEFT)
.setProgramLocationListener(new SourceProgramLocationListener());
dualListingPanel.getListingPanel(RIGHT)
dualListingProvider.getListingPanel(RIGHT)
.setProgramLocationListener(
new DestinationProgramLocationListener());
sourceHighlightProvider = new VTDualListingHighlightProvider(controller, true);
destinationHighlightProvider = new VTDualListingHighlightProvider(controller, false);
dualListingPanel.addHighlightProviders(sourceHighlightProvider,
dualListingProvider.addHighlightProviders(sourceHighlightProvider,
destinationHighlightProvider);
sourceHighlightProvider.setListingPanel(dualListingPanel.getListingPanel(LEFT));
destinationHighlightProvider.setListingPanel(dualListingPanel.getListingPanel(RIGHT));
sourceHighlightProvider.setListingPanel(dualListingProvider.getListingPanel(LEFT));
destinationHighlightProvider
.setListingPanel(dualListingProvider.getListingPanel(RIGHT));
new VTDualListingDragNDropHandler(controller, dualListingPanel);
new VTDualListingDragNDropHandler(controller, dualListingProvider);
}
splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, markupItemsTablePanel,
@ -250,8 +256,8 @@ public class VTMarkupItemsTableProvider extends ComponentProviderAdapter
// the same destination address.
processingMarkupItemSelected = true;
ListingCodeComparisonPanel dualListingPanel =
functionComparisonPanel.getDualListingPanel();
ListingCodeComparisonView dualListingPanel =
functionComparisonPanel.getDualListingView();
VTMarkupItem markupItem = null;
if (table.getSelectedRowCount() == 1) {
// we get out the model here in case it has been wrapped by one of the filters
@ -358,7 +364,8 @@ public class VTMarkupItemsTableProvider extends ComponentProviderAdapter
* Otherwise, hide it.
*/
private void showComparisonPanelWithinProvider(boolean show) {
ListingCodeComparisonPanel dualListingPanel = functionComparisonPanel.getDualListingPanel();
ListingCodeComparisonView dualListingProvider =
functionComparisonPanel.getDualListingView();
boolean contains = markupPanel.isAncestorOf(splitPane);
if (show) {
if (!contains) {
@ -369,10 +376,10 @@ public class VTMarkupItemsTableProvider extends ComponentProviderAdapter
splitPane.add(markupItemsTablePanel);
splitPane.add(functionComparisonPanel);
markupPanel.add(splitPane, BorderLayout.CENTER);
if (dualListingPanel != null) {
dualListingPanel.getListingPanel(LEFT)
if (dualListingProvider != null) {
dualListingProvider.getListingPanel(LEFT)
.setProgramLocationListener(new SourceProgramLocationListener());
dualListingPanel.getListingPanel(LEFT)
dualListingProvider.getListingPanel(LEFT)
.setProgramLocationListener(new DestinationProgramLocationListener());
}
@ -386,9 +393,9 @@ public class VTMarkupItemsTableProvider extends ComponentProviderAdapter
else {
if (contains) {
// Remove the split pane.
if (dualListingPanel != null) {
dualListingPanel.getListingPanel(LEFT).setProgramLocationListener(null);
dualListingPanel.getListingPanel(RIGHT).setProgramLocationListener(null);
if (dualListingProvider != null) {
dualListingProvider.getListingPanel(LEFT).setProgramLocationListener(null);
dualListingProvider.getListingPanel(RIGHT).setProgramLocationListener(null);
}
markupPanel.remove(splitPane);
splitPane.remove(functionComparisonPanel);
@ -471,9 +478,10 @@ public class VTMarkupItemsTableProvider extends ComponentProviderAdapter
@Override
public List<DockingActionIf> getPopupActions(Tool t, ActionContext context) {
ListingCodeComparisonPanel dualListingPanel = functionComparisonPanel.getDualListingPanel();
if (context.getComponentProvider() == this && dualListingPanel != null) {
ListingPanel sourcePanel = dualListingPanel.getListingPanel(LEFT);
ListingCodeComparisonView dualListingProvider =
functionComparisonPanel.getDualListingView();
if (context.getComponentProvider() == this && dualListingProvider != null) {
ListingPanel sourcePanel = dualListingProvider.getListingPanel(LEFT);
return sourcePanel.getHeaderActions(getOwner());
}
return new ArrayList<>();
@ -483,34 +491,35 @@ public class VTMarkupItemsTableProvider extends ComponentProviderAdapter
public ActionContext getActionContext(MouseEvent event) {
Object source = (event != null) ? event.getSource() : null;
Component sourceComponent = (source instanceof Component) ? (Component) source : null;
// If action is on the markup table, return a markup item context for markup popup actions.
if (event == null || tablePanel.isAncestorOf(sourceComponent)) {
List<VTMarkupItem> selectedItems = getSelectedMarkupItems();
VTMarkupItemContext vtMarkupItemContext = new VTMarkupItemContext(this, selectedItems);
if (functionComparisonPanel.isVisible()) {
CodeComparisonPanel displayedPanel =
functionComparisonPanel.getDisplayedPanel();
vtMarkupItemContext.setCodeComparisonPanel(displayedPanel);
CodeComparisonView displayedProvider =
functionComparisonPanel.getDisplayedView();
vtMarkupItemContext.setCodeComparisonView(displayedProvider);
}
return vtMarkupItemContext;
}
// Is the action being taken on the dual listing.
ListingCodeComparisonPanel dualListingPanel = functionComparisonPanel.getDualListingPanel();
if (dualListingPanel != null && dualListingPanel.isAncestorOf(sourceComponent)) {
// If the action is on one of the listings in the ListingCodeComparisonPanel
ListingCodeComparisonView listingView = functionComparisonPanel.getDualListingView();
if (listingView != null && listingView.isAncestorOf(sourceComponent)) {
// If the action is on one of the listings in the Listing view
// then return a special version tracking listing context. This will allow
// popup actions for the ListingDiff and also the markup item actions for the
// current markup item.
if (sourceComponent instanceof FieldPanel) {
ListingPanel listingPanel =
dualListingPanel.getListingPanel((FieldPanel) sourceComponent);
listingView.getListingPanel((FieldPanel) sourceComponent);
if (listingPanel != null) {
VTListingNavigator vtListingNavigator =
new VTListingNavigator(dualListingPanel, listingPanel);
VTListingNavigator vtListingNavigator = new VTListingNavigator(listingPanel);
VTListingContext vtListingContext =
new VTListingContext(this, vtListingNavigator);
vtListingContext.setCodeComparisonPanel(dualListingPanel);
vtListingContext.setContextObject(dualListingPanel);
vtListingContext.setCodeComparisonPanel(listingView);
vtListingContext.setContextObject(listingView);
vtListingContext.setSourceObject(source);
return vtListingContext;
}
@ -542,6 +551,8 @@ public class VTMarkupItemsTableProvider extends ComponentProviderAdapter
return;
}
functionComparisonPanel.dispose();
// must remove the listener first to avoid callback whilst we are disposing
ListSelectionModel selectionModel = markupItemsTable.getSelectionModel();
selectionModel.removeListSelectionListener(markupItemSelectionListener);
@ -564,9 +575,10 @@ public class VTMarkupItemsTableProvider extends ComponentProviderAdapter
private void refresh() {
markupItemsTableModel.reload(false);
markupItemsTable.repaint();
ListingCodeComparisonPanel dualListingPanel = functionComparisonPanel.getDualListingPanel();
if (dualListingPanel != null) {
dualListingPanel.updateListings();
ListingCodeComparisonView dualListingProvider =
functionComparisonPanel.getDualListingView();
if (dualListingProvider != null) {
dualListingProvider.updateListings();
}
sourceHighlightProvider.updateMarkup();
destinationHighlightProvider.updateMarkup();
@ -773,11 +785,12 @@ public class VTMarkupItemsTableProvider extends ComponentProviderAdapter
* @return true if the dual listing is showing
*/
public boolean isDualListingShowing() {
ListingCodeComparisonPanel dualListingPanel = functionComparisonPanel.getDualListingPanel();
if (dualListingPanel == null) {
ListingCodeComparisonView dualListingProvider =
functionComparisonPanel.getDualListingView();
if (dualListingProvider == null) {
return false;
}
return dualListingPanel.isShowing();
return dualListingProvider.isShowing();
}
@Override
@ -836,7 +849,6 @@ public class VTMarkupItemsTableProvider extends ComponentProviderAdapter
* @param saveState the configuration state to restore
*/
public void readConfigState(SaveState saveState) {
functionComparisonPanel.readConfigState(getName(), saveState);
showComparisonPanelWithinProvider(saveState.getBoolean(SHOW_COMPARISON_PANEL, true));
for (Filter<VTMarkupItem> filter : filters) {
@ -881,8 +893,6 @@ public class VTMarkupItemsTableProvider extends ComponentProviderAdapter
* @param saveState the new configuration state
*/
public void writeConfigState(SaveState saveState) {
// save config state here
functionComparisonPanel.writeConfigState(getName(), saveState);
saveState.putBoolean(SHOW_COMPARISON_PANEL, functionComparisonPanel.isShowing());
for (Filter<VTMarkupItem> filter : filters) {
@ -947,6 +957,15 @@ public class VTMarkupItemsTableProvider extends ComponentProviderAdapter
refilter(); // this will do nothing if we are frozen
}
/**
* Gets the function comparison panel component that possibly contains multiple different views
* for comparing code such as a dual listing.
* @return the function comparison panel
*/
public FunctionComparisonPanel getFunctionComparisonPanel() {
return functionComparisonPanel;
}
//==================================================================================================
// Inner Classes
//==================================================================================================
@ -1010,13 +1029,4 @@ public class VTMarkupItemsTableProvider extends ComponentProviderAdapter
}
}
}
/**
* Gets the function comparison panel component that possibly contains multiple different views
* for comparing code such as a dual listing.
* @return the function comparison panel
*/
public FunctionComparisonPanel getFunctionComparisonPanel() {
return functionComparisonPanel;
}
}

View file

@ -52,7 +52,7 @@ import ghidra.feature.vt.gui.provider.onetomany.VTMatchSourceTableProvider;
import ghidra.feature.vt.gui.task.*;
import ghidra.feature.vt.gui.util.MatchInfo;
import ghidra.feature.vt.gui.wizard.add.*;
import ghidra.features.base.codecompare.listing.ListingCodeComparisonPanel;
import ghidra.features.base.codecompare.listing.ListingCodeComparisonView;
import ghidra.framework.main.DataTreeDialog;
import ghidra.framework.main.datatree.DataTree;
import ghidra.framework.main.datatree.ProjectDataTreePanel;
@ -765,7 +765,7 @@ public class VersionTrackingPluginScreenShots extends GhidraScreenShotGenerator
JComponent component = provider.getComponent();
Component listingComponent =
findComponentByName(component, ListingCodeComparisonPanel.NAME);
findComponentByName(component, ListingCodeComparisonView.NAME);
if (listingComponent == null) {
return false; // not in the parent's hierarchy
}

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -193,7 +193,7 @@ public class VTImpliedMatchCorrelatorTest extends AbstractVTCorrelatorTest {
// get the resulting implied matches and verify that none of the matches that were already
// created
VTMatchSet impliedMatchSet = getVTMatchSet("Implied Match");
Assert.assertNotEquals("vtMatchSet does not exist", null, impliedMatchSet);
assertNotNull(impliedMatchSet);
// Now test that only the expected items are in this set for the given function we just
// applied
@ -276,9 +276,7 @@ public class VTImpliedMatchCorrelatorTest extends AbstractVTCorrelatorTest {
protected VTMatch getMatch(VTMatchSet matches, Address sourceAddress,
Address destinationAddress) {
Iterator<VTMatch> it = matches.getMatches().iterator();
while (it.hasNext()) {
VTMatch match = it.next();
for (VTMatch match : matches.getMatches()) {
if (match.getSourceAddress().equals(sourceAddress) &&
match.getDestinationAddress().equals(destinationAddress)) {
return match;

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -33,9 +33,9 @@ import ghidra.feature.vt.api.db.VTSessionDB;
import ghidra.feature.vt.api.main.*;
import ghidra.feature.vt.api.util.VTOptions;
import ghidra.feature.vt.gui.plugin.*;
import ghidra.feature.vt.gui.provider.markuptable.VTMarkupItemsTableProvider;
import ghidra.feature.vt.gui.provider.matchtable.VTMatchTableModel;
import ghidra.feature.vt.gui.provider.matchtable.VTMatchTableProvider;
import ghidra.framework.plugintool.Plugin;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.listing.Program;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
@ -56,9 +56,10 @@ public class VTTestEnv extends TestEnv {
public VTTestEnv() throws Exception {
PluginTool tool = getTool();
tool.removePlugins(new Plugin[] { getPlugin(ProgramManagerPlugin.class) });
tool.addPlugin(VTPlugin.class.getName());
PluginTool pluignTool = getTool();
pluignTool.removePlugins(List.of(getPlugin(ProgramManagerPlugin.class)));
pluignTool.addPlugin(VTPlugin.class.getName());
plugin = getPlugin(VTPlugin.class);
controller = (VTController) getInstanceField("controller", plugin);
matchTableProvider = (VTMatchTableProvider) getInstanceField("matchesProvider", plugin);
@ -238,7 +239,19 @@ public class VTTestEnv extends TestEnv {
}
public void focusMatchTable() {
runSwing(() -> matchTableProvider.getComponent().requestFocus());
runSwing(() -> matchTableProvider.requestFocus());
}
public VTMarkupItemsTableProvider getMarkupItemsProvider() {
return (VTMarkupItemsTableProvider) getInstanceField("markupProvider", plugin);
}
public void focusMarkupItemsTable() {
VTMarkupItemsTableProvider markupProvider = getMarkupItemsProvider();
runSwing(() -> {
markupProvider.toFront();
markupProvider.requestFocus();
});
}
public void triggerMatchTableDataChanged() {
@ -250,4 +263,5 @@ public class VTTestEnv extends TestEnv {
public VTMatchTableProvider getMatchTableProvider() {
return matchTableProvider;
}
}