GT-2999: fixed how comparison action is set to SHARED

This commit is contained in:
adamopolous 2019-12-31 08:17:07 -05:00
parent ec7773b464
commit 496408f2b7
23 changed files with 264 additions and 217 deletions

View file

@ -15,7 +15,7 @@
functions in a simple side-by-side panel. </P> functions in a simple side-by-side panel. </P>
<P>To begin, select a function (or multiple functions) from the listing or <P>To begin, select a function (or multiple functions) from the listing or
the function table. Then right-click and select the <b>Compare Selected the <A HREF="help/topics/FunctionWindowPlugin/function_window.htm">function table</a>. Then right-click and select the <b>Compare Selected
Functions</b> option.</P> Functions</b> option.</P>
<P><A name="Dual_Listing"></A>A new function comparison window will appear (subsequent <P><A name="Dual_Listing"></A>A new function comparison window will appear (subsequent

View file

@ -142,6 +142,17 @@ class FunctionComparisonData {
return function != null; return function != null;
} }
/**
* Returns true if this class holds no function, data or address set
* information
*
* @return true if this class holds no function, data or address set
* information
*/
public boolean isEmpty() {
return function == null && data == null && addressSet == null;
}
/** /**
* Resets all fields in this model to a nominal state * Resets all fields in this model to a nominal state
*/ */
@ -151,4 +162,23 @@ class FunctionComparisonData {
this.addressSet = new AddressSet(); this.addressSet = new AddressSet();
this.program = null; this.program = null;
} }
public String toString() {
String str = "";
if (function != null) {
str = function.getName();
}
else if (data != null) {
str = data.getAddress().toString();
}
else if (addressSet != null) {
str = addressSet.toString();
}
else {
str = "none";
}
return str;
}
} }

View file

@ -167,21 +167,6 @@ public class FunctionComparisonPanel extends JPanel implements ChangeListener {
} }
} }
/**
* Removes the functions in the left/right panels if they are in the
* given set
*
* @param functions the functions to remove
*/
public void removeFunctions(Set<Function> functions) {
if (functions.contains(leftComparisonData.getFunction())) {
setLeftFunction(null);
}
if (functions.contains(rightComparisonData.getFunction())) {
setRightFunction(null);
}
}
/** /**
* Get the actions for this FunctionComparisonPanel * Get the actions for this FunctionComparisonPanel
* *
@ -204,16 +189,16 @@ public class FunctionComparisonPanel extends JPanel implements ChangeListener {
Data rightData = rightComparisonData.getData(); Data rightData = rightComparisonData.getData();
if (leftFunc != null && rightFunc != null) { if (leftFunc != null && rightFunc != null) {
return "Function comparison of " + leftFunc.getName(true) + " & " + return leftFunc.getName(true) + " & " +
rightFunc.getName(true); rightFunc.getName(true);
} }
if (leftData != null && rightData != null) { if (leftData != null && rightData != null) {
return "Function comparison of " + leftData.getDataType().getName() + " & " + return leftData.getDataType().getName() + " & " +
rightData.getDataType().getName(); rightData.getDataType().getName();
} }
// Otherwise give a simple description for address sets // Otherwise give a simple description for address sets
return "Function comparison"; return "Nothing selected";
} }
/** /**
@ -233,20 +218,20 @@ public class FunctionComparisonPanel extends JPanel implements ChangeListener {
} }
/** /**
* Returns true if the comparison window has no functions to display in * Returns true if the comparison window has no information to display in
* either the left or right panel * either the left or right panel
* *
* @return true if the comparison window has no functions to display * @return true if the comparison window has no information to display
*/ */
public boolean isEmpty() { public boolean isEmpty() {
return getLeftFunction() == null || getRightFunction() == null; return leftComparisonData.isEmpty() || rightComparisonData.isEmpty();
} }
/** /**
* Gets the ListingCodeComparisonPanel being displayed by this panel * Gets the ListingCodeComparisonPanel being displayed by this panel
* if one exists * if one exists
* *
* @return the ListingCodeComparisonPanel or null * @return the comparison panel or null
*/ */
public ListingCodeComparisonPanel getDualListingPanel() { public ListingCodeComparisonPanel getDualListingPanel() {
for (CodeComparisonPanel<? extends FieldPanelCoordinator> codeComparisonPanel : codeComparisonPanels) { for (CodeComparisonPanel<? extends FieldPanelCoordinator> codeComparisonPanel : codeComparisonPanels) {
@ -258,9 +243,6 @@ public class FunctionComparisonPanel extends JPanel implements ChangeListener {
return null; return null;
} }
/**
* Invoked when a new tab on the panel has been selected
*/
@Override @Override
public void stateChanged(ChangeEvent e) { public void stateChanged(ChangeEvent e) {
tabChanged(); tabChanged();
@ -388,6 +370,24 @@ public class FunctionComparisonPanel extends JPanel implements ChangeListener {
return null; return null;
} }
/**
* Returns the comparison data object for the left panel
*
* @return the comparison data object for the left panel
*/
public FunctionComparisonData getLeftComparisonData() {
return leftComparisonData;
}
/**
* Returns the comparison data object for the right panel
*
* @return the comparison data object for the right panel
*/
public FunctionComparisonData getRightComparisonData() {
return rightComparisonData;
}
/** /**
* Gets the function currently displayed in the left side of this panel * Gets the function currently displayed in the left side of this panel
* *
@ -634,25 +634,6 @@ public class FunctionComparisonPanel extends JPanel implements ChangeListener {
toggleScrollLockAction = new ToggleScrollLockAction(); toggleScrollLockAction = new ToggleScrollLockAction();
} }
/**
* Comparator that lets CodeComparisonPanels be sorted based on their
* title names
*/
private class CodeComparisonPanelComparator
implements Comparator<CodeComparisonPanel<? extends FieldPanelCoordinator>> {
@Override
public int compare(CodeComparisonPanel<? extends FieldPanelCoordinator> o1,
CodeComparisonPanel<? extends FieldPanelCoordinator> o2) {
if (o1 == o2) {
return 0;
}
String title1 = o1.getTitle();
String title2 = o2.getTitle();
return title1.compareTo(title2);
}
}
/** /**
* Action that sets the scrolling state of the comparison panels * Action that sets the scrolling state of the comparison panels
*/ */
@ -716,10 +697,7 @@ public class FunctionComparisonPanel extends JPanel implements ChangeListener {
} }
} }
// Sort the list of code comparison panels so they display in the same order codeComparisonPanels.sort((p1, p2) -> p1.getTitle().compareTo(p2.getTitle()));
// each time for the user.
CodeComparisonPanelComparator comparator = new CodeComparisonPanelComparator();
codeComparisonPanels.sort(comparator);
} }
return codeComparisonPanels; return codeComparisonPanels;
} }

View file

@ -76,7 +76,8 @@ public class FunctionComparisonPlugin extends ProgramPlugin
@Override @Override
protected void init() { protected void init() {
CompareFunctionsAction compareFunctionsAction = new CompareFunctionsFromListingAction(tool); CompareFunctionsAction compareFunctionsAction =
new CompareFunctionsFromListingAction(tool, getName());
tool.addAction(compareFunctionsAction); tool.addAction(compareFunctionsAction);
} }
@ -132,6 +133,12 @@ public class FunctionComparisonPlugin extends ProgramPlugin
functionComparisonManager.addProviderListener(listener); functionComparisonManager.addProviderListener(listener);
} }
@Override
public void removeFunctionComparisonProviderListener(
ComponentProviderActivationListener listener) {
functionComparisonManager.removeProviderListener(listener);
}
@Override @Override
public void removeFunction(Function function) { public void removeFunction(Function function) {
functionComparisonManager.removeFunction(function); functionComparisonManager.removeFunction(function);

View file

@ -125,7 +125,7 @@ public class FunctionComparisonProvider extends ComponentProviderAdapter
public void modelChanged(List<FunctionComparison> model) { public void modelChanged(List<FunctionComparison> model) {
this.model.setComparisons(model); this.model.setComparisons(model);
functionComparisonPanel.reload(); functionComparisonPanel.reload();
setTabText(functionComparisonPanel); setTabText(functionComparisonPanel.getDescription());
closeIfEmpty(); closeIfEmpty();
} }
@ -225,25 +225,12 @@ public class FunctionComparisonProvider extends ComponentProviderAdapter
functionComparisonPanel.writeConfigState(getName(), saveState); functionComparisonPanel.writeConfigState(getName(), saveState);
} }
/**
* Creates the text that is displayed on the tab for this provider
*
* @param comparisonPanel the function comparison panel for this provider
*/
public void setTabText(FunctionComparisonPanel comparisonPanel) {
Function leftFunction = comparisonPanel.getLeftFunction();
Function rightFunction = comparisonPanel.getRightFunction();
String tabText = (leftFunction == null && rightFunction == null) ? "No Functions Yet"
: getTabText(leftFunction, rightFunction);
setTabText(tabText);
}
/** /**
* Perform initialization for this provider and its panel * Perform initialization for this provider and its panel
*/ */
protected void initFunctionComparisonPanel() { protected void initFunctionComparisonPanel() {
setTransient(); setTransient();
setTabText(functionComparisonPanel); setTabText(functionComparisonPanel.getDescription());
addSpecificCodeComparisonActions(); addSpecificCodeComparisonActions();
tool.addPopupActionProvider(this); tool.addPopupActionProvider(this);
setHelpLocation(new HelpLocation(HELP_TOPIC, "Function Comparison")); setHelpLocation(new HelpLocation(HELP_TOPIC, "Function Comparison"));
@ -267,19 +254,6 @@ public class FunctionComparisonProvider extends ComponentProviderAdapter
} }
} }
/**
* Returns the text that should be displayed in the tab, given the two
* left/right functions
*
* @param leftFunction
* @param rightFunction
* @return the tab text
*/
private String getTabText(Function leftFunction, Function rightFunction) {
return ((leftFunction != null) ? leftFunction.getName() : "none") + " & " +
((rightFunction != null) ? rightFunction.getName() : "none");
}
/** /**
* Gets actions specific to the code comparison panel and adds them to this * Gets actions specific to the code comparison panel and adds them to this
* provider * provider

View file

@ -159,6 +159,16 @@ public class FunctionComparisonProviderManager implements FunctionComparisonProv
listeners.add(listener); listeners.add(listener);
} }
/**
* Removes a subscriber who no longer wishes to receive provider activation
* events
*
* @param listener the subscriber to remove
*/
public void removeProviderListener(ComponentProviderActivationListener listener) {
listeners.remove(listener);
}
/** /**
* Closes all the comparison providers that contain a function from * Closes all the comparison providers that contain a function from
* the given program * the given program

View file

@ -66,7 +66,7 @@ public class MultiFunctionComparisonPanel extends FunctionComparisonPanel {
* @param provider the comparison provider associated with this panel * @param provider the comparison provider associated with this panel
* @param tool the active plugin tool * @param tool the active plugin tool
*/ */
public MultiFunctionComparisonPanel(FunctionComparisonProvider provider, public MultiFunctionComparisonPanel(MultiFunctionComparisonProvider provider,
PluginTool tool) { PluginTool tool) {
super(provider, tool, null, null); super(provider, tool, null, null);
@ -81,16 +81,6 @@ public class MultiFunctionComparisonPanel extends FunctionComparisonPanel {
getComparisonPanels().forEach(p -> p.setShowTitles(false)); getComparisonPanels().forEach(p -> p.setShowTitles(false));
} }
/**
* Clears the given functions from the comparison panel (both the
* source and target lists) (the default for this method is to only clear
* out the functions visible in the left/right panels)
*/
@Override
public void removeFunctions(Set<Function> functions) {
((MultiFunctionComparisonProvider) provider).removeFunctions(functions);
}
/** /**
* Clears out the source and targets lists and reloads them to * Clears out the source and targets lists and reloads them to
* ensure that they reflect the current state of the data model. Any * ensure that they reflect the current state of the data model. Any
@ -105,9 +95,7 @@ public class MultiFunctionComparisonPanel extends FunctionComparisonPanel {
reloadTargetList(selectedSource); reloadTargetList(selectedSource);
loadFunctions(selectedSource, (Function) targetFunctionsCBModel.getSelectedItem()); loadFunctions(selectedSource, (Function) targetFunctionsCBModel.getSelectedItem());
((FunctionComparisonProvider) provider).setTabText(this); updateTabText();
((FunctionComparisonProvider) provider)
.setTitle(((FunctionComparisonProvider) provider).getTabText());
// Fire a notification to update the UI state; without this the // Fire a notification to update the UI state; without this the
// actions would not be properly enabled/disabled // actions would not be properly enabled/disabled
@ -181,6 +169,16 @@ public class MultiFunctionComparisonPanel extends FunctionComparisonPanel {
restoreSelection(targetFunctionsCB, selection); restoreSelection(targetFunctionsCB, selection);
} }
/**
* Sets the text on the current tab to match whatever is displayed in the
* comparison panels
*/
private void updateTabText() {
String tabText = getDescription();
provider.setTabText(tabText);
provider.setTitle(tabText);
}
/** /**
* Sets a given function to be the selected item in a given combo * Sets a given function to be the selected item in a given combo
* box. If the function isn't found, the first item in the box is * box. If the function isn't found, the first item in the box is
@ -238,6 +236,8 @@ public class MultiFunctionComparisonPanel extends FunctionComparisonPanel {
// to load the targets associated with it // to load the targets associated with it
reloadTargetList((Function) sourceFunctionsCBModel.getSelectedItem()); reloadTargetList((Function) sourceFunctionsCBModel.getSelectedItem());
updateTabText();
// Fire a notification to update the UI state; without this the // Fire a notification to update the UI state; without this the
// actions would not be properly enabled/disabled // actions would not be properly enabled/disabled
tool.contextChanged(provider); tool.contextChanged(provider);
@ -275,6 +275,8 @@ public class MultiFunctionComparisonPanel extends FunctionComparisonPanel {
Function selected = (Function) targetFunctionsCBModel.getSelectedItem(); Function selected = (Function) targetFunctionsCBModel.getSelectedItem();
loadFunctions((Function) sourceFunctionsCBModel.getSelectedItem(), selected); loadFunctions((Function) sourceFunctionsCBModel.getSelectedItem(), selected);
updateTabText();
// Fire a notification to update the UI state; without this the // Fire a notification to update the UI state; without this the
// actions would not be properly enabled/disabled // actions would not be properly enabled/disabled
tool.contextChanged(provider); tool.contextChanged(provider);

View file

@ -15,6 +15,7 @@
*/ */
package ghidra.app.plugin.core.functioncompare.actions; package ghidra.app.plugin.core.functioncompare.actions;
import java.awt.event.InputEvent;
import java.util.Set; import java.util.Set;
import javax.swing.Icon; import javax.swing.Icon;
@ -57,9 +58,10 @@ public abstract class CompareFunctionsAction extends DockingAction {
* Constructor * Constructor
* *
* @param tool the plugin tool * @param tool the plugin tool
* @param owner the action owner (usually the plugin name)
*/ */
public CompareFunctionsAction(PluginTool tool) { public CompareFunctionsAction(PluginTool tool, String owner) {
super("Compare Functions", tool.getName()); super("Compare Functions", owner, KeyBindingType.SHARED);
this.comparisonService = tool.getService(FunctionComparisonService.class); this.comparisonService = tool.getService(FunctionComparisonService.class);
setActionAttributes(); setActionAttributes();
} }
@ -101,5 +103,8 @@ public abstract class CompareFunctionsAction extends DockingAction {
new ToolBarData(getToolBarIcon(), CREATE_COMPARISON_GROUP); new ToolBarData(getToolBarIcon(), CREATE_COMPARISON_GROUP);
setToolBarData(newToolBarData); setToolBarData(newToolBarData);
setHelpLocation(new HelpLocation("FunctionComparison", "Function_Comparison")); setHelpLocation(new HelpLocation("FunctionComparison", "Function_Comparison"));
KeyBindingData data = new KeyBindingData('C', InputEvent.SHIFT_DOWN_MASK);
setKeyBindingData(data);
} }
} }

View file

@ -21,7 +21,7 @@ import docking.ActionContext;
import ghidra.app.plugin.core.functionwindow.FunctionRowObject; import ghidra.app.plugin.core.functionwindow.FunctionRowObject;
import ghidra.app.plugin.core.functionwindow.FunctionTableModel; import ghidra.app.plugin.core.functionwindow.FunctionTableModel;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.Function;
import ghidra.util.table.GhidraTable; import ghidra.util.table.GhidraTable;
/** /**
@ -41,9 +41,10 @@ public class CompareFunctionsFromFunctionTableAction extends CompareFunctionsAct
* Constructor * Constructor
* *
* @param tool the plugin tool * @param tool the plugin tool
* @param owner the action owner
*/ */
public CompareFunctionsFromFunctionTableAction(PluginTool tool) { public CompareFunctionsFromFunctionTableAction(PluginTool tool, String owner) {
super(tool); super(tool, owner);
} }
@Override @Override
@ -66,12 +67,9 @@ public class CompareFunctionsFromFunctionTableAction extends CompareFunctionsAct
return Collections.emptySet(); return Collections.emptySet();
} }
FunctionTableModel model = (FunctionTableModel) table.getModel(); FunctionTableModel model = (FunctionTableModel) table.getModel();
Program program = model.getProgram();
FunctionManager functionManager = program.getFunctionManager();
List<FunctionRowObject> functionRowObjects = model.getRowObjects(selectedRows); List<FunctionRowObject> functionRowObjects = model.getRowObjects(selectedRows);
for (FunctionRowObject functionRowObject : functionRowObjects) { for (FunctionRowObject functionRowObject : functionRowObjects) {
long key = functionRowObject.getKey(); Function rowFunction = functionRowObject.getFunction();
Function rowFunction = functionManager.getFunction(key);
functions.add(rowFunction); functions.add(rowFunction);
} }
return functions; return functions;

View file

@ -34,9 +34,10 @@ public class CompareFunctionsFromListingAction extends CompareFunctionsAction {
* Constructor * Constructor
* *
* @param tool the plugin tool * @param tool the plugin tool
* @param owner the action owner
*/ */
public CompareFunctionsFromListingAction(PluginTool tool) { public CompareFunctionsFromListingAction(PluginTool tool, String owner) {
super(tool); super(tool, owner);
} }
@Override @Override

View file

@ -93,6 +93,5 @@ public class NextFunctionAction extends DockingAction {
MultiFunctionComparisonPanel panel = (MultiFunctionComparisonPanel) provider.getComponent(); MultiFunctionComparisonPanel panel = (MultiFunctionComparisonPanel) provider.getComponent();
JComboBox<Function> focusedComponent = panel.getFocusedComponent(); JComboBox<Function> focusedComponent = panel.getFocusedComponent();
focusedComponent.setSelectedIndex(focusedComponent.getSelectedIndex() + 1); focusedComponent.setSelectedIndex(focusedComponent.getSelectedIndex() + 1);
provider.contextChanged();
} }
} }

View file

@ -15,6 +15,7 @@
*/ */
package ghidra.app.plugin.core.functioncompare.actions; package ghidra.app.plugin.core.functioncompare.actions;
import java.awt.event.InputEvent;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -34,7 +35,6 @@ import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
import ghidra.util.SystemUtilities;
import resources.MultiIcon; import resources.MultiIcon;
import resources.ResourceManager; import resources.ResourceManager;
import resources.icons.ScaledImageIconWrapper; import resources.icons.ScaledImageIconWrapper;
@ -86,6 +86,9 @@ public class OpenFunctionTableAction extends DockingAction {
HelpLocation helpLocation = new HelpLocation(MultiFunctionComparisonPanel.HELP_TOPIC, HelpLocation helpLocation = new HelpLocation(MultiFunctionComparisonPanel.HELP_TOPIC,
"Add_To_Comparison"); "Add_To_Comparison");
setHelpLocation(helpLocation); setHelpLocation(helpLocation);
KeyBindingData data = new KeyBindingData('A', InputEvent.SHIFT_DOWN_MASK);
setKeyBindingData(data);
} }
@Override @Override
@ -95,7 +98,10 @@ public class OpenFunctionTableAction extends DockingAction {
@Override @Override
public void actionPerformed(ActionContext context) { public void actionPerformed(ActionContext context) {
Runnable runnable = () -> { if (!(context.getComponentProvider() instanceof FunctionComparisonProvider)) {
return;
}
FunctionComparisonProvider provider = FunctionComparisonProvider provider =
(FunctionComparisonProvider) context.getComponentProvider(); (FunctionComparisonProvider) context.getComponentProvider();
Program currentProgram = programManagerService.getCurrentProgram(); Program currentProgram = programManagerService.getCurrentProgram();
@ -114,8 +120,5 @@ public class OpenFunctionTableAction extends DockingAction {
Set<Function> functions = Set<Function> functions =
rows.stream().map(row -> row.getFunction()).collect(Collectors.toSet()); rows.stream().map(row -> row.getFunction()).collect(Collectors.toSet());
comparisonService.compareFunctions(new HashSet<>(functions), provider); comparisonService.compareFunctions(new HashSet<>(functions), provider);
};
SystemUtilities.runSwingLater(runnable);
} }
} }

View file

@ -93,6 +93,5 @@ public class PreviousFunctionAction extends DockingAction {
MultiFunctionComparisonPanel panel = (MultiFunctionComparisonPanel) provider.getComponent(); MultiFunctionComparisonPanel panel = (MultiFunctionComparisonPanel) provider.getComponent();
JComboBox<Function> focusedComponent = panel.getFocusedComponent(); JComboBox<Function> focusedComponent = panel.getFocusedComponent();
focusedComponent.setSelectedIndex(focusedComponent.getSelectedIndex() - 1); focusedComponent.setSelectedIndex(focusedComponent.getSelectedIndex() - 1);
provider.contextChanged();
} }
} }

View file

@ -51,7 +51,6 @@ import ghidra.util.task.SwingUpdateManager;
category = PluginCategoryNames.CODE_VIEWER, category = PluginCategoryNames.CODE_VIEWER,
shortDescription = "Function Viewer", shortDescription = "Function Viewer",
description = "Provides a window that displays the list of functions in the program.", description = "Provides a window that displays the list of functions in the program.",
servicesRequired = { FunctionComparisonService.class },
eventsConsumed = { ProgramClosedPluginEvent.class } eventsConsumed = { ProgramClosedPluginEvent.class }
) )
//@formatter:on //@formatter:on
@ -78,9 +77,7 @@ public class FunctionWindowPlugin extends ProgramPlugin implements DomainObjectL
@Override @Override
public void init() { public void init() {
super.init(); super.init();
provider = new FunctionWindowProvider(this); provider = new FunctionWindowProvider(this);
functionComparisonService = tool.getService(FunctionComparisonService.class);
createActions(); createActions();
/** /**
@ -90,11 +87,6 @@ public class FunctionWindowPlugin extends ProgramPlugin implements DomainObjectL
provider.getTable().getSelectionModel().addListSelectionListener(x -> { provider.getTable().getSelectionModel().addListSelectionListener(x -> {
tool.contextChanged(provider); tool.contextChanged(provider);
}); });
// Listen for providers being opened/closed to we can disable the
// add-to-comparison action if there are no comparison windows
// open.
functionComparisonService.addFunctionComparisonProviderListener(this);
} }
@Override @Override
@ -109,6 +101,26 @@ public class FunctionWindowPlugin extends ProgramPlugin implements DomainObjectL
super.dispose(); super.dispose();
} }
@Override
public void serviceAdded(Class<?> interfaceClass, Object service) {
if (interfaceClass == FunctionComparisonService.class) {
functionComparisonService = (FunctionComparisonService) service;
// Listen for providers being opened/closed to we can disable
// comparison actions if there are no comparison providers
// open
functionComparisonService.addFunctionComparisonProviderListener(this);
}
}
@Override
public void serviceRemoved(Class<?> interfaceClass, Object service) {
if (interfaceClass == FunctionComparisonService.class) {
functionComparisonService.removeFunctionComparisonProviderListener(this);
functionComparisonService = null;
}
}
@Override @Override
public void domainObjectChanged(DomainObjectChangedEvent ev) { public void domainObjectChanged(DomainObjectChangedEvent ev) {
@ -205,24 +217,10 @@ public class FunctionWindowPlugin extends ProgramPlugin implements DomainObjectL
selectAction = new MakeProgramSelectionAction(this, provider.getTable()); selectAction = new MakeProgramSelectionAction(this, provider.getTable());
tool.addLocalAction(provider, selectAction); tool.addLocalAction(provider, selectAction);
compareFunctionsAction = new CompareFunctionsFromFunctionTableAction(tool); compareFunctionsAction = new CompareFunctionsFromFunctionTableAction(tool, getName());
tool.addLocalAction(provider, compareFunctionsAction); tool.addLocalAction(provider, compareFunctionsAction);
} }
// private void installDummyAction(DockingAction action) {
// DummyKeyBindingsOptionsAction dummyAction =
// new DummyKeyBindingsOptionsAction(action.getName(), null);
// tool.addAction(dummyAction);
//
// ToolOptions options = tool.getOptions(DockingToolConstants.KEY_BINDINGS);
// options.addOptionsChangeListener(this);
//
// KeyStroke keyStroke = options.getKeyStroke(dummyAction.getFullName(), null);
// if (keyStroke != null) {
// action.setUnvalidatedKeyBindingData(new KeyBindingData(keyStroke));
// }
// }
@Override @Override
public void optionsChanged(ToolOptions options, String optionName, Object oldValue, public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
Object newValue) { Object newValue) {
@ -237,11 +235,6 @@ public class FunctionWindowPlugin extends ProgramPlugin implements DomainObjectL
} }
} }
void setActionsEnabled(boolean enabled) {
selectAction.setEnabled(enabled);
compareFunctionsAction.setEnabled(enabled);
}
void showFunctions() { void showFunctions() {
provider.showFunctions(); provider.showFunctions();
} }

View file

@ -128,9 +128,7 @@ public class FunctionWindowProvider extends ComponentProviderAdapter {
functionTable.setPreferredScrollableViewportSize(new Dimension(350, 150)); functionTable.setPreferredScrollableViewportSize(new Dimension(350, 150));
functionTable.setRowSelectionAllowed(true); functionTable.setRowSelectionAllowed(true);
functionTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); functionTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
functionTable.getSelectionModel() functionTable.getSelectionModel().addListSelectionListener(e -> tool.contextChanged(this));
.addListSelectionListener(
e -> plugin.setActionsEnabled(functionTable.getSelectedRowCount() > 0));
functionModel.addTableModelListener(e -> { functionModel.addTableModelListener(e -> {
int rowCount = functionModel.getRowCount(); int rowCount = functionModel.getRowCount();

View file

@ -27,7 +27,6 @@ import ghidra.app.plugin.core.functioncompare.*;
import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskLauncher; import ghidra.util.task.TaskLauncher;
/** /**
@ -114,7 +113,7 @@ public class FunctionComparisonModel {
* Note: It is assumed that when using this method, all functions can be * Note: It is assumed that when using this method, all functions can be
* compared with all other functions; meaning each function will be added as * compared with all other functions; meaning each function will be added as
* both a source AND a target. To specify a specific source/target * both a source AND a target. To specify a specific source/target
* relationship, see {@link #compareFunctions(Function, Function)}. * relationship, use {@link #compareFunctions(Function, Function)}.
* *
* @param functions the set of functions to compare * @param functions the set of functions to compare
*/ */
@ -295,13 +294,11 @@ public class FunctionComparisonModel {
// Now loop over the given functions and create new comparisons // Now loop over the given functions and create new comparisons
for (Function f : functions) { for (Function f : functions) {
try { if (monitor.isCancelled()) {
monitor.checkCanceled();
}
catch (CancelledException e) {
Msg.info(this, "Function comparison operation cancelled"); Msg.info(this, "Function comparison operation cancelled");
return; return;
} }
FunctionComparison fc = new FunctionComparison(); FunctionComparison fc = new FunctionComparison();
fc.setSource(f); fc.setSource(f);
fc.addTargets(functions); fc.addTargets(functions);

View file

@ -25,14 +25,24 @@ import ghidra.program.model.listing.Function;
/** /**
* Allows users to create comparisons between functions which will be displayed * Allows users to create comparisons between functions which will be displayed
* side-by-side in a {@link FunctionComparisonProvider} * side-by-side in a {@link FunctionComparisonProvider}. Each side in the
* display will allow the user to select one or more functions
*/ */
@ServiceInfo(defaultProvider = FunctionComparisonPlugin.class) @ServiceInfo(defaultProvider = FunctionComparisonPlugin.class)
public interface FunctionComparisonService { public interface FunctionComparisonService {
/** /**
* Creates a comparison between a set of functions, where each function * Creates a comparison between a set of functions, where each function
* in the list can be compared against any other function in the list * in the list can be compared against any other.
* <p>
* eg: Given a set of 3 functions (f1, f2, f3), the comparison dialog will
* allow the user to display either f1, f2 or f3 on EITHER side of the
* comparison.
* <p>
* Note that this method will always create a new provider; if you want to
* add functions to an existing comparison, use
* {@link #compareFunctions(Set, FunctionComparisonProvider) this}
* variant that takes a provider.
* *
* @param functions the functions to compare * @param functions the functions to compare
* @return the new comparison provider * @return the new comparison provider
@ -40,7 +50,14 @@ public interface FunctionComparisonService {
public FunctionComparisonProvider compareFunctions(Set<Function> functions); public FunctionComparisonProvider compareFunctions(Set<Function> functions);
/** /**
* Creates a comparison between two functions * Creates a comparison between two functions, where the source function
* will be shown on the left side of the comparison dialog and the target
* on the right.
* <p>
* Note that this will always create a new provider; if you want to add
* functions to an existing comparison, use
* {@link #compareFunctions(Function, Function, FunctionComparisonProvider) this}
* variant that takes a provider.
* *
* @param source a function in the comparison * @param source a function in the comparison
* @param target a function in the comparison * @param target a function in the comparison
@ -51,8 +68,11 @@ public interface FunctionComparisonService {
/** /**
* Creates a comparison between a set of functions, adding them to the * Creates a comparison between a set of functions, adding them to the
* given comparison provider * given comparison provider. Each function in the given set will be added
* to both sides of the comparison, allowing users to compare any functions
* in the existing provider with the new set.
* *
* @see #compareFunctions(Set)
* @param functions the functions to compare * @param functions the functions to compare
* @param provider the provider to add the comparisons to * @param provider the provider to add the comparisons to
*/ */
@ -61,8 +81,12 @@ public interface FunctionComparisonService {
/** /**
* Creates a comparison between two functions and adds it to a given * Creates a comparison between two functions and adds it to a given
* comparison provider * comparison provider. The existing comparisons in the provider will not
* be affected, unless the provider already contains a comparison with
* the same source function; in this case the given target will be added
* to that comparisons' list of targets.
* *
* @see #compareFunctions(Function, Function)
* @param source a function in the comparison * @param source a function in the comparison
* @param target a function in the comparison * @param target a function in the comparison
* @param provider the provider to add the comparison to * @param provider the provider to add the comparison to
@ -80,7 +104,7 @@ public interface FunctionComparisonService {
/** /**
* Removes a given function from all comparisons in the given comparison * Removes a given function from all comparisons in the given comparison
* provider * provider only
* *
* @param function the function to remove * @param function the function to remove
* @param provider the comparison provider to remove functions from * @param provider the comparison provider to remove functions from
@ -94,4 +118,12 @@ public interface FunctionComparisonService {
* @param listener the listener to be added * @param listener the listener to be added
*/ */
public void addFunctionComparisonProviderListener(ComponentProviderActivationListener listener); public void addFunctionComparisonProviderListener(ComponentProviderActivationListener listener);
/**
* Removes a listener from the list of provider activation event subscribers
*
* @param listener the listener to remove
*/
public void removeFunctionComparisonProviderListener(
ComponentProviderActivationListener listener);
} }

View file

@ -39,8 +39,8 @@ import ghidra.util.classfinder.ExtensionPoint;
* discovered by the {@link FunctionComparisonPanel} class and included as a * discovered by the {@link FunctionComparisonPanel} class and included as a
* form of comparing two sections of code within the same or different programs * form of comparing two sections of code within the same or different programs
* <p> * <p>
* NOTE: ALL CodeComparisonPanel CLASSES MUST END IN < * NOTE: ALL CodeComparisonPanel CLASSES MUST END IN
* code>CodeComparisonPanel</code> so they are discoverable by the * <code>CodeComparisonPanel</code> so they are discoverable by the
* {@link ClassSearcher} * {@link ClassSearcher}
*/ */
public abstract class CodeComparisonPanel<T extends FieldPanelCoordinator> extends JPanel public abstract class CodeComparisonPanel<T extends FieldPanelCoordinator> extends JPanel

View file

@ -15,7 +15,9 @@
*/ */
package ghidra.app.plugin.core.functioncompare; package ghidra.app.plugin.core.functioncompare;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.awt.Window; import java.awt.Window;
import java.util.Date; import java.util.Date;
@ -25,10 +27,10 @@ import javax.swing.JPanel;
import org.junit.*; import org.junit.*;
import docking.ActionContext;
import docking.action.DockingActionIf; import docking.action.DockingActionIf;
import docking.widgets.dialogs.TableChooserDialog; import docking.widgets.dialogs.TableChooserDialog;
import docking.widgets.table.GFilterTable; import docking.widgets.table.GFilterTable;
import generic.test.AbstractGenericTest;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.function.FunctionPlugin; import ghidra.app.plugin.core.function.FunctionPlugin;
import ghidra.app.plugin.core.functionwindow.FunctionRowObject; import ghidra.app.plugin.core.functionwindow.FunctionRowObject;
@ -46,7 +48,7 @@ import ghidra.test.TestEnv;
* Tests for the {@link FunctionComparisonPlugin function comparison plugin} * Tests for the {@link FunctionComparisonPlugin function comparison plugin}
* that involve the GUI * that involve the GUI
*/ */
public class CompareFunctionsTestSlow extends AbstractGhidraHeadedIntegrationTest { public class CompareFunctionsSlowTest extends AbstractGhidraHeadedIntegrationTest {
private TestEnv env; private TestEnv env;
private Program program1; private Program program1;
@ -65,8 +67,6 @@ public class CompareFunctionsTestSlow extends AbstractGhidraHeadedIntegrationTes
plugin = env.addPlugin(FunctionComparisonPlugin.class); plugin = env.addPlugin(FunctionComparisonPlugin.class);
functionPlugin = env.addPlugin(FunctionPlugin.class); functionPlugin = env.addPlugin(FunctionPlugin.class);
cbPlugin = env.addPlugin(CodeBrowserPlugin.class); cbPlugin = env.addPlugin(CodeBrowserPlugin.class);
assertNotNull(plugin);
assertNotNull(functionPlugin);
buildTestProgram1(); buildTestProgram1();
buildTestProgram2(); buildTestProgram2();
showTool(plugin.getTool()); showTool(plugin.getTool());
@ -84,7 +84,7 @@ public class CompareFunctionsTestSlow extends AbstractGhidraHeadedIntegrationTes
provider = plugin.compareFunctions(functions); provider = plugin.compareFunctions(functions);
provider = waitForComponentProvider(FunctionComparisonProvider.class); provider = waitForComponentProvider(FunctionComparisonProvider.class);
plugin.removeFunction(foo, provider); plugin.removeFunction(foo, provider);
assert (!provider.isVisible()); assertFalse(provider.isVisible());
} }
@Test @Test
@ -120,11 +120,15 @@ public class CompareFunctionsTestSlow extends AbstractGhidraHeadedIntegrationTes
DockingActionIf nextAction = getAction(plugin, "Compare Next Function"); DockingActionIf nextAction = getAction(plugin, "Compare Next Function");
DockingActionIf prevAction = getAction(plugin, "Compare Previous Function"); DockingActionIf prevAction = getAction(plugin, "Compare Previous Function");
assert (nextAction.isEnabled()); ActionContext context = provider.getActionContext(null);
assert (!prevAction.isEnabled()); assertTrue(nextAction.isEnabledForContext(context));
assertFalse(prevAction.isEnabledForContext(context));
performAction(nextAction); performAction(nextAction);
assert (!nextAction.isEnabled());
assert (prevAction.isEnabled()); context = provider.getActionContext(null);
assertFalse(nextAction.isEnabledForContext(context));
assertTrue(prevAction.isEnabledForContext(context));
} }
@Test @Test
@ -141,11 +145,15 @@ public class CompareFunctionsTestSlow extends AbstractGhidraHeadedIntegrationTes
DockingActionIf nextAction = getAction(plugin, "Compare Next Function"); DockingActionIf nextAction = getAction(plugin, "Compare Next Function");
DockingActionIf prevAction = getAction(plugin, "Compare Previous Function"); DockingActionIf prevAction = getAction(plugin, "Compare Previous Function");
assert (nextAction.isEnabled()); ActionContext context = provider.getActionContext(null);
assert (!prevAction.isEnabled()); assertTrue(nextAction.isEnabledForContext(context));
assertFalse(prevAction.isEnabledForContext(context));
performAction(nextAction); performAction(nextAction);
assert (!nextAction.isEnabled());
assert (prevAction.isEnabled()); context = provider.getActionContext(null);
assertFalse(nextAction.isEnabledForContext(context));
assertTrue(prevAction.isEnabledForContext(context));
JPanel rightPanel = JPanel rightPanel =
provider.getComponent().getDualListingPanel().getRightPanel().getFieldPanel(); provider.getComponent().getDualListingPanel().getRightPanel().getFieldPanel();
@ -153,8 +161,9 @@ public class CompareFunctionsTestSlow extends AbstractGhidraHeadedIntegrationTes
waitForSwing(); waitForSwing();
provider.getComponent().updateActionEnablement(); provider.getComponent().updateActionEnablement();
assert (nextAction.isEnabled()); context = provider.getActionContext(null);
assert (!prevAction.isEnabled()); assertTrue(nextAction.isEnabledForContext(context));
assertFalse(prevAction.isEnabledForContext(context));
} }
@Test @Test
@ -163,11 +172,15 @@ public class CompareFunctionsTestSlow extends AbstractGhidraHeadedIntegrationTes
provider = plugin.compareFunctions(functions); provider = plugin.compareFunctions(functions);
provider.setVisible(true); provider.setVisible(true);
// Must do this or the context for the action initiated below will be
// for the listing, not the comparison provider
clickComponentProvider(provider);
DockingActionIf openTableAction = getAction(plugin, "Add Functions To Comparison"); DockingActionIf openTableAction = getAction(plugin, "Add Functions To Comparison");
performAction(openTableAction); performAction(openTableAction);
Window selectWindow = waitForWindowByTitleContaining("Select Functions"); Window selectWindow = waitForWindowByTitleContaining("Select Functions");
assert (selectWindow != null); assertNotNull(selectWindow);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -182,26 +195,26 @@ public class CompareFunctionsTestSlow extends AbstractGhidraHeadedIntegrationTes
// initiated below // initiated below
clickComponentProvider(provider); clickComponentProvider(provider);
assert (provider.getModel().getSourceFunctions().size() == 1); assertTrue(provider.getModel().getSourceFunctions().size() == 1);
assert (provider.getModel().getSourceFunctions().contains(foo)); assertTrue(provider.getModel().getSourceFunctions().contains(foo));
DockingActionIf openTableAction = getAction(plugin, "Add Functions To Comparison"); DockingActionIf openTableAction = getAction(plugin, "Add Functions To Comparison");
performAction(openTableAction); performAction(openTableAction);
TableChooserDialog<FunctionTableModel> chooser = TableChooserDialog<FunctionTableModel> chooser =
waitForDialogComponent(TableChooserDialog.class); waitForDialogComponent(TableChooserDialog.class);
assert (chooser != null); assertNotNull(chooser);
GFilterTable<FunctionRowObject> table = GFilterTable<FunctionRowObject> table =
(GFilterTable<FunctionRowObject>) getInstanceField("gFilterTable", chooser); (GFilterTable<FunctionRowObject>) getInstanceField("gFilterTable", chooser);
assert (table.getModel().getRowCount() == 2); assertTrue(table.getModel().getRowCount() == 2);
clickTableCell(table.getTable(), 1, 0, 1); clickTableCell(table.getTable(), 1, 0, 1);
pressButtonByText(chooser, "OK"); pressButtonByText(chooser, "OK");
waitForSwing(); waitForSwing();
assert (provider.getModel().getSourceFunctions().size() == 2); assertTrue(provider.getModel().getSourceFunctions().size() == 2);
assert (provider.getModel().getSourceFunctions().contains(foo)); assertTrue(provider.getModel().getSourceFunctions().contains(foo));
assert (provider.getModel().getSourceFunctions().contains(bat)); assertTrue(provider.getModel().getSourceFunctions().contains(bat));
} }
/** /**
@ -215,9 +228,9 @@ public class CompareFunctionsTestSlow extends AbstractGhidraHeadedIntegrationTes
provider = plugin.compareFunctions(functions); provider = plugin.compareFunctions(functions);
provider.setVisible(true); provider.setVisible(true);
assert (provider.getModel().getSourceFunctions().size() == 2); assertTrue(provider.getModel().getSourceFunctions().size() == 2);
assert (provider.getModel().getSourceFunctions().contains(foo)); assertTrue(provider.getModel().getSourceFunctions().contains(foo));
assert (provider.getModel().getSourceFunctions().contains(bar)); assertTrue(provider.getModel().getSourceFunctions().contains(bar));
Address addr = program1.getAddressFactory().getAddress("10018cf"); Address addr = program1.getAddressFactory().getAddress("10018cf");
ProgramLocation loc = new ProgramLocation(program1, addr); ProgramLocation loc = new ProgramLocation(program1, addr);
@ -227,8 +240,8 @@ public class CompareFunctionsTestSlow extends AbstractGhidraHeadedIntegrationTes
waitForSwing(); waitForSwing();
assert (provider.getModel().getSourceFunctions().size() == 1); assertTrue(provider.getModel().getSourceFunctions().size() == 1);
assert (provider.getModel().getSourceFunctions().contains(bar)); assertTrue(provider.getModel().getSourceFunctions().contains(bar));
} }
/** /**
@ -246,7 +259,6 @@ public class CompareFunctionsTestSlow extends AbstractGhidraHeadedIntegrationTes
bat = builder.createEmptyFunction("Bat", "100299e", 130, null, p, p, p); bat = builder.createEmptyFunction("Bat", "100299e", 130, null, p, p, p);
program1 = builder.getProgram(); program1 = builder.getProgram();
AbstractGenericTest.setInstanceField("recordChanges", program1, Boolean.TRUE);
return builder; return builder;
} }
@ -264,7 +276,6 @@ public class CompareFunctionsTestSlow extends AbstractGhidraHeadedIntegrationTes
bar = builder.createEmptyFunction("Bar", "10018cf", 10, null, p); bar = builder.createEmptyFunction("Bar", "10018cf", 10, null, p);
program2 = builder.getProgram(); program2 = builder.getProgram();
AbstractGenericTest.setInstanceField("recordChanges", program2, Boolean.TRUE);
return builder; return builder;
} }
} }

View file

@ -15,7 +15,7 @@
*/ */
package ghidra.app.plugin.core.functioncompare; package ghidra.app.plugin.core.functioncompare;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.util.Date; import java.util.Date;
@ -64,7 +64,6 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest {
public void setUp() throws Exception { public void setUp() throws Exception {
DummyPluginTool tool = new DummyPluginTool(); DummyPluginTool tool = new DummyPluginTool();
plugin = new FunctionComparisonPlugin(tool); plugin = new FunctionComparisonPlugin(tool);
assertNotNull(plugin);
buildTestProgram1(); buildTestProgram1();
buildTestProgram2(); buildTestProgram2();
@ -81,7 +80,7 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest {
public void testSetNoFunctions() throws Exception { public void testSetNoFunctions() throws Exception {
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(); Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet();
FunctionComparisonProvider provider = plugin.compareFunctions(functions); FunctionComparisonProvider provider = plugin.compareFunctions(functions);
assert (provider == null); assertNull(provider);
} }
@Test @Test

View file

@ -15,6 +15,9 @@
*/ */
package ghidra.app.plugin.core.functioncompare; package ghidra.app.plugin.core.functioncompare;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.*; import java.util.*;
import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Function;
@ -23,7 +26,7 @@ import ghidra.program.model.listing.Function;
* Helper methods for use with function comparison tests * Helper methods for use with function comparison tests
* *
* @see {@link CompareFunctionsTest} * @see {@link CompareFunctionsTest}
* @see {@link CompareFunctionsTestSlow} * @see {@link CompareFunctionsSlowTest}
*/ */
public class CompareFunctionsTestUtility { public class CompareFunctionsTestUtility {
@ -38,8 +41,8 @@ public class CompareFunctionsTestUtility {
Function... functions) { Function... functions) {
Set<Function> funcs = new HashSet<>(Arrays.asList(functions)); Set<Function> funcs = new HashSet<>(Arrays.asList(functions));
Set<Function> fcs = provider.getModel().getSourceFunctions(); Set<Function> fcs = provider.getModel().getSourceFunctions();
assert (fcs.size() == funcs.size()); assertEquals(fcs.size(), funcs.size());
assert (fcs.containsAll(funcs)); assertTrue(fcs.containsAll(funcs));
} }
/** /**
@ -54,8 +57,8 @@ public class CompareFunctionsTestUtility {
Function source, Function... targets) { Function source, Function... targets) {
Set<Function> targetsAsList = new HashSet<>(Arrays.asList(targets)); Set<Function> targetsAsList = new HashSet<>(Arrays.asList(targets));
Set<Function> tgts = provider.getModel().getTargetFunctions(source); Set<Function> tgts = provider.getModel().getTargetFunctions(source);
assert (tgts.size() == targetsAsList.size()); assertEquals(tgts.size(), targetsAsList.size());
assert (tgts.containsAll(targetsAsList)); assertTrue(tgts.containsAll(targetsAsList));
} }
/** /**

View file

@ -15,8 +15,12 @@
*/ */
package ghidra.feature.vt.gui.provider.functionassociation; package ghidra.feature.vt.gui.provider.functionassociation;
import static ghidra.feature.vt.api.impl.VTChangeManager.*; import static ghidra.feature.vt.api.impl.VTChangeManager.DOCR_VT_ASSOCIATION_STATUS_CHANGED;
import static ghidra.feature.vt.gui.provider.functionassociation.FilterSettings.*; import static ghidra.feature.vt.api.impl.VTChangeManager.DOCR_VT_MATCH_ADDED;
import static ghidra.feature.vt.api.impl.VTChangeManager.DOCR_VT_MATCH_DELETED;
import static ghidra.feature.vt.gui.provider.functionassociation.FilterSettings.SHOW_ALL;
import static ghidra.feature.vt.gui.provider.functionassociation.FilterSettings.SHOW_UNACCEPTED;
import static ghidra.feature.vt.gui.provider.functionassociation.FilterSettings.SHOW_UNMATCHED;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
@ -473,8 +477,10 @@ public class VTFunctionAssociationProvider extends ComponentProviderAdapter
sourceFunctionsModel.addTableModelListener(new TitleUpdateListener()); sourceFunctionsModel.addTableModelListener(new TitleUpdateListener());
sourceFunctionsTable.getColumnModel().getColumn( sourceFunctionsTable.getColumnModel()
VTFunctionAssociationTableModel.ADDRESS_COL).setPreferredWidth( .getColumn(
VTFunctionAssociationTableModel.ADDRESS_COL)
.setPreferredWidth(
VTFunctionAssociationTableModel.ADDRESS_COL_WIDTH); VTFunctionAssociationTableModel.ADDRESS_COL_WIDTH);
sourceTableFilterPanel = sourceTableFilterPanel =
@ -530,8 +536,10 @@ public class VTFunctionAssociationProvider extends ComponentProviderAdapter
JTableHeader functionHeader = destinationFunctionsTable.getTableHeader(); JTableHeader functionHeader = destinationFunctionsTable.getTableHeader();
functionHeader.setUpdateTableInRealTime(true); functionHeader.setUpdateTableInRealTime(true);
destinationFunctionsTable.getColumnModel().getColumn( destinationFunctionsTable.getColumnModel()
VTFunctionAssociationTableModel.ADDRESS_COL).setPreferredWidth( .getColumn(
VTFunctionAssociationTableModel.ADDRESS_COL)
.setPreferredWidth(
VTFunctionAssociationTableModel.ADDRESS_COL_WIDTH); VTFunctionAssociationTableModel.ADDRESS_COL_WIDTH);
destinationTableFilterPanel = destinationTableFilterPanel =

View file

@ -181,7 +181,7 @@ public class FunctionComparisonScreenShots extends GhidraScreenShotGenerator {
waitForSwing(); waitForSwing();
DockingActionIf openTableAction = getAction(plugin, "Add Functions To Comparison"); DockingActionIf openTableAction = getAction(plugin, "Add Functions To Comparison");
performAction(openTableAction); performAction(openTableAction, false);
TableChooserDialog<?> dialog = TableChooserDialog<?> dialog =
waitForDialogComponent(TableChooserDialog.class); waitForDialogComponent(TableChooserDialog.class);