GP-1899 Corrected bit-field component and editor issues for structure

editor
This commit is contained in:
ghidra1 2024-07-24 14:32:57 -04:00
parent d7c7fc0a99
commit 02b0dfe5d1
8 changed files with 134 additions and 110 deletions

View file

@ -15,17 +15,9 @@
*/ */
package ghidra.app.plugin.core.compositeeditor; package ghidra.app.plugin.core.compositeeditor;
import java.awt.Component;
import docking.ActionContext; import docking.ActionContext;
import docking.DockingWindowManager;
import ghidra.program.model.data.Structure;
import ghidra.util.exception.AssertException; import ghidra.util.exception.AssertException;
/**
* Action for use in the composite data type editor.
* This action has help associated with it.
*/
public class AddBitFieldAction extends CompositeEditorTableAction { public class AddBitFieldAction extends CompositeEditorTableAction {
public final static String ACTION_NAME = "Add Bitfield"; public final static String ACTION_NAME = "Add Bitfield";
@ -45,33 +37,17 @@ public class AddBitFieldAction extends CompositeEditorTableAction {
@Override @Override
public void actionPerformed(ActionContext context) { public void actionPerformed(ActionContext context) {
StructureEditorProvider structProvider = (StructureEditorProvider) provider;
CompEditorModel editorModel = (CompEditorModel) model; structProvider.showAddBitFieldEditor();
if (editorModel.getNumSelectedRows() != 1) {
return;
}
int rowIndex = model.getSelectedRows()[0];
BitFieldEditorDialog dlg =
new BitFieldEditorDialog(editorModel.viewComposite, provider.dtmService,
-(rowIndex + 1), model.showHexNumbers,
ordinal -> refreshTableAndSelection(editorModel, ordinal));
Component c = provider.getComponent();
DockingWindowManager.showDialog(c, dlg);
requestTableFocus();
}
private void refreshTableAndSelection(CompEditorModel editorModel, int ordinal) {
editorModel.notifyCompositeChanged();
} }
@Override @Override
public void adjustEnablement() { public void adjustEnablement() {
boolean enabled = true; boolean enabled = true;
CompEditorModel editorModel = (CompEditorModel) model; CompEditorModel editorModel = (CompEditorModel) model;
// Union do not support non-packed placement of bitfields // Unions do not support non-packed manipulation of bitfields
if (!(editorModel.viewComposite instanceof Structure) || editorModel.isPackingEnabled() || if (!(provider instanceof StructureEditorProvider structProvider) ||
editorModel.getNumSelectedRows() != 1) { editorModel.isPackingEnabled() || editorModel.getNumSelectedRows() != 1) {
enabled = false; enabled = false;
} }
setEnabled(enabled); setEnabled(enabled);

View file

@ -171,6 +171,8 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable {
if (!editUseEnabled && composite != null) { if (!editUseEnabled && composite != null) {
allocationByteSize = composite.getLength(); allocationByteSize = composite.getLength();
} }
setBounds(0, 0, getPreferredWidth(), getPreferredHeight());
invalidate();
init(null); init(null);
} }
@ -315,8 +317,8 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable {
* (allocation unit size is determine by current {@link #allocationByteSize}). * (allocation unit size is determine by current {@link #allocationByteSize}).
*/ */
void refresh(int bitSize, int bitOffset) { void refresh(int bitSize, int bitOffset) {
bitFieldAllocation = new BitFieldAllocation(bitSize, bitOffset);
updatePreferredSize(); updatePreferredSize();
bitFieldAllocation = new BitFieldAllocation(bitSize, bitOffset);
repaint(); repaint();
} }
@ -333,8 +335,8 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable {
void refresh(int byteSize, int byteOffset, int bitSize, int bitOffset) { void refresh(int byteSize, int byteOffset, int bitSize, int bitOffset) {
this.allocationByteOffset = byteOffset; this.allocationByteOffset = byteOffset;
this.allocationByteSize = byteSize; this.allocationByteSize = byteSize;
bitFieldAllocation = new BitFieldAllocation(bitSize, bitOffset);
updatePreferredSize(); updatePreferredSize();
bitFieldAllocation = new BitFieldAllocation(bitSize, bitOffset);
repaint(); repaint();
} }
@ -1030,6 +1032,14 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable {
rightChopBytes = rightChop; rightChopBytes = rightChop;
allocationBytes = allocationByteSize - leftChopBytes - rightChopBytes; allocationBytes = allocationByteSize - leftChopBytes - rightChopBytes;
if (allocationBytes <= 0) {
int junk = 0;
// allocation shrunk - need to adjust window
// TODO: Need to adjust view port sizing when allocationByteSize changes
}
allocateBits(); allocateBits();
layoutBits(); layoutBits();
} }

View file

@ -281,6 +281,7 @@ public abstract class CompositeEditorPanel extends JPanel
if (cellEditor != null) { if (cellEditor != null) {
cellEditor.cancelCellEditing(); cellEditor.cancelCellEditing();
} }
provider.closeDependentEditors();
} }
protected void stopCellEditing() { protected void stopCellEditing() {
@ -545,7 +546,7 @@ public abstract class CompositeEditorPanel extends JPanel
} }
} }
public void dataTypeManagerRestored() { protected void dataTypeManagerRestored() {
DataTypeManager originalDTM = model.getOriginalDataTypeManager(); DataTypeManager originalDTM = model.getOriginalDataTypeManager();
if (originalDTM == null) { if (originalDTM == null) {
// editor unloaded // editor unloaded

View file

@ -21,6 +21,7 @@ import javax.swing.*;
import docking.*; import docking.*;
import docking.widgets.OptionDialog; import docking.widgets.OptionDialog;
import docking.widgets.table.GTable;
import generic.theme.GIcon; import generic.theme.GIcon;
import ghidra.app.context.ProgramActionContext; import ghidra.app.context.ProgramActionContext;
import ghidra.app.services.DataTypeManagerService; import ghidra.app.services.DataTypeManagerService;
@ -338,4 +339,23 @@ public abstract class CompositeEditorProvider extends ComponentProviderAdapter
help.registerHelp(object, new HelpLocation(getHelpTopic(), getHelpName() + "_" + anchor)); help.registerHelp(object, new HelpLocation(getHelpTopic(), getHelpName() + "_" + anchor));
} }
protected void requestTableFocus() {
JTable table = editorPanel.getTable();
if (!table.isEditing()) {
table.requestFocus();
return;
}
if (table instanceof GTable gTable) {
gTable.requestTableEditorFocus();
}
else {
table.getEditorComponent().requestFocus();
}
}
protected void closeDependentEditors() {
// do nothing by default
}
} }

View file

@ -20,7 +20,6 @@ import java.awt.event.ActionListener;
import javax.swing.*; import javax.swing.*;
import docking.action.*; import docking.action.*;
import docking.widgets.table.GTable;
import ghidra.framework.plugintool.Plugin; import ghidra.framework.plugintool.Plugin;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
@ -88,21 +87,8 @@ abstract public class CompositeEditorTableAction extends DockingAction implement
} }
protected void requestTableFocus() { protected void requestTableFocus() {
if (provider == null) { if (provider != null) {
return; // must have been disposed provider.requestTableFocus();
}
JTable table = ((CompositeEditorPanel) provider.getComponent()).getTable();
if (!table.isEditing()) {
table.requestFocus();
return;
}
if (table instanceof GTable gTable) {
gTable.requestTableEditorFocus();
}
else {
table.getEditorComponent().requestFocus();
} }
} }

View file

@ -15,14 +15,7 @@
*/ */
package ghidra.app.plugin.core.compositeeditor; package ghidra.app.plugin.core.compositeeditor;
import java.awt.Component;
import javax.swing.JTable;
import docking.ActionContext; import docking.ActionContext;
import docking.DockingWindowManager;
import ghidra.program.model.data.DataTypeComponent;
import ghidra.program.model.data.Structure;
import ghidra.util.exception.AssertException; import ghidra.util.exception.AssertException;
public class EditBitFieldAction extends CompositeEditorTableAction { public class EditBitFieldAction extends CompositeEditorTableAction {
@ -41,50 +34,18 @@ public class EditBitFieldAction extends CompositeEditorTableAction {
adjustEnablement(); adjustEnablement();
} }
private DataTypeComponent getUnalignedBitFieldComponent() {
CompEditorModel editorModel = (CompEditorModel) model;
if ((editorModel.viewComposite instanceof Structure) &&
!editorModel.viewComposite.isPackingEnabled() &&
editorModel.getNumSelectedRows() == 1) {
int rowIndex = model.getSelectedRows()[0];
if (rowIndex < model.getNumComponents()) {
DataTypeComponent dtComponent = model.getComponent(rowIndex);
if (dtComponent.isBitFieldComponent()) {
return dtComponent;
}
}
}
return null;
}
@Override @Override
public void actionPerformed(ActionContext context) { public void actionPerformed(ActionContext context) {
StructureEditorProvider structProvider = (StructureEditorProvider) provider;
CompEditorModel editorModel = (CompEditorModel) model; structProvider.showBitFieldEditor();
DataTypeComponent dtComponent = getUnalignedBitFieldComponent();
if (dtComponent == null) {
return;
}
BitFieldEditorDialog dlg = new BitFieldEditorDialog(editorModel.viewComposite,
provider.dtmService, dtComponent.getOrdinal(), model.showHexNumbers,
ordinal -> refreshTableAndSelection(editorModel, ordinal));
Component c = provider.getComponent();
DockingWindowManager.showDialog(c, dlg);
requestTableFocus();
}
private void refreshTableAndSelection(CompEditorModel editorModel, int ordinal) {
editorModel.fireTableDataChanged();
editorModel.compositeInfoChanged();
JTable editorTable = provider.getTable();
editorTable.getSelectionModel().setSelectionInterval(ordinal, ordinal);
} }
@Override @Override
public void adjustEnablement() { public void adjustEnablement() {
setEnabled(getUnalignedBitFieldComponent() != null); // Unions do not support non-packed manipulation of bitfields
boolean enabled = (provider instanceof StructureEditorProvider structProvider) &&
structProvider.getSelectedNonPackedBitFieldComponent() != null;
setEnabled(enabled);
} }
} }

View file

@ -17,15 +17,20 @@ package ghidra.app.plugin.core.compositeeditor;
import javax.swing.Icon; import javax.swing.Icon;
import docking.DockingWindowManager;
import generic.theme.GIcon; import generic.theme.GIcon;
import ghidra.framework.plugintool.Plugin; import ghidra.framework.plugintool.Plugin;
import ghidra.program.model.data.DataTypeComponent;
import ghidra.program.model.data.Structure; import ghidra.program.model.data.Structure;
import ghidra.util.Msg;
/** /**
* Editor for a Structure Data Type. * Editor for a Structure Data Type.
*/ */
public class StructureEditorProvider extends CompositeEditorProvider { public class StructureEditorProvider extends CompositeEditorProvider {
private BitFieldEditorDialog bitFieldEditor;
protected static final Icon STRUCTURE_EDITOR_ICON = protected static final Icon STRUCTURE_EDITOR_ICON =
new GIcon("icon.plugin.composite.editor.provider.structure"); new GIcon("icon.plugin.composite.editor.provider.structure");
@ -95,4 +100,69 @@ public class StructureEditorProvider extends CompositeEditorProvider {
editorPanel.selectField(fieldName); editorPanel.selectField(fieldName);
} }
} }
@Override
protected void closeDependentEditors() {
if (bitFieldEditor != null && bitFieldEditor.isVisible()) {
bitFieldEditor.close();
}
}
private void refreshTableAndSelection(int ordinal) {
editorModel.notifyCompositeChanged();
editorModel.setSelection(new int[] { ordinal, ordinal });
}
void showAddBitFieldEditor() {
int[] selectedRows = editorModel.getSelectedRows();
// TODO: Add w/ GP-4740 merge
// if (editorPanel.hasInvalidEntry() || editorPanel.hasUncomittedEntry() ||
// selectedRows.length != 1 || editorModel.viewComposite.isPackingEnabled()) {
// Msg.error(this, "Unsupported add bitfield editor use");
// return;
// }
bitFieldEditor =
new BitFieldEditorDialog(editorModel.viewComposite, dtmService, -(selectedRows[0] + 1),
editorModel.showHexNumbers, ordinal -> refreshTableAndSelection(ordinal));
DockingWindowManager.showDialog(editorPanel, bitFieldEditor);
requestTableFocus();
}
void showBitFieldEditor() {
DataTypeComponent dtComponent = getSelectedNonPackedBitFieldComponent();
if (dtComponent == null) {
Msg.error(this, "Unsupported bitfield editor use");
return;
}
bitFieldEditor = new BitFieldEditorDialog(editorModel.viewComposite, dtmService,
dtComponent.getOrdinal(), editorModel.showHexNumbers,
ordinal -> refreshTableAndSelection(ordinal));
DockingWindowManager.showDialog(editorPanel, bitFieldEditor);
requestTableFocus();
}
/**
* Get the selected bitfield component if contained within a non-packed structure
* @return selected bitfield component or null
*/
DataTypeComponent getSelectedNonPackedBitFieldComponent() {
if (!editorModel.viewComposite.isPackingEnabled() &&
editorModel.getNumSelectedRows() == 1) {
int rowIndex = editorModel.getSelectedRows()[0];
if (rowIndex < editorModel.getNumComponents()) {
DataTypeComponent dtComponent = editorModel.getComponent(rowIndex);
if (dtComponent.isBitFieldComponent()) {
return dtComponent;
}
}
}
return null;
}
} }

View file

@ -274,7 +274,7 @@ public class StackEditorPanel extends CompositeEditorPanel {
} }
@Override @Override
public void dataTypeManagerRestored() { protected void dataTypeManagerRestored() {
boolean reload = true; boolean reload = true;
String objectType = "program"; String objectType = "program";
DataTypeManager dtm = ((StackEditorModel) model).getOriginalDataTypeManager(); DataTypeManager dtm = ((StackEditorModel) model).getOriginalDataTypeManager();