Merge remote-tracking branch

'origin/GP-4728-dragonmacher-edit-structure-field--SQUASHED'
(Closes #5717)
This commit is contained in:
Ryan Kurtz 2024-06-28 13:30:11 -04:00
commit c95c7581d7
8 changed files with 152 additions and 34 deletions

View file

@ -54,6 +54,11 @@ public class DefaultDataTypeManagerService extends DefaultDataTypeArchiveService
throw new UnsupportedOperationException();
}
@Override
public void edit(Structure structure, String fieldName) {
throw new UnsupportedOperationException();
}
@Override
public DataType getDataType(String filterText) {
throw new UnsupportedOperationException();

View file

@ -20,8 +20,7 @@ import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.*;
import java.awt.event.*;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.EventObject;
import java.util.*;
import java.util.List;
import javax.swing.*;
@ -218,6 +217,47 @@ public abstract class CompositeEditorPanel extends JPanel
}
}
/**
* Select the field by the given name in this panel's table.
*
* @param fieldName the field name
*/
public void selectField(String fieldName) {
if (!model.isLoaded()) {
return; // disposed; not sure if this can happen
}
// Find the given field by name in the current editor, which, if edited, may not match the
// original data type. If the user has renamed the field, but not saved the editor, then
// we may not find the field.
int row = findRowForFieldName(fieldName);
if (row == -1) {
return;
}
table.getSelectionModel().setSelectionInterval(row, row);
}
private int findRowForFieldName(String fieldName) {
int n = model.getRowCount();
for (int row = 0; row < n; row++) {
DataTypeComponent dtc = model.getComponent(row);
if (dtc != null) {
String dtcFieldName = dtc.getFieldName();
if (Objects.equals(fieldName, dtcFieldName)) {
return row;
}
String defaultName = dtc.getDefaultFieldName();
if (Objects.equals(fieldName, defaultName)) {
return row;
}
}
}
return -1;
}
protected void cancelCellEditing() {
TableCellEditor cellEditor = table.getCellEditor();
if (cellEditor != null) {
@ -1416,5 +1456,4 @@ public abstract class CompositeEditorPanel extends JPanel
KeyBindingUtils.clearKeyBinding(this, keyStroke);
}
}
}

View file

@ -89,4 +89,10 @@ public class StructureEditorProvider extends CompositeEditorProvider {
public String getHelpTopic() {
return "DataTypeEditors";
}
public void selectField(String fieldName) {
if (fieldName != null) {
editorPanel.selectField(fieldName);
}
}
}

View file

@ -492,20 +492,14 @@ public class DataTypeManagerPlugin extends ProgramPlugin
@Override
public void edit(DataType dt) {
DataTypeManager dataTypeManager = dt.getDataTypeManager();
if (dataTypeManager == null) {
throw new IllegalArgumentException(
"DataType " + dt.getPathName() + " has no DataTypeManager! Make sure the " +
"given DataType has been resolved by a DataTypeManager");
}
CategoryPath categoryPath = dt.getCategoryPath();
if (categoryPath == null) {
throw new IllegalArgumentException(
"DataType " + dt.getName() + " has no category path!");
}
editorManager.edit(dt);
}
@Override
public void edit(Structure dt, String fieldName) {
editorManager.edit(dt, fieldName);
}
@Override
public DataTypeManager getBuiltInDataTypesManager() {
return dataTypeManagerHandler.getBuiltInDataTypesManager();

View file

@ -97,17 +97,8 @@ public class DataTypeEditorManager implements EditorListener {
*/
public void edit(DataType dataType) {
DataTypeManager dataTypeManager = dataType.getDataTypeManager();
if (dataTypeManager == null) {
throw new IllegalArgumentException(
"Datatype " + dataType.getName() + " doesn't have a data type manager specified.");
}
EditorProvider editor = getEditor(dataType);
EditorProvider editor = reuseExistingEditor(dataType);
if (editor != null) {
ComponentProvider componentProvider = editor.getComponentProvider();
plugin.getTool().showComponentProvider(componentProvider, true);
componentProvider.toFront();
return;
}
@ -124,12 +115,57 @@ public class DataTypeEditorManager implements EditorListener {
else if (dataType instanceof FunctionDefinition) {
editFunctionSignature((FunctionDefinition) dataType);
}
if (editor == null) {
return;
}
if (editor != null) {
editor.addEditorListener(this);
editorList.add(editor);
}
}
/**
* Displays a data type editor for editing the given Structure. If the structure is is already
* being edited then it is brought to the front. Otherwise, a new editor is created and
* displayed.
* @param structure the structure.
* @param fieldName the optional name of the field to select in the editor.
*/
public void edit(Structure structure, String fieldName) {
StructureEditorProvider editor = (StructureEditorProvider) getEditor(structure);
if (editor != null) {
reuseExistingEditor(structure);
editor.selectField(fieldName);
return;
}
editor = new StructureEditorProvider(plugin, structure,
showStructureNumbersInHex());
editor.selectField(fieldName);
editor.addEditorListener(this);
editorList.add(editor);
}
private EditorProvider reuseExistingEditor(DataType dataType) {
DataTypeManager dataTypeManager = dataType.getDataTypeManager();
if (dataTypeManager == null) {
throw new IllegalArgumentException(
"Datatype " + dataType.getName() + " doesn't have a data type manager specified.");
}
CategoryPath categoryPath = dataType.getCategoryPath();
if (categoryPath == null) {
throw new IllegalArgumentException(
"DataType " + dataType.getName() + " has no category path!");
}
EditorProvider editor = getEditor(dataType);
if (editor != null) {
ComponentProvider componentProvider = editor.getComponentProvider();
plugin.getTool().showComponentProvider(componentProvider, true);
componentProvider.toFront();
}
return editor;
}
private void installEditorActions() {

View file

@ -22,8 +22,7 @@ import javax.swing.tree.TreePath;
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
import ghidra.framework.plugintool.ServiceInfo;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeManagerChangeListener;
import ghidra.program.model.data.*;
import ghidra.util.HelpLocation;
/**
@ -88,14 +87,24 @@ public interface DataTypeManagerService extends DataTypeQueryService, DataTypeAr
public boolean isEditable(DataType dt);
/**
* Pop up an editor dialog for the given data type.
* Pop up an editor window for the given data type.
*
* @param dt data type that either a Structure or a Union; built in types cannot be edited
* @param dt the data type; built in types cannot be edited
* @throws IllegalArgumentException if the given has not been resolved by a DataTypeManager;
* in other words, if {@link DataType#getDataTypeManager()} returns null.
* in other words, if {@link DataType#getDataTypeManager()} returns null
*/
public void edit(DataType dt);
/**
* Pop up an editor window for the given structure.
*
* @param structure the structure
* @param fieldName the optional structure field name to select in the editor window
* @throws IllegalArgumentException if the given has not been resolved by a DataTypeManager;
* in other words, if {@link DataType#getDataTypeManager()} returns null
*/
public void edit(Structure structure, String fieldName);
/**
* Selects the given data type in the display of data types. A null <code>dataType</code>
* value will clear the current selection.

View file

@ -99,6 +99,11 @@ public class TestDoubleDataTypeManagerService implements DataTypeManagerService
throw new UnsupportedOperationException();
}
@Override
public void edit(Structure structure, String fieldName) {
throw new UnsupportedOperationException();
}
@Override
public void closeArchive(DataTypeManager dtm) {
throw new UnsupportedOperationException();

View file

@ -17,14 +17,16 @@ package ghidra.app.plugin.core.decompile.actions;
import docking.ActionContext;
import docking.action.MenuData;
import ghidra.app.decompiler.ClangFieldToken;
import ghidra.app.decompiler.ClangToken;
import ghidra.app.decompiler.component.DecompilerPanel;
import ghidra.app.decompiler.component.DecompilerUtils;
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.HelpTopics;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.Function;
import ghidra.util.HelpLocation;
import ghidra.util.UndefinedFunction;
@ -74,9 +76,31 @@ public class EditDataTypeAction extends AbstractDecompilerAction {
if (baseDtDTM != dataTypeManager) {
baseDataType = baseDataType.clone(dataTypeManager);
}
final DataTypeManagerService service =
DataTypeManagerService service =
context.getTool().getService(DataTypeManagerService.class);
if (dataType instanceof Structure structure) {
editStructure(service, structure, context);
}
else {
service.edit(baseDataType);
}
}
private void editStructure(DataTypeManagerService service, Structure structure,
DecompilerActionContext context) {
DecompilerPanel decompilerPanel = context.getDecompilerPanel();
ClangToken tokenAtCursor = decompilerPanel.getTokenAtCursor();
if (tokenAtCursor instanceof ClangFieldToken) {
String fieldName = tokenAtCursor.getText();
if (fieldName != null) {
service.edit(structure, fieldName);
return;
}
}
service.edit(structure);
}
}