From b490ac5e635667a1d14678cb9a2134bf14211bb7 Mon Sep 17 00:00:00 2001
From: dragonmacher <48328597+dragonmacher@users.noreply.github.com>
Date: Tue, 21 Jul 2026 13:22:05 -0400
Subject: [PATCH] GP-7075 - Structure Editor - Added actions to jump to the
next row with a defined data type
---
.../DataTypeEditors/StructureEditor.htm | 15 ++++
.../compositeeditor/CompositeEditorPanel.java | 72 +++++++++++++++++--
.../CompositeEditorProvider.java | 4 ++
.../NextPrevDefinedComponentAction.java | 53 ++++++++++++++
.../ShowDataTypeInTreeAction.java | 3 -
.../StructureEditorProvider.java | 2 +
6 files changed, 141 insertions(+), 8 deletions(-)
create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/NextPrevDefinedComponentAction.java
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeEditors/StructureEditor.htm b/Ghidra/Features/Base/src/main/help/help/topics/DataTypeEditors/StructureEditor.htm
index 510a020979..2b0c9c4cf0 100644
--- a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeEditors/StructureEditor.htm
+++ b/Ghidra/Features/Base/src/main/help/help/topics/DataTypeEditors/StructureEditor.htm
@@ -1202,6 +1202,21 @@
+
+
Go To Next / Previous Defined Type
+
+
+
+ Go to Next Defined Type and Go to Previous Defined Type are
+ available from the popup menu. They allow you to jump to the next row that has a
+ defined data type. This is useful when dealing with structures that have long runs of
+ undfined types used for padding. If you invoke the action on a row that already has a
+ defined data type, then the action will first find the next row with an undefined type and
+ start the search from there.
+
+
+
+
Showing a Component's Data Type
Category
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java
index 72d9fb9b50..f475d55194 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java
@@ -942,25 +942,83 @@ public abstract class CompositeEditorPanel isUndefined(dtc);
+ int undefinedRow = findNextMatchingDtc(currentRow, forward, isUndefined);
+ int startRow = undefinedRow + (forward ? 1 : -1);
+ int n = model.getRowCount();
+ if (startRow >= n) {
+ return null;
+ }
+
+ DtcMatcher isDefined = dtc -> !isUndefined(dtc);
+ return findNextMatchingDtc(startRow, forward, isDefined);
+ }
+
+ private int findNextMatchingDtc(int row, boolean forward, DtcMatcher matcher) {
+
+ int start = row;
+ int end = forward ? model.getRowCount() : -1;
+ int direction = forward ? 1 : -1;
+ for (int i = start; i != end; i += direction) {
+ DataTypeComponent dtc = model.getComponent(i);
+ if (matcher.matches(dtc)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ // just a nicer predicate
+ private interface DtcMatcher {
+ public boolean matches(DataTypeComponent dtc);
+ }
+
+ private boolean isUndefined(DataTypeComponent dtc) {
+ if (dtc == null) {
+ return true;
+ }
+
+ DataType dt = dtc.getDataType();
+ return Undefined.isUndefined(dt);
+ }
+
+ private void goToRow(int row) {
+ table.getSelectionModel().setSelectionInterval(row, row);
+ Rectangle cellRect = table.getCellRect(row, 0, true);
+ table.scrollRectToVisible(cellRect);
+ }
+
void search(String searchText, boolean forward) {
searchText = searchText.toLowerCase();
Integer row = forward ? findForward(searchText) : findBackward(searchText);
if (row != null) {
- table.getSelectionModel().setSelectionInterval(row, row);
- Rectangle cellRect = table.getCellRect(row, 0, true);
- table.scrollRectToVisible(cellRect);
+ goToRow(row);
}
-
}
private Integer findForward(String text) {
@@ -1085,6 +1143,10 @@ public abstract class CompositeEditorPanel provider, boolean forward) {
+ super(provider, getName(forward));
+
+ this.forward = forward;
+
+ MenuData data = new MenuData(new String[] { getName(forward) });
+ data.setMenuGroup(BASIC_ACTION_GROUP + "_2"); // put below the basic action group
+ setPopupMenuData(data);
+
+ setKeyBindingData(new KeyBindingData(forward ? "Control Down" : "Control Up"));
+
+ setHelpLocation(
+ new HelpLocation(provider.getHelpTopic(), "Structure_Editor_Go_To_Next_Defined"));
+ }
+
+ @Override
+ public void actionPerformed(ActionContext context) {
+ provider.goToNextDefinedRow(forward);
+ }
+
+ private static String getName(boolean forward) {
+ return "Go to " + (forward ? "Next" : "Previous") + " Defined Type";
+ }
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ShowDataTypeInTreeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ShowDataTypeInTreeAction.java
index 2e6ed2bed1..5a6110b163 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ShowDataTypeInTreeAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ShowDataTypeInTreeAction.java
@@ -18,7 +18,6 @@ package ghidra.app.plugin.core.compositeeditor;
import javax.swing.Icon;
import docking.ActionContext;
-import docking.action.ToolBarData;
import generic.theme.GIcon;
import ghidra.app.services.DataTypeManagerService;
import ghidra.program.model.data.*;
@@ -37,8 +36,6 @@ public class ShowDataTypeInTreeAction extends CompositeEditorTableAction {
public ShowDataTypeInTreeAction(CompositeEditorProvider, ?> provider) {
super(provider, ACTION_NAME, TOOLBAR_GROUP, null /*popupPath*/, null /*menuPath*/, ICON);
-
- setToolBarData(new ToolBarData(ICON, TOOLBAR_GROUP));
}
@Override
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorProvider.java
index a69b9c6f51..c227ef4ee8 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorProvider.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorProvider.java
@@ -85,6 +85,8 @@ public class StructureEditorProvider
new AddBitFieldAction(this),
new EditBitFieldAction(this),
new ShowDataTypeInTreeAction(this),
+ new NextPrevDefinedComponentAction(this, true),
+ new NextPrevDefinedComponentAction(this, false),
// new ViewBitFieldAction(this)
};