mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-07-30 07:18:37 -09:00
Merge remote-tracking branch
'origin/GP-7075-dragonmacher-structure-editor-go-to-next-defined--SQUASHED' (Closes #9376)
This commit is contained in:
@@ -1202,6 +1202,21 @@
|
|||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
||||||
|
<H2><A name="Structure_Editor_Go_To_Next_Defined"></A> Go To Next / Previous Defined Type</H2>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>
|
||||||
|
<B>Go to Next Defined Type</B> and <B>Go to Previous Defined Type</B> 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.
|
||||||
|
</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
||||||
<H2><A name="Structure_Editor_Show_Component_Path"></A> Showing a Component's Data Type
|
<H2><A name="Structure_Editor_Show_Component_Path"></A> Showing a Component's Data Type
|
||||||
Category</H2>
|
Category</H2>
|
||||||
|
|
||||||
|
|||||||
@@ -942,25 +942,83 @@ public abstract class CompositeEditorPanel<T extends Composite, M extends Compos
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void statusChanged(String message, boolean beep) {
|
public void statusChanged(String message, boolean beep) {
|
||||||
if ((message == null) || (message.length() == 0)) {
|
if (StringUtils.isBlank(message)) {
|
||||||
message = " ";
|
message = " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
setStatus(message);
|
setStatus(message);
|
||||||
if (beep) {
|
if (beep) {
|
||||||
getToolkit().beep();
|
getToolkit().beep();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void goToNextDefinedRow(boolean forward) {
|
||||||
|
|
||||||
|
Integer nextRow = findNextDefinedRow(forward);
|
||||||
|
if (nextRow == null) {
|
||||||
|
getToolkit().beep();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
goToRow(nextRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer findNextDefinedRow(boolean forward) {
|
||||||
|
|
||||||
|
int currentRow = Math.max(0, model.getRow());
|
||||||
|
DtcMatcher isUndefined = dtc -> 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) {
|
void search(String searchText, boolean forward) {
|
||||||
searchText = searchText.toLowerCase();
|
searchText = searchText.toLowerCase();
|
||||||
Integer row = forward ? findForward(searchText) : findBackward(searchText);
|
Integer row = forward ? findForward(searchText) : findBackward(searchText);
|
||||||
|
|
||||||
if (row != null) {
|
if (row != null) {
|
||||||
table.getSelectionModel().setSelectionInterval(row, row);
|
goToRow(row);
|
||||||
Rectangle cellRect = table.getCellRect(row, 0, true);
|
|
||||||
table.scrollRectToVisible(cellRect);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Integer findForward(String text) {
|
private Integer findForward(String text) {
|
||||||
@@ -1085,6 +1143,10 @@ public abstract class CompositeEditorPanel<T extends Composite, M extends Compos
|
|||||||
clsm.setSelectionInterval(viewColumn, viewColumn);
|
clsm.setSelectionInterval(viewColumn, viewColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=================================================================================================
|
||||||
|
// Inner Classes
|
||||||
|
//=================================================================================================
|
||||||
|
|
||||||
private class ComponentStringCellEditor extends ComponentCellEditor {
|
private class ComponentStringCellEditor extends ComponentCellEditor {
|
||||||
public ComponentStringCellEditor(JTextField textField) {
|
public ComponentStringCellEditor(JTextField textField) {
|
||||||
super(textField);
|
super(textField);
|
||||||
|
|||||||
@@ -225,6 +225,10 @@ public abstract class CompositeEditorProvider<T extends Composite, M extends Com
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void goToNextDefinedRow(boolean forward) {
|
||||||
|
editorPanel.goToNextDefinedRow(forward);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HelpLocation getHelpLocation() {
|
public HelpLocation getHelpLocation() {
|
||||||
return new HelpLocation(getHelpTopic(), getHelpName());
|
return new HelpLocation(getHelpTopic(), getHelpName());
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.plugin.core.compositeeditor;
|
||||||
|
|
||||||
|
import docking.ActionContext;
|
||||||
|
import docking.action.KeyBindingData;
|
||||||
|
import docking.action.MenuData;
|
||||||
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An action that lets the user jump to the next row that has a defined type.
|
||||||
|
*/
|
||||||
|
public class NextPrevDefinedComponentAction extends CompositeEditorTableAction {
|
||||||
|
|
||||||
|
private boolean forward;
|
||||||
|
|
||||||
|
public NextPrevDefinedComponentAction(CompositeEditorProvider<?, ?> 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";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,6 @@ package ghidra.app.plugin.core.compositeeditor;
|
|||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.action.ToolBarData;
|
|
||||||
import generic.theme.GIcon;
|
import generic.theme.GIcon;
|
||||||
import ghidra.app.services.DataTypeManagerService;
|
import ghidra.app.services.DataTypeManagerService;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
@@ -37,8 +36,6 @@ public class ShowDataTypeInTreeAction extends CompositeEditorTableAction {
|
|||||||
|
|
||||||
public ShowDataTypeInTreeAction(CompositeEditorProvider<?, ?> provider) {
|
public ShowDataTypeInTreeAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, TOOLBAR_GROUP, null /*popupPath*/, null /*menuPath*/, ICON);
|
super(provider, ACTION_NAME, TOOLBAR_GROUP, null /*popupPath*/, null /*menuPath*/, ICON);
|
||||||
|
|
||||||
setToolBarData(new ToolBarData(ICON, TOOLBAR_GROUP));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ public class StructureEditorProvider
|
|||||||
new AddBitFieldAction(this),
|
new AddBitFieldAction(this),
|
||||||
new EditBitFieldAction(this),
|
new EditBitFieldAction(this),
|
||||||
new ShowDataTypeInTreeAction(this),
|
new ShowDataTypeInTreeAction(this),
|
||||||
|
new NextPrevDefinedComponentAction(this, true),
|
||||||
|
new NextPrevDefinedComponentAction(this, false),
|
||||||
|
|
||||||
// new ViewBitFieldAction(this)
|
// new ViewBitFieldAction(this)
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user