Merge remote-tracking branch 'origin/Ghidra_12.0'

This commit is contained in:
Ryan Kurtz 2025-09-17 12:12:00 -04:00
commit 5bad4f187d
10 changed files with 117 additions and 37 deletions

View file

@ -481,22 +481,23 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
action = new GotoNextFunctionAction(tool, plugin.getName()); action = new GotoNextFunctionAction(tool, plugin.getName());
tool.addAction(action); tool.addAction(action);
toggleVariablesAction = new ToggleActionBuilder("Show Function Variables", plugin.getName()) toggleVariablesAction =
.popupMenuPath("Show/Hide All Variables") new ToggleActionBuilder("Show All Function Variables", plugin.getName())
.popupMenuGroup("Variables") .popupMenuPath("Function", "Show/Hide All Variables")
.helpLocation(new HelpLocation("CodeBrowserPlugin", "Show_All_Variables")) .popupMenuGroup("Variables")
.selected(true) .helpLocation(new HelpLocation("CodeBrowserPlugin", "Show_All_Variables"))
.withContext(ProgramLocationActionContext.class) .selected(true)
.enabledWhen(this::isInFunctionArea) .withContext(ProgramLocationActionContext.class)
.onAction(c -> showVariablesForAllFunctions(toggleVariablesAction.isSelected())) .onAction(c -> showVariablesForAllFunctions(toggleVariablesAction.isSelected()))
.buildAndInstallLocal(this); .buildAndInstallLocal(this);
new ActionBuilder("Toggle Show Function Variables", plugin.getName()) new ActionBuilder("Toggle Show Function Variables", plugin.getName())
.popupMenuPath("Show/Hide Variables") .popupMenuPath("Function", "Show/Hide Variables")
.popupMenuGroup("Variables") .popupMenuGroup("Variables")
.helpLocation(new HelpLocation("CodeBrowserPlugin", "Show_Variables")) .helpLocation(new HelpLocation("CodeBrowserPlugin", "Show_Variables"))
.keyBinding("SPACE") .keyBinding("SPACE")
.withContext(ProgramLocationActionContext.class) .withContext(ProgramLocationActionContext.class)
.validWhen(this::isInFunctionArea)
.enabledWhen(this::isInFunctionArea) .enabledWhen(this::isInFunctionArea)
.onAction(c -> toggleShowVariables(c.getAddress())) .onAction(c -> toggleShowVariables(c.getAddress()))
.buildAndInstallLocal(this); .buildAndInstallLocal(this);

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -42,7 +42,8 @@ public class CollapseAllDataAction extends ProgramLocationContextAction {
super("Collapse All Data", provider.getOwner()); super("Collapse All Data", provider.getOwner());
this.provider = provider; this.provider = provider;
setPopupMenuData(new MenuData(new String[] { "Collapse All Data" }, null, "Structure")); setPopupMenuData(
new MenuData(new String[] { "Data", "Collapse All Data" }, null, "BasicData2"));
setHelpLocation(new HelpLocation("CodeBrowserPlugin", "ExpandCollapseActions")); setHelpLocation(new HelpLocation("CodeBrowserPlugin", "ExpandCollapseActions"));

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -39,7 +39,8 @@ public class ExpandAllDataAction extends ProgramLocationContextAction {
super("Expand All Data", provider.getOwner()); super("Expand All Data", provider.getOwner());
this.provider = provider; this.provider = provider;
setPopupMenuData(new MenuData(new String[] { "Expand All Data" }, null, "Structure")); setPopupMenuData(
new MenuData(new String[] { "Data", "Expand All Data" }, null, "BasicData2"));
setDescription("Open all data recursively from the current location downward."); setDescription("Open all data recursively from the current location downward.");
setHelpLocation(new HelpLocation("CodeBrowserPlugin", "ExpandCollapseActions")); setHelpLocation(new HelpLocation("CodeBrowserPlugin", "ExpandCollapseActions"));
@ -83,11 +84,11 @@ public class ExpandAllDataAction extends ProgramLocationContextAction {
private void updatePopupMenuName(boolean hasSelection) { private void updatePopupMenuName(boolean hasSelection) {
if (hasSelection) { if (hasSelection) {
getPopupMenuData().setMenuPath(new String[] { "Expand All Data In Selection" }); getPopupMenuData().setMenuPath(new String[] { "Data", "Expand All Data In Selection" });
setDescription("Open all data recursively in the current selection."); setDescription("Open all data recursively in the current selection.");
} }
else { else {
getPopupMenuData().setMenuPath(new String[] { "Expand All Data" }); getPopupMenuData().setMenuPath(new String[] { "Data", "Expand All Data" });
setDescription("Open all data recursively from the current location downward."); setDescription("Open all data recursively from the current location downward.");
} }
} }

View file

@ -42,7 +42,8 @@ public class ToggleExpandCollapseDataAction extends ProgramLocationContextAction
this.provider = provider; this.provider = provider;
setPopupMenuData( setPopupMenuData(
new MenuData(new String[] { "Toggle Expand/Collapse Data" }, null, "Structure")); new MenuData(new String[] { "Data", "Toggle Expand/Collapse Data" }, null,
"BasicData2"));
setKeyBindingData(new KeyBindingData(' ', 0)); setKeyBindingData(new KeyBindingData(' ', 0));
setHelpLocation(new HelpLocation("CodeBrowserPlugin", "ExpandCollapseActions")); setHelpLocation(new HelpLocation("CodeBrowserPlugin", "ExpandCollapseActions"));

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -83,7 +83,7 @@ public class FieldFormatModel {
} }
/** /**
* Returns the formatMgr that is managing this model. * {@return the FormatManager managing this format.}
*/ */
public FormatManager getFormatManager() { public FormatManager getFormatManager() {
return formatMgr; return formatMgr;
@ -109,6 +109,7 @@ public class FieldFormatModel {
/** /**
* Adds new empty row at the given position. The position must be in the * Adds new empty row at the given position. The position must be in the
* interval [0,numRows]. * interval [0,numRows].
* @param index the index to add a new row
* @exception IllegalArgumentException thrown if the position is outside the * @exception IllegalArgumentException thrown if the position is outside the
* interval [0,numRows]. * interval [0,numRows].
*/ */
@ -186,21 +187,23 @@ public class FieldFormatModel {
} }
/** /**
* Returns the number of rows in the model. * {@return the number of rows in this format}
*/ */
public int getNumRows() { public int getNumRows() {
return rows.size(); return rows.size();
} }
/** /**
* Returns the name of this format model. * {@return the name of this format model.}
*/ */
public String getName() { public String getName() {
return name; return name;
} }
/** /**
* Returns the number of FieldFactorys on any given row. * Returns the number of factories on the given row.
* @param row the row to get the number of factories for
* @return the number of factories on the given row
*/ */
public int getNumFactorys(int row) { public int getNumFactorys(int row) {
if ((row < 0) || (row >= rows.size())) { if ((row < 0) || (row >= rows.size())) {
@ -210,14 +213,16 @@ public class FieldFormatModel {
} }
/** /**
* Returns the FieldFactorys on a given row. * Returns the factories on the given row.
* @param row the row to factories for
* @return the FieldFactorys for a given row
*/ */
public FieldFactory[] getFactorys(int row) { public FieldFactory[] getFactorys(int row) {
return (rows.get(row)).getFactorys(); return (rows.get(row)).getFactorys();
} }
/** /**
* Returns the list factories valid for this format. * {@return the list of factories used in this format.}
*/ */
public FieldFactory[] getFactorys() { public FieldFactory[] getFactorys() {
return factories.clone(); return factories.clone();
@ -251,7 +256,7 @@ public class FieldFormatModel {
} }
/** /**
* Returns the width of this model * {@return the width of this format.}
*/ */
public int getWidth() { public int getWidth() {
return width; return width;
@ -280,6 +285,7 @@ public class FieldFormatModel {
/** /**
* Saves this format to XML. * Saves this format to XML.
* @return the XML element for the saved format
*/ */
public Element saveToXml() { public Element saveToXml() {
Element root = new Element("FORMAT"); Element root = new Element("FORMAT");

View file

@ -959,6 +959,9 @@ public class FormatManager implements OptionsChangeListener {
for (int i = 0; i < NUM_MODELS; i++) { for (int i = 0; i < NUM_MODELS; i++) {
if (saveState.hasValue(models[i].getName())) { if (saveState.hasValue(models[i].getName())) {
models[i].restoreFromXml(saveState.getXmlElement(models[i].getName())); models[i].restoreFromXml(saveState.getXmlElement(models[i].getName()));
// hack to make sure the new open/close variables field is present
// If missing, we are just going to reset it to the default format
checkForMissingOpenCloseField(models[i]);
} }
else { else {
models[i].restoreFromXml(getDefaultModel(i)); models[i].restoreFromXml(getDefaultModel(i));
@ -968,6 +971,27 @@ public class FormatManager implements OptionsChangeListener {
modelChanged(null); modelChanged(null);
} }
// This is a hack to make sure the new variables open/close field is present.
// This was added in version 12.0 and can probably be removed in a few releases.
private void checkForMissingOpenCloseField(FieldFormatModel model) {
if (!model.getName().equals("Variable")) {
return;
}
if (!hasField(model, "+")) {
model.restoreFromXml(getDefaultVariableFormat());
}
}
private boolean hasField(FieldFormatModel model, String fieldName) {
FieldFactory[] unusedFactories = model.getUnusedFactories();
for (FieldFactory fieldFactory : unusedFactories) {
if (fieldFactory.getFieldName().equals("+")) {
return false;
}
}
return true;
}
public ServiceProvider getServiceProvider() { public ServiceProvider getServiceProvider() {
return serviceProvider; return serviceProvider;
} }

View file

@ -47,7 +47,7 @@ import ghidra.util.task.TaskMonitor;
* Component Provider for displaying lists of {@link QuickFix}s and the actions to execute them * Component Provider for displaying lists of {@link QuickFix}s and the actions to execute them
* in bulk or individually. * in bulk or individually.
*/ */
public class QuckFixTableProvider extends ComponentProvider { public class QuickFixTableProvider extends ComponentProvider {
private static final Icon EXECUTE_ICON = new GIcon("icon.base.plugin.quickfix.done"); private static final Icon EXECUTE_ICON = new GIcon("icon.base.plugin.quickfix.done");
private JComponent component; private JComponent component;
private QuickFixTableModel tableModel; private QuickFixTableModel tableModel;
@ -57,7 +57,7 @@ public class QuckFixTableProvider extends ComponentProvider {
private ToggleDockingAction toggleAutoDeleteAction; private ToggleDockingAction toggleAutoDeleteAction;
private boolean autoDelete; private boolean autoDelete;
public QuckFixTableProvider(PluginTool tool, String title, String owner, Program program, public QuickFixTableProvider(PluginTool tool, String title, String owner, Program program,
TableDataLoader<QuickFix> loader) { TableDataLoader<QuickFix> loader) {
super(tool, title, owner); super(tool, title, owner);
setIcon(new GIcon("icon.plugin.table.service")); setIcon(new GIcon("icon.plugin.table.service"));
@ -168,7 +168,7 @@ public class QuckFixTableProvider extends ComponentProvider {
if (e.getValueIsAdjusting()) { if (e.getValueIsAdjusting()) {
return; return;
} }
dockingTool.contextChanged(QuckFixTableProvider.this); dockingTool.contextChanged(QuickFixTableProvider.this);
}); });
table.setActionsEnabled(true); table.setActionsEnabled(true);
@ -314,7 +314,7 @@ public class QuckFixTableProvider extends ComponentProvider {
//================================================================================================== //==================================================================================================
private class QuickFixActionContext extends DefaultActionContext { private class QuickFixActionContext extends DefaultActionContext {
QuickFixActionContext() { QuickFixActionContext() {
super(QuckFixTableProvider.this, table); super(QuickFixTableProvider.this, table);
} }
public int getSelectedRowCount() { public int getSelectedRowCount() {

View file

@ -26,10 +26,10 @@ import ghidra.util.HelpLocation;
import ghidra.util.Msg; import ghidra.util.Msg;
/** /**
* Subclass of the {@link QuckFixTableProvider} that customizes it specifically for search and replace * Subclass of the {@link QuickFixTableProvider} that customizes it specifically for search and replace
* operations. * operations.
*/ */
public class SearchAndReplaceProvider extends QuckFixTableProvider { public class SearchAndReplaceProvider extends QuickFixTableProvider {
private SearchAndReplacePlugin plugin; private SearchAndReplacePlugin plugin;
private SearchAndReplaceQuery query; private SearchAndReplaceQuery query;

View file

@ -18,6 +18,7 @@ package docking.actions;
import docking.*; import docking.*;
import docking.action.DockingActionIf; import docking.action.DockingActionIf;
import docking.tool.ToolConstants; import docking.tool.ToolConstants;
import docking.widgets.filechooser.GhidraFileChooser;
import docking.widgets.table.GTable; import docking.widgets.table.GTable;
import docking.widgets.tree.GTree; import docking.widgets.tree.GTree;
@ -36,11 +37,11 @@ public class SharedActionRegistry {
*/ */
public static void installSharedActions(Tool tool, ToolActions toolActions) { public static void installSharedActions(Tool tool, ToolActions toolActions) {
GTable.createSharedActions(tool, toolActions, ToolConstants.SHARED_OWNER); GTable.createSharedActions(tool, toolActions, ToolConstants.SHARED_OWNER);
GTree.createSharedActions(tool, toolActions, ToolConstants.SHARED_OWNER); GTree.createSharedActions(tool, toolActions, ToolConstants.SHARED_OWNER);
DialogComponentProvider.createSharedActions(tool, toolActions, ToolConstants.SHARED_OWNER); DialogComponentProvider.createSharedActions(tool, toolActions, ToolConstants.SHARED_OWNER);
DockingWindowManager.createSharedActions(tool, toolActions, ToolConstants.SHARED_OWNER); DockingWindowManager.createSharedActions(tool, toolActions, ToolConstants.SHARED_OWNER);
GhidraFileChooser.registerSharedActions(tool, toolActions);
} }
} }

View file

@ -40,7 +40,7 @@ import docking.*;
import docking.action.DockingAction; import docking.action.DockingAction;
import docking.action.DockingActionIf; import docking.action.DockingActionIf;
import docking.action.builder.ActionBuilder; import docking.action.builder.ActionBuilder;
import docking.actions.KeyBindingUtils; import docking.actions.*;
import docking.menu.DockingToolBarUtils; import docking.menu.DockingToolBarUtils;
import docking.widgets.*; import docking.widgets.*;
import docking.widgets.combobox.GComboBox; import docking.widgets.combobox.GComboBox;
@ -87,6 +87,10 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
*/ */
private static final int BIG_DATA_THRESHOLD = 200; private static final int BIG_DATA_THRESHOLD = 200;
private static final String ACTION_NAME_BACK = "Last Folder Visited";
private static final String ACTION_NAME_FORWARD = "Previous Folder Visited";
private static final String ACTION_NAME_UP = "Up One Level";
static final String UP_BUTTON_NAME = "UP_BUTTON"; static final String UP_BUTTON_NAME = "UP_BUTTON";
private static final Color FOREROUND_COLOR = new GColor("color.fg.filechooser"); private static final Color FOREROUND_COLOR = new GColor("color.fg.filechooser");
private static final Color BACKGROUND_COLOR = new GColor("color.bg.filechooser"); private static final Color BACKGROUND_COLOR = new GColor("color.bg.filechooser");
@ -285,16 +289,19 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
String owner = getClass().getSimpleName(); String owner = getClass().getSimpleName();
upAction = new ActionBuilder("Up One Level", owner) upAction = new ActionBuilder("Up One Level", owner)
.sharedKeyBinding()
.keyBinding("Alt Up") .keyBinding("Alt Up")
.onAction(c -> goUp()) .onAction(c -> goUp())
.build(); .build();
backAction = new ActionBuilder("Last Folder Visited", owner) backAction = new ActionBuilder("Last Folder Visited", owner)
.sharedKeyBinding()
.keyBinding("Alt Left") .keyBinding("Alt Left")
.onAction(c -> goBack()) .onAction(c -> goBack())
.build(); .build();
forwardAction = new ActionBuilder("Previous Folder Visited", owner) forwardAction = new ActionBuilder("Previous Folder Visited", owner)
.sharedKeyBinding()
.keyBinding("Alt Right") .keyBinding("Alt Right")
.onAction(c -> goForward()) .onAction(c -> goForward())
.build(); .build();
@ -310,6 +317,18 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
updateNavigationButtonToolTips(); updateNavigationButtonToolTips();
} }
public static void registerSharedActions(Tool tool, ToolActions toolActions) {
toolActions.registerSharedActionPlaceholder(
new GfcActionPlaceholder(ACTION_NAME_BACK, "Alt Left"));
toolActions.registerSharedActionPlaceholder(
new GfcActionPlaceholder(ACTION_NAME_FORWARD, "Alt Right"));
toolActions.registerSharedActionPlaceholder(
new GfcActionPlaceholder(ACTION_NAME_UP, "Alt Up"));
}
private JComponent buildWorkPanel() { private JComponent buildWorkPanel() {
buildWaitPanel(); buildWaitPanel();
@ -2530,4 +2549,30 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
} }
// A class that allows us to register actions and keybindings before this dialog is instantiated
private static class GfcActionPlaceholder implements SharedDockingActionPlaceholder {
private String name;
private String keyBinding;
GfcActionPlaceholder(String name, String keyBinding) {
this.name = name;
this.keyBinding = keyBinding;
}
@Override
public String getName() {
return name;
}
@Override
public KeyStroke getKeyBinding() {
return KeyBindingUtils.parseKeyStroke(keyBinding);
}
@Override
public String getOwner() {
return GhidraFileChooser.class.getSimpleName();
}
}
} }