GP-6694 - Functions Window - Added an action to select the row

corresponding to the current function
This commit is contained in:
dragonmacher
2026-04-13 20:58:20 -04:00
parent b82a2b4fc2
commit cc5449d166
4 changed files with 100 additions and 15 deletions
@@ -28,17 +28,27 @@ function's signature. Click on the top of a column to sort the list by that col
<p>Click on a function to navigate to that function in the Code Browser.</p>
<h3><a name="Make_Selection"></a>Make Selection</h3>
<blockquote>
<p>The Functions window has an icon (<img src="Icons.MAKE_SELECTION_ICON">)
on the tool bar to make a selection in the Code Browser. To make a selection,</p>
<ol>
<li>&nbsp;Select the functions in the <b>Functions</b> window.</li>
<li>Right mouse click and select the <img src="Icons.MAKE_SELECTION_ICON"> <b>Make
Selection</b> option, OR select the <img src="Icons.MAKE_SELECTION_ICON">button on
the tool bar.</li>
</ol>
</blockquote>
<H3><A name="Navigate_on_Incoming_Location_Changes"></A>
Navigate on Incoming Location Changes<IMG src="Icons.NAVIGATE_ON_INCOMING_EVENT_ICON"></H3>
<BLOCKQUOTE>
<P>When selected, the Function Table will select the row in the table that corresponds to the
symbol selected in the <A href="help/topics/CodeBrowserPlugin/CodeBrowser.htm">Listing</A>.
</P>
</BLOCKQUOTE>
<h3><a name="Make_Selection"></a>Make Selection</h3>
<blockquote>
<p>The Functions window has an icon (<img src="Icons.MAKE_SELECTION_ICON">)
on the tool bar to make a selection in the Code Browser. To make a selection,</p>
<ol>
<li>&nbsp;Select the functions in the <b>Functions</b> window.</li>
<li>Right mouse click and select the <img src="Icons.MAKE_SELECTION_ICON"> <b>Make
Selection</b> option, OR select the <img src="Icons.MAKE_SELECTION_ICON">button on
the tool bar.</li>
</ol>
</blockquote>
<h3><a name="Function_Comparison"></a><a name="Compare_Selected_Functions"></a>Compare Selected Functions</h3>
<blockquote>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 27 KiB

@@ -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.
@@ -25,6 +25,7 @@ import ghidra.app.plugin.ProgramPlugin;
import ghidra.app.services.FunctionComparisonService;
import ghidra.framework.model.DomainObjectListener;
import ghidra.framework.model.DomainObjectListenerBuilder;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.PluginInfo;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.PluginStatus;
@@ -33,6 +34,7 @@ import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.util.ProgramChangeRecord;
import ghidra.program.util.ProgramLocation;
import ghidra.util.task.SwingUpdateManager;
//@formatter:off
@@ -98,6 +100,16 @@ public class FunctionWindowPlugin extends ProgramPlugin {
}
}
@Override
public void readConfigState(SaveState saveState) {
provider.readConfigState(saveState);
}
@Override
public void writeConfigState(SaveState saveState) {
provider.writeConfigState(saveState);
}
private DomainObjectListener createDomainObjectListener() {
// @formatter:off
return new DomainObjectListenerBuilder(this)
@@ -161,6 +173,11 @@ public class FunctionWindowPlugin extends ProgramPlugin {
provider.programClosed();
}
@Override
protected void locationChanged(ProgramLocation loc) {
provider.locationChanged(loc);
}
Program getProgram() {
return currentProgram;
}
@@ -25,12 +25,13 @@ import javax.swing.table.*;
import docking.ActionContext;
import docking.DefaultActionContext;
import docking.action.DockingAction;
import docking.action.*;
import docking.action.builder.ActionBuilder;
import generic.theme.GIcon;
import ghidra.app.context.FunctionSupplierContext;
import ghidra.app.context.ProgramLocationSupplierContext;
import ghidra.app.services.FunctionComparisonService;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.ComponentProviderAdapter;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.*;
@@ -39,6 +40,7 @@ import ghidra.program.util.ProgramLocation;
import ghidra.util.HelpLocation;
import ghidra.util.table.*;
import ghidra.util.table.actions.MakeProgramSelectionAction;
import resources.Icons;
/**
* Provider that displays all functions in the selected program
@@ -48,6 +50,9 @@ public class FunctionWindowProvider extends ComponentProviderAdapter {
public static final Icon ICON = new GIcon("icon.plugin.functionwindow.provider");
private static final Icon COMPARISON_ICON = new GIcon("icon.plugin.functioncompare.new");
private static final String NAVIGATE_ON_INCOMING_EVENT_KEY = "NAVIGATE_ON_INCOMING_EVENT";
private static final String NAVIGATE_ON_OUTGOING_EVENT_KEY = "NAVIGATE_ON_OUTGOING_EVENT";
private FunctionWindowPlugin plugin;
private GhidraTable functionTable;
private FunctionTableModel functionModel;
@@ -57,6 +62,8 @@ public class FunctionWindowProvider extends ComponentProviderAdapter {
private GhidraThreadedTablePanel<FunctionRowObject> threadedTablePanel;
private DockingAction compareAction;
private ToggleDockingAction navigateIncomingAction;
private SelectionNavigationAction navigateOutgoingAction;
/**
* Constructor
@@ -76,7 +83,22 @@ public class FunctionWindowProvider extends ComponentProviderAdapter {
}
private void createActions() {
addLocalAction(new SelectionNavigationAction(plugin.getName(), getTable()));
String navGroup = "A";
navigateIncomingAction =
new ToggleDockingAction("Navigate on Incoming Location Changes", plugin.getName(),
KeyBindingType.SHARED) {
// stub
};
navigateIncomingAction
.setToolBarData(new ToolBarData(Icons.NAVIGATE_ON_INCOMING_EVENT_ICON, navGroup));
addLocalAction(navigateIncomingAction);
navigateOutgoingAction = new SelectionNavigationAction(plugin.getName(), getTable());
ToolBarData tbData = navigateOutgoingAction.getToolBarData();
tbData.setToolBarGroup(navGroup);
addLocalAction(navigateOutgoingAction);
addLocalAction(new MakeProgramSelectionAction(plugin, getTable()));
}
@@ -109,6 +131,20 @@ public class FunctionWindowProvider extends ComponentProviderAdapter {
service.createComparison(functions);
}
void readConfigState(SaveState saveState) {
boolean navigateIncoming = saveState.getBoolean(NAVIGATE_ON_INCOMING_EVENT_KEY, false);
boolean navigateOutgoing = saveState.getBoolean(NAVIGATE_ON_OUTGOING_EVENT_KEY, false);
navigateIncomingAction.setSelected(navigateIncoming);
navigateOutgoingAction.setSelected(navigateOutgoing);
}
void writeConfigState(SaveState saveState) {
boolean navigateIncoming = navigateIncomingAction.isSelected();
boolean navigateOutgoing = navigateOutgoingAction.isSelected();
saveState.putBoolean(NAVIGATE_ON_INCOMING_EVENT_KEY, navigateIncoming);
saveState.putBoolean(NAVIGATE_ON_OUTGOING_EVENT_KEY, navigateOutgoing);
}
@Override
public void componentHidden() {
functionModel.reload(null);
@@ -217,6 +253,27 @@ public class FunctionWindowProvider extends ComponentProviderAdapter {
}
}
public void locationChanged(ProgramLocation loc) {
if (!navigateIncomingAction.isSelected()) {
return;
}
if (loc == null) {
return;
}
Program p = loc.getProgram();
FunctionManager fm = p.getFunctionManager();
Address address = loc.getAddress();
Function function = fm.getFunctionContaining(address);
if (function == null) {
return;
}
FunctionRowObject ro = new FunctionRowObject(function);
tableFilterPanel.setSelectedItem(ro);
}
/**
* Gathers this function and any functions that thunk it
* @param f the function
@@ -311,4 +368,5 @@ public class FunctionWindowProvider extends ComponentProviderAdapter {
return s.getProgramLocation();
}
}
}