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>
|
||||
|
||||
|
||||
<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
|
||||
Category</H2>
|
||||
|
||||
|
||||
@@ -942,25 +942,83 @@ public abstract class CompositeEditorPanel<T extends Composite, M extends Compos
|
||||
|
||||
@Override
|
||||
public void statusChanged(String message, boolean beep) {
|
||||
if ((message == null) || (message.length() == 0)) {
|
||||
if (StringUtils.isBlank(message)) {
|
||||
message = " ";
|
||||
}
|
||||
|
||||
setStatus(message);
|
||||
if (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) {
|
||||
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<T extends Composite, M extends Compos
|
||||
clsm.setSelectionInterval(viewColumn, viewColumn);
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
// Inner Classes
|
||||
//=================================================================================================
|
||||
|
||||
private class ComponentStringCellEditor extends ComponentCellEditor {
|
||||
public ComponentStringCellEditor(JTextField 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
|
||||
public HelpLocation getHelpLocation() {
|
||||
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 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
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user