mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge branch 'GP-5557_ghidra1_CompositeEditorFixes' into patch
This commit is contained in:
commit
3725eb0b39
85 changed files with 703 additions and 633 deletions
|
@ -217,8 +217,8 @@ public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endTransaction(int transactionID, boolean commit) {
|
public boolean endTransaction(int transactionID, boolean commit) {
|
||||||
trace.endTransaction(transactionID, commit);
|
return trace.endTransaction(transactionID, commit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1173,8 +1173,8 @@ public class DBTraceProgramView implements TraceProgramView {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endTransaction(int transactionID, boolean commit) {
|
public boolean endTransaction(int transactionID, boolean commit) {
|
||||||
trace.endTransaction(transactionID, commit);
|
return trace.endTransaction(transactionID, commit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -384,8 +384,8 @@ public class DBTraceProgramViewRegisters implements TraceProgramView {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endTransaction(int transactionID, boolean commit) {
|
public boolean endTransaction(int transactionID, boolean commit) {
|
||||||
view.endTransaction(transactionID, commit);
|
return view.endTransaction(transactionID, commit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -26,7 +26,7 @@ public class AddBitFieldAction extends CompositeEditorTableAction {
|
||||||
"Add a bitfield at the position of a selected component";
|
"Add a bitfield at the position of a selected component";
|
||||||
private static String[] POPUP_PATH = new String[] { ACTION_NAME };
|
private static String[] POPUP_PATH = new String[] { ACTION_NAME };
|
||||||
|
|
||||||
public AddBitFieldAction(CompositeEditorProvider provider) {
|
public AddBitFieldAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, null);
|
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, null);
|
||||||
setDescription(DESCRIPTION);
|
setDescription(DESCRIPTION);
|
||||||
if (!(model instanceof CompEditorModel)) {
|
if (!(model instanceof CompEditorModel)) {
|
||||||
|
@ -46,9 +46,9 @@ public class AddBitFieldAction extends CompositeEditorTableAction {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
boolean enabled = true;
|
boolean enabled = true;
|
||||||
CompEditorModel editorModel = (CompEditorModel) model;
|
CompEditorModel<?> editorModel = (CompEditorModel<?>) model;
|
||||||
// Unions do not support non-packed manipulation of bitfields
|
// Unions do not support non-packed manipulation of bitfields
|
||||||
if (!(provider instanceof StructureEditorProvider structProvider) ||
|
if (!(provider instanceof StructureEditorProvider) ||
|
||||||
editorModel.isPackingEnabled() || editorModel.getNumSelectedRows() != 1) {
|
editorModel.isPackingEnabled() || editorModel.getNumSelectedRows() != 1) {
|
||||||
enabled = false;
|
enabled = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ public class ApplyAction extends CompositeEditorTableAction {
|
||||||
private final static Icon ICON = new GIcon("icon.plugin.composite.editor.apply");
|
private final static Icon ICON = new GIcon("icon.plugin.composite.editor.apply");
|
||||||
private final static String[] POPUP_PATH = new String[] { "Apply Edits" };
|
private final static String[] POPUP_PATH = new String[] { "Apply Edits" };
|
||||||
|
|
||||||
public ApplyAction(CompositeEditorProvider provider) {
|
public ApplyAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||||
|
|
||||||
setDescription("Apply editor changes");
|
setDescription("Apply editor changes");
|
||||||
|
|
|
@ -38,7 +38,7 @@ public class ArrayAction extends CompositeEditorTableAction {
|
||||||
private final static KeyStroke KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, 0);
|
private final static KeyStroke KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, 0);
|
||||||
private static String[] POPUP_PATH = new String[] { ACTION_NAME };
|
private static String[] POPUP_PATH = new String[] { ACTION_NAME };
|
||||||
|
|
||||||
public ArrayAction(CompositeEditorProvider provider) {
|
public ArrayAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||||
setDescription(DESCRIPTION);
|
setDescription(DESCRIPTION);
|
||||||
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
||||||
|
|
|
@ -33,7 +33,7 @@ public class ClearAction extends CompositeEditorTableAction {
|
||||||
private final static String[] POPUP_PATH = new String[] { "Clear" };
|
private final static String[] POPUP_PATH = new String[] { "Clear" };
|
||||||
private final static KeyStroke KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_C, 0);
|
private final static KeyStroke KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_C, 0);
|
||||||
|
|
||||||
public ClearAction(CompositeEditorProvider provider) {
|
public ClearAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||||
|
|
||||||
setDescription("Clear the selected components");
|
setDescription("Clear the selected components");
|
||||||
|
|
|
@ -29,7 +29,7 @@ import ghidra.util.*;
|
||||||
import ghidra.util.exception.*;
|
import ghidra.util.exception.*;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public abstract class CompEditorModel extends CompositeEditorModel {
|
public abstract class CompEditorModel<T extends Composite> extends CompositeEditorModel<T> {
|
||||||
|
|
||||||
private volatile boolean consideringReplacedDataType = false;
|
private volatile boolean consideringReplacedDataType = false;
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
* Creates a model for editing a composite data type.
|
* Creates a model for editing a composite data type.
|
||||||
* @param provider the provider that is using this model for editing.
|
* @param provider the provider that is using this model for editing.
|
||||||
*/
|
*/
|
||||||
CompEditorModel(CompositeEditorProvider provider) {
|
CompEditorModel(CompositeEditorProvider<T, ? extends CompEditorModel<T>> provider) {
|
||||||
super(provider);
|
super(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
* @param dataType the composite data type being edited.
|
* @param dataType the composite data type being edited.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void load(Composite dataType) {
|
public void load(T dataType) {
|
||||||
super.load(dataType);
|
super.load(dataType);
|
||||||
fixSelection();
|
fixSelection();
|
||||||
selectionChanged();
|
selectionChanged();
|
||||||
|
@ -76,7 +76,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
FieldSelection saveSelection = new FieldSelection(selection);
|
FieldSelection saveSelection = new FieldSelection(selection);
|
||||||
Composite originalDt = getOriginalComposite();
|
T originalDt = getOriginalComposite();
|
||||||
if (originalDt == null || originalDTM == null) {
|
if (originalDt == null || originalDTM == null) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Can't apply edits without a data type or data type manager.");
|
"Can't apply edits without a data type or data type manager.");
|
||||||
|
@ -118,7 +118,8 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
load(originalDt);
|
load(originalDt);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Composite dt = (Composite) originalDTM.resolve(viewComposite, null);
|
@SuppressWarnings("unchecked")
|
||||||
|
T dt = (T) originalDTM.resolve(viewComposite, null);
|
||||||
load(dt);
|
load(dt);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -376,7 +377,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
int componentOrdinal = convertRowToOrdinal(rowIndex);
|
int componentOrdinal = convertRowToOrdinal(rowIndex);
|
||||||
delete(componentOrdinal);
|
delete(componentOrdinal);
|
||||||
fixSelection();
|
fixSelection();
|
||||||
componentEdited();
|
|
||||||
selectionChanged();
|
selectionChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,8 +411,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
}
|
}
|
||||||
viewDTM.withTransaction("Delete Components", () -> viewComposite.delete(ordinals));
|
viewDTM.withTransaction("Delete Components", () -> viewComposite.delete(ordinals));
|
||||||
fixSelection();
|
fixSelection();
|
||||||
componentEdited();
|
|
||||||
notifyCompositeChanged();
|
|
||||||
selectionChanged();
|
selectionChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,12 +425,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
|
|
||||||
int[] selectedComponents = getSelectedComponentRows();
|
int[] selectedComponents = getSelectedComponentRows();
|
||||||
int firstRowIndex = !selection.isEmpty() ? selectedComponents[0] : getRowCount();
|
int firstRowIndex = !selection.isEmpty() ? selectedComponents[0] : getRowCount();
|
||||||
try {
|
|
||||||
delete(selectedComponents);
|
delete(selectedComponents);
|
||||||
}
|
|
||||||
finally {
|
|
||||||
componentEdited();
|
|
||||||
}
|
|
||||||
selection.addRange(firstRowIndex, firstRowIndex + 1);
|
selection.addRange(firstRowIndex, firstRowIndex + 1);
|
||||||
fixSelection();
|
fixSelection();
|
||||||
selectionChanged();
|
selectionChanged();
|
||||||
|
@ -532,7 +525,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
}
|
}
|
||||||
DataTypeComponent dtc = insert(rowIndex, datatype, length, null, null);
|
DataTypeComponent dtc = insert(rowIndex, datatype, length, null, null);
|
||||||
fixSelection();
|
fixSelection();
|
||||||
componentEdited();
|
|
||||||
selectionChanged();
|
selectionChanged();
|
||||||
return dtc;
|
return dtc;
|
||||||
}
|
}
|
||||||
|
@ -562,7 +554,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
checkIsAllowableDataType(dataType);
|
checkIsAllowableDataType(dataType);
|
||||||
insertMultiple(rowIndex, dataType, dtLen, multiple, monitor);
|
insertMultiple(rowIndex, dataType, dtLen, multiple, monitor);
|
||||||
fixSelection();
|
fixSelection();
|
||||||
componentEdited();
|
|
||||||
selectionChanged();
|
selectionChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -601,7 +592,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
});
|
});
|
||||||
|
|
||||||
fixSelection();
|
fixSelection();
|
||||||
componentEdited();
|
// componentEdited();
|
||||||
selectionChanged();
|
selectionChanged();
|
||||||
return dtc;
|
return dtc;
|
||||||
}
|
}
|
||||||
|
@ -637,7 +628,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
fixSelection();
|
fixSelection();
|
||||||
componentEdited();
|
//componentEdited();
|
||||||
selectionChanged();
|
selectionChanged();
|
||||||
return dtc;
|
return dtc;
|
||||||
}
|
}
|
||||||
|
@ -753,7 +744,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
replace(rowIndex, datatype, newCompSize, oldDtc.getFieldName(), oldDtc.getComment());
|
replace(rowIndex, datatype, newCompSize, oldDtc.getFieldName(), oldDtc.getComment());
|
||||||
|
|
||||||
fixSelection();
|
fixSelection();
|
||||||
componentEdited();
|
|
||||||
selectionChanged();
|
selectionChanged();
|
||||||
return dtc;
|
return dtc;
|
||||||
}
|
}
|
||||||
|
@ -806,7 +796,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
}
|
}
|
||||||
dtc.setComment(oldDtc.getComment());
|
dtc.setComment(oldDtc.getComment());
|
||||||
fixSelection();
|
fixSelection();
|
||||||
componentEdited();
|
|
||||||
selectionChanged();
|
selectionChanged();
|
||||||
return dtc;
|
return dtc;
|
||||||
}
|
}
|
||||||
|
@ -994,7 +983,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
int newIndex = startIndex - 1;
|
int newIndex = startIndex - 1;
|
||||||
moved = shiftComponentsUp(startIndex, endIndex);
|
moved = shiftComponentsUp(startIndex, endIndex);
|
||||||
if (moved) {
|
if (moved) {
|
||||||
componentEdited();
|
|
||||||
FieldSelection tmpFieldSelection = new FieldSelection();
|
FieldSelection tmpFieldSelection = new FieldSelection();
|
||||||
tmpFieldSelection.addRange(newIndex, newIndex + numSelected);
|
tmpFieldSelection.addRange(newIndex, newIndex + numSelected);
|
||||||
setSelection(tmpFieldSelection);
|
setSelection(tmpFieldSelection);
|
||||||
|
@ -1018,7 +1006,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
int newIndex = startIndex + 1;
|
int newIndex = startIndex + 1;
|
||||||
moved = shiftComponentsDown(startIndex, endIndex);
|
moved = shiftComponentsDown(startIndex, endIndex);
|
||||||
if (moved) {
|
if (moved) {
|
||||||
componentEdited();
|
|
||||||
FieldSelection tmpFieldSelection = new FieldSelection();
|
FieldSelection tmpFieldSelection = new FieldSelection();
|
||||||
tmpFieldSelection.addRange(newIndex, newIndex + numSelected);
|
tmpFieldSelection.addRange(newIndex, newIndex + numSelected);
|
||||||
setSelection(tmpFieldSelection);
|
setSelection(tmpFieldSelection);
|
||||||
|
@ -1038,7 +1025,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
// Adjust the selection since we added some components. Select last component added.
|
// Adjust the selection since we added some components. Select last component added.
|
||||||
setSelection(new int[] { rowIndex + multiple });
|
setSelection(new int[] { rowIndex + multiple });
|
||||||
|
|
||||||
componentEdited();
|
|
||||||
lastNumDuplicates = multiple;
|
lastNumDuplicates = multiple;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1143,9 +1129,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
public void setValueAt(Object aValue, int rowIndex, int modelColumnIndex) {
|
public void setValueAt(Object aValue, int rowIndex, int modelColumnIndex) {
|
||||||
try {
|
try {
|
||||||
settingValueAt = true;
|
settingValueAt = true;
|
||||||
if (fieldEdited(aValue, rowIndex, modelColumnIndex)) {
|
fieldEdited(aValue, rowIndex, modelColumnIndex);
|
||||||
componentEdited();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
settingValueAt = false;
|
settingValueAt = false;
|
||||||
|
@ -1284,7 +1268,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Composite composite = getOriginalComposite();
|
T composite = getOriginalComposite();
|
||||||
boolean reload = true;
|
boolean reload = true;
|
||||||
if (hasChanges || !viewComposite.isEquivalent(composite)) {
|
if (hasChanges || !viewComposite.isEquivalent(composite)) {
|
||||||
hasChanges = true;
|
hasChanges = true;
|
||||||
|
@ -1323,7 +1307,11 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
public void dataTypeRemoved(DataTypeManager dtm, DataTypePath path) {
|
public void dataTypeRemoved(DataTypeManager dtm, DataTypePath path) {
|
||||||
|
|
||||||
if (dtm != originalDTM) {
|
if (dtm != originalDTM) {
|
||||||
return; // Different DTM than the one for this data type.
|
throw new AssertException("Listener only supports original DTM");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLoaded()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType dataType = viewDTM.getDataType(path.getCategoryPath(), path.getDataTypeName());
|
DataType dataType = viewDTM.getDataType(path.getCategoryPath(), path.getDataTypeName());
|
||||||
|
@ -1380,7 +1368,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
|
public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
|
||||||
|
|
||||||
if (dtm != originalDTM) {
|
if (dtm != originalDTM) {
|
||||||
return; // Different DTM than the one for this data type.
|
throw new AssertException("Listener only supports original DTM");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isLoaded()) {
|
if (!isLoaded()) {
|
||||||
|
@ -1434,7 +1422,11 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
public void dataTypeMoved(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
|
public void dataTypeMoved(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
|
||||||
|
|
||||||
if (dtm != originalDTM) {
|
if (dtm != originalDTM) {
|
||||||
return; // Different DTM than the one for this data type.
|
throw new AssertException("Listener only supports original DTM");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLoaded()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType dt = viewDTM.getDataType(oldPath);
|
DataType dt = viewDTM.getDataType(oldPath);
|
||||||
|
@ -1468,20 +1460,14 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
public void dataTypeChanged(DataTypeManager dtm, DataTypePath path) {
|
public void dataTypeChanged(DataTypeManager dtm, DataTypePath path) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
if (dtm != originalDTM) {
|
||||||
|
throw new AssertException("Listener only supports original DTM");
|
||||||
|
}
|
||||||
|
|
||||||
if (!isLoaded()) {
|
if (!isLoaded()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dtm instanceof CompositeViewerDataTypeManager) {
|
|
||||||
// required to detect settings changes
|
|
||||||
componentEdited();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dtm != originalDTM) {
|
|
||||||
return; // Different DTM than the one for this data type.
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we don't currently have any modifications that need applying and
|
// If we don't currently have any modifications that need applying and
|
||||||
// the structure in the editor just changed, then show the changed
|
// the structure in the editor just changed, then show the changed
|
||||||
// structure.
|
// structure.
|
||||||
|
@ -1566,7 +1552,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
DataType newDataType) {
|
DataType newDataType) {
|
||||||
|
|
||||||
if (dtm != originalDTM) {
|
if (dtm != originalDTM) {
|
||||||
return; // Different DTM than the one for this data type.
|
throw new AssertException("Listener only supports original DTM");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isLoaded()) {
|
if (!isLoaded()) {
|
||||||
|
@ -1723,15 +1709,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||||
return lastNumDuplicates;
|
return lastNumDuplicates;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Called whenever the data structure's modification state changes.
|
|
||||||
*/
|
|
||||||
void componentEdited() {
|
|
||||||
updateAndCheckChangeState(); // Update the composite's change state information.
|
|
||||||
fireTableDataChanged();
|
|
||||||
componentDataChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int convertRowToOrdinal(int rowIndex) {
|
protected int convertRowToOrdinal(int rowIndex) {
|
||||||
return rowIndex;
|
return rowIndex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import docking.widgets.button.GRadioButton;
|
import docking.widgets.button.GRadioButton;
|
||||||
import docking.widgets.fieldpanel.support.FieldSelection;
|
|
||||||
import docking.widgets.label.GDLabel;
|
import docking.widgets.label.GDLabel;
|
||||||
import docking.widgets.textfield.GFormattedTextField;
|
import docking.widgets.textfield.GFormattedTextField;
|
||||||
import generic.theme.GThemeDefaults.Colors.Palette;
|
import generic.theme.GThemeDefaults.Colors.Palette;
|
||||||
|
@ -50,8 +49,12 @@ import ghidra.util.layout.VerticalLayout;
|
||||||
/**
|
/**
|
||||||
* Panel for editing a composite with a blank line at the bottom of the table
|
* Panel for editing a composite with a blank line at the bottom of the table
|
||||||
* when in unlocked mode.
|
* when in unlocked mode.
|
||||||
|
*
|
||||||
|
* @param <T> Specific {@link Composite} type being edited
|
||||||
|
* @param <M> Specific {@link CompEditorModel} implementation which supports editing T
|
||||||
*/
|
*/
|
||||||
public class CompEditorPanel extends CompositeEditorPanel {
|
public class CompEditorPanel<T extends Composite, M extends CompEditorModel<T>>
|
||||||
|
extends CompositeEditorPanel<T, M> {
|
||||||
|
|
||||||
protected final static Insets LEFT_INSETS = new Insets(2, 3, 1, 0);
|
protected final static Insets LEFT_INSETS = new Insets(2, 3, 1, 0);
|
||||||
protected final static Insets VERTICAL_INSETS = new Insets(2, 2, 1, 0);
|
protected final static Insets VERTICAL_INSETS = new Insets(2, 2, 1, 0);
|
||||||
|
@ -93,7 +96,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
* @param provider
|
* @param provider
|
||||||
* the editor provider furnishing this panel for editing.
|
* the editor provider furnishing this panel for editing.
|
||||||
*/
|
*/
|
||||||
public CompEditorPanel(CompEditorModel model, CompositeEditorProvider provider) {
|
public CompEditorPanel(M model, CompositeEditorProvider<T, M> provider) {
|
||||||
super(model, provider);
|
super(model, provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,6 +359,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
public void keyPressed(KeyEvent e) {
|
public void keyPressed(KeyEvent e) {
|
||||||
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
||||||
e.consume();
|
e.consume();
|
||||||
|
setStatus("");
|
||||||
// revert to model state when escape is hit
|
// revert to model state when escape is hit
|
||||||
setCompositeName(model.getCompositeName());
|
setCompositeName(model.getCompositeName());
|
||||||
}
|
}
|
||||||
|
@ -406,6 +410,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
public void keyPressed(KeyEvent e) {
|
public void keyPressed(KeyEvent e) {
|
||||||
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
|
||||||
e.consume();
|
e.consume();
|
||||||
|
setStatus("");
|
||||||
// revert to model state when escape is hit
|
// revert to model state when escape is hit
|
||||||
setDescription(model.getDescription());
|
setDescription(model.getDescription());
|
||||||
}
|
}
|
||||||
|
@ -523,7 +528,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
"setting and the alignment of each component data type.</html>";
|
"setting and the alignment of each component data type.</html>";
|
||||||
|
|
||||||
defaultAlignButton.addActionListener(e -> {
|
defaultAlignButton.addActionListener(e -> {
|
||||||
((CompEditorModel) model).setAlignmentType(AlignmentType.DEFAULT, -1);
|
model.setAlignmentType(AlignmentType.DEFAULT, -1);
|
||||||
});
|
});
|
||||||
|
|
||||||
defaultAlignButton.setToolTipText(alignmentToolTip);
|
defaultAlignButton.setToolTipText(alignmentToolTip);
|
||||||
|
@ -532,7 +537,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
|
|
||||||
private void setupMachineMinAlignButton() {
|
private void setupMachineMinAlignButton() {
|
||||||
DataOrganization dataOrganization =
|
DataOrganization dataOrganization =
|
||||||
((CompEditorModel) model).viewComposite.getDataOrganization();
|
model.viewComposite.getDataOrganization();
|
||||||
int machineAlignment = dataOrganization.getMachineAlignment();
|
int machineAlignment = dataOrganization.getMachineAlignment();
|
||||||
|
|
||||||
machineAlignButton = new GRadioButton("machine: " + machineAlignment);
|
machineAlignButton = new GRadioButton("machine: " + machineAlignment);
|
||||||
|
@ -546,7 +551,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
machineAlignButton.setToolTipText(alignmentToolTip);
|
machineAlignButton.setToolTipText(alignmentToolTip);
|
||||||
|
|
||||||
machineAlignButton.addActionListener(e -> {
|
machineAlignButton.addActionListener(e -> {
|
||||||
((CompEditorModel) model).setAlignmentType(AlignmentType.MACHINE, -1);
|
model.setAlignmentType(AlignmentType.MACHINE, -1);
|
||||||
});
|
});
|
||||||
|
|
||||||
provider.registerHelp(machineAlignButton, "Align");
|
provider.registerHelp(machineAlignButton, "Align");
|
||||||
|
@ -634,7 +639,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
((CompEditorModel) model).setAlignmentType(AlignmentType.EXPLICIT, minAlignment);
|
model.setAlignmentType(AlignmentType.EXPLICIT, minAlignment);
|
||||||
adjustCompositeInfo();
|
adjustCompositeInfo();
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e1) {
|
catch (IllegalArgumentException e1) {
|
||||||
|
@ -664,7 +669,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
infoPanel.add(actualAlignmentPanel, gridBagConstraints);
|
infoPanel.add(actualAlignmentPanel, gridBagConstraints);
|
||||||
|
|
||||||
actualAlignmentValueLabel = new JLabel();
|
actualAlignmentValueLabel = new JLabel();
|
||||||
int actualAlignment = ((CompEditorModel) model).getActualAlignment();
|
int actualAlignment = model.getActualAlignment();
|
||||||
actualAlignmentValueLabel.setText(Integer.toString(actualAlignment));
|
actualAlignmentValueLabel.setText(Integer.toString(actualAlignment));
|
||||||
actualAlignmentValueLabel.setToolTipText(actualAlignmentToolTip);
|
actualAlignmentValueLabel.setToolTipText(actualAlignmentToolTip);
|
||||||
actualAlignmentValueLabel.setBackground(getBackground());
|
actualAlignmentValueLabel.setBackground(getBackground());
|
||||||
|
@ -765,7 +770,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
"<font color=\"" + Palette.BLUE.toHexString() +
|
"<font color=\"" + Palette.BLUE.toHexString() +
|
||||||
"\" size=\"-2\">(<F1> for help)</font></html>";
|
"\" size=\"-2\">(<F1> for help)</font></html>";
|
||||||
packingEnablementButton.addActionListener(e -> {
|
packingEnablementButton.addActionListener(e -> {
|
||||||
((CompEditorModel) model).setPackingType(
|
model.setPackingType(
|
||||||
packingEnablementButton.isSelected() ? PackingType.DEFAULT : PackingType.DISABLED,
|
packingEnablementButton.isSelected() ? PackingType.DEFAULT : PackingType.DISABLED,
|
||||||
-1);
|
-1);
|
||||||
});
|
});
|
||||||
|
@ -783,7 +788,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
"<html>Indicates <B>default</B> compiler packing rules should be applied.</html>";
|
"<html>Indicates <B>default</B> compiler packing rules should be applied.</html>";
|
||||||
|
|
||||||
defaultPackingButton.addActionListener(e -> {
|
defaultPackingButton.addActionListener(e -> {
|
||||||
((CompEditorModel) model).setPackingType(PackingType.DEFAULT, -1);
|
model.setPackingType(PackingType.DEFAULT, -1);
|
||||||
});
|
});
|
||||||
|
|
||||||
defaultPackingButton.setToolTipText(packingToolTipText);
|
defaultPackingButton.setToolTipText(packingToolTipText);
|
||||||
|
@ -860,7 +865,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void chooseByValuePacking() {
|
private void chooseByValuePacking() {
|
||||||
((CompEditorModel) model).setPackingType(PackingType.EXPLICIT, 1);
|
model.setPackingType(PackingType.EXPLICIT, 1);
|
||||||
explicitPackingTextField.selectAll();
|
explicitPackingTextField.selectAll();
|
||||||
explicitPackingTextField.requestFocus();
|
explicitPackingTextField.requestFocus();
|
||||||
}
|
}
|
||||||
|
@ -873,7 +878,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
if (explicitPacking <= 0) {
|
if (explicitPacking <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
((CompEditorModel) model).setPackingType(PackingType.EXPLICIT, explicitPacking);
|
model.setPackingType(PackingType.EXPLICIT, explicitPacking);
|
||||||
adjustCompositeInfo();
|
adjustCompositeInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -881,7 +886,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
* Sets the currently displayed structure packing value (maximum component alignment)
|
* Sets the currently displayed structure packing value (maximum component alignment)
|
||||||
*/
|
*/
|
||||||
public void refreshGUIPackingValue() {
|
public void refreshGUIPackingValue() {
|
||||||
PackingType packingType = ((CompEditorModel) model).getPackingType();
|
PackingType packingType = model.getPackingType();
|
||||||
String packingString = "";
|
String packingString = "";
|
||||||
|
|
||||||
boolean packingEnabled = packingType != PackingType.DISABLED;
|
boolean packingEnabled = packingType != PackingType.DISABLED;
|
||||||
|
@ -895,7 +900,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
defaultPackingButton.setSelected(true);
|
defaultPackingButton.setSelected(true);
|
||||||
}
|
}
|
||||||
else if (packingType == PackingType.EXPLICIT) {
|
else if (packingType == PackingType.EXPLICIT) {
|
||||||
int packValue = ((CompEditorModel) model).getExplicitPackingValue();
|
int packValue = model.getExplicitPackingValue();
|
||||||
packingString =
|
packingString =
|
||||||
model.showHexNumbers ? CompositeViewerModel.getHexString(packValue, true)
|
model.showHexNumbers ? CompositeViewerModel.getHexString(packValue, true)
|
||||||
: Integer.toString(packValue);
|
: Integer.toString(packValue);
|
||||||
|
@ -985,7 +990,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!((CompEditorModel) model).isSizeEditable()) {
|
if (!model.isSizeEditable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1022,13 +1027,13 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void chooseExplicitAlign() {
|
private void chooseExplicitAlign() {
|
||||||
if (((CompEditorModel) model).getAlignmentType() != AlignmentType.EXPLICIT) {
|
if (model.getAlignmentType() != AlignmentType.EXPLICIT) {
|
||||||
Composite viewComposite = ((CompEditorModel) model).viewComposite;
|
Composite viewComposite = model.viewComposite;
|
||||||
int defaultValue = 1;
|
int defaultValue = 1;
|
||||||
if (viewComposite.isPackingEnabled()) {
|
if (viewComposite.isPackingEnabled()) {
|
||||||
defaultValue = viewComposite.getDataOrganization().getMachineAlignment();
|
defaultValue = viewComposite.getDataOrganization().getMachineAlignment();
|
||||||
}
|
}
|
||||||
((CompEditorModel) model).setAlignmentType(AlignmentType.EXPLICIT, defaultValue);
|
model.setAlignmentType(AlignmentType.EXPLICIT, defaultValue);
|
||||||
}
|
}
|
||||||
explicitAlignTextField.selectAll();
|
explicitAlignTextField.selectAll();
|
||||||
explicitAlignTextField.requestFocus();
|
explicitAlignTextField.requestFocus();
|
||||||
|
@ -1118,6 +1123,8 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setStatus("");
|
||||||
|
|
||||||
// Adjust the value.
|
// Adjust the value.
|
||||||
String newName = nameTextField.getText().trim();
|
String newName = nameTextField.getText().trim();
|
||||||
if (!DataUtilities.isValidDataTypeName(newName)) {
|
if (!DataUtilities.isValidDataTypeName(newName)) {
|
||||||
|
@ -1163,6 +1170,8 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setStatus("");
|
||||||
|
|
||||||
String newValue = this.descriptionTextField.getText().trim();
|
String newValue = this.descriptionTextField.getText().trim();
|
||||||
if (!newValue.equals(model.getDescription())) {
|
if (!newValue.equals(model.getDescription())) {
|
||||||
model.setDescription(newValue);
|
model.setDescription(newValue);
|
||||||
|
@ -1197,7 +1206,6 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
nameTextField.setText(name);
|
nameTextField.setText(name);
|
||||||
nameTextField.setDefaultValue(name);
|
nameTextField.setDefaultValue(name);
|
||||||
nameTextField.setIsError(false);
|
nameTextField.setIsError(false);
|
||||||
setStatus("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1209,12 +1217,11 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
descriptionTextField.setText(description);
|
descriptionTextField.setText(description);
|
||||||
descriptionTextField.setDefaultValue(description);
|
descriptionTextField.setDefaultValue(description);
|
||||||
descriptionTextField.setIsError(false);
|
descriptionTextField.setIsError(false);
|
||||||
setStatus("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refreshGUIMinimumAlignmentValue() {
|
public void refreshGUIMinimumAlignmentValue() {
|
||||||
|
|
||||||
AlignmentType alignmentType = ((CompEditorModel) model).getAlignmentType();
|
AlignmentType alignmentType = model.getAlignmentType();
|
||||||
String minimumAlignmentStr = "";
|
String minimumAlignmentStr = "";
|
||||||
if (alignmentType == AlignmentType.DEFAULT) {
|
if (alignmentType == AlignmentType.DEFAULT) {
|
||||||
defaultAlignButton.setSelected(true);
|
defaultAlignButton.setSelected(true);
|
||||||
|
@ -1224,7 +1231,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
explicitAlignButton.setSelected(true);
|
explicitAlignButton.setSelected(true);
|
||||||
int minimumAlignment = ((CompEditorModel) model).getExplicitMinimumAlignment();
|
int minimumAlignment = model.getExplicitMinimumAlignment();
|
||||||
minimumAlignmentStr =
|
minimumAlignmentStr =
|
||||||
model.showHexNumbers ? CompositeViewerModel.getHexString(minimumAlignment, true)
|
model.showHexNumbers ? CompositeViewerModel.getHexString(minimumAlignment, true)
|
||||||
: Integer.toString(minimumAlignment);
|
: Integer.toString(minimumAlignment);
|
||||||
|
@ -1238,7 +1245,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
* Updates the GUI display of the actual alignment value.
|
* Updates the GUI display of the actual alignment value.
|
||||||
*/
|
*/
|
||||||
public void refreshGUIActualAlignmentValue() {
|
public void refreshGUIActualAlignmentValue() {
|
||||||
int actualAlignment = ((CompEditorModel) model).getActualAlignment();
|
int actualAlignment = model.getActualAlignment();
|
||||||
String alignmentStr =
|
String alignmentStr =
|
||||||
model.showHexNumbers ? CompositeViewerModel.getHexString(actualAlignment, true)
|
model.showHexNumbers ? CompositeViewerModel.getHexString(actualAlignment, true)
|
||||||
: Integer.toString(actualAlignment);
|
: Integer.toString(actualAlignment);
|
||||||
|
@ -1259,7 +1266,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
|
||||||
* @param size the new size
|
* @param size the new size
|
||||||
*/
|
*/
|
||||||
private void setCompositeSize(int size) {
|
private void setCompositeSize(int size) {
|
||||||
boolean sizeIsEditable = ((CompEditorModel) model).isSizeEditable();
|
boolean sizeIsEditable = model.isSizeEditable();
|
||||||
if (sizeTextField.isEditable() != sizeIsEditable) {
|
if (sizeTextField.isEditable() != sizeIsEditable) {
|
||||||
setSizeEditable(sizeIsEditable);
|
setSizeEditable(sizeIsEditable);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ public class ComponentProgramActionContext extends ProgramActionContext
|
||||||
private DataTypeComponent component;
|
private DataTypeComponent component;
|
||||||
private Composite composite;
|
private Composite composite;
|
||||||
|
|
||||||
public ComponentProgramActionContext(CompositeEditorProvider compositeEditorProvider,
|
public ComponentProgramActionContext(CompositeEditorProvider<?, ?> compositeEditorProvider,
|
||||||
Program program, DataTypeComponent component) {
|
Program program, DataTypeComponent component) {
|
||||||
super(compositeEditorProvider, program);
|
super(compositeEditorProvider, program);
|
||||||
this.component = component;
|
this.component = component;
|
||||||
|
|
|
@ -29,7 +29,7 @@ public class ComponentStandAloneActionContext extends DefaultActionContext
|
||||||
private DataTypeComponent component;
|
private DataTypeComponent component;
|
||||||
private Composite composite;
|
private Composite composite;
|
||||||
|
|
||||||
public ComponentStandAloneActionContext(CompositeEditorProvider compositeEditorProvider,
|
public ComponentStandAloneActionContext(CompositeEditorProvider<?, ?> compositeEditorProvider,
|
||||||
DataTypeComponent component) {
|
DataTypeComponent component) {
|
||||||
super(compositeEditorProvider);
|
super(compositeEditorProvider);
|
||||||
this.component = component;
|
this.component = component;
|
||||||
|
|
|
@ -26,7 +26,7 @@ import ghidra.program.model.data.*;
|
||||||
* Other CompositeEditorActions can be added for it to manage.
|
* Other CompositeEditorActions can be added for it to manage.
|
||||||
*/
|
*/
|
||||||
public class CompositeEditorActionManager {
|
public class CompositeEditorActionManager {
|
||||||
private CompositeEditorProvider provider;
|
private CompositeEditorProvider<?, ?> provider;
|
||||||
private ArrayList<CompositeEditorTableAction> editorActions =
|
private ArrayList<CompositeEditorTableAction> editorActions =
|
||||||
new ArrayList<CompositeEditorTableAction>();
|
new ArrayList<CompositeEditorTableAction>();
|
||||||
private ArrayList<CompositeEditorTableAction> favoritesActions =
|
private ArrayList<CompositeEditorTableAction> favoritesActions =
|
||||||
|
@ -45,7 +45,7 @@ public class CompositeEditorActionManager {
|
||||||
* @param provider the provider that owns this composite editor action manager
|
* @param provider the provider that owns this composite editor action manager
|
||||||
* favorites and cycle groups.
|
* favorites and cycle groups.
|
||||||
*/
|
*/
|
||||||
public CompositeEditorActionManager(CompositeEditorProvider provider) {
|
public CompositeEditorActionManager(CompositeEditorProvider<?, ?> provider) {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
this.dataTypeMgrService = provider.dtmService;
|
this.dataTypeMgrService = provider.dtmService;
|
||||||
adapter = new DataTypeManagerChangeListenerAdapter() {
|
adapter = new DataTypeManagerChangeListenerAdapter() {
|
||||||
|
|
|
@ -43,8 +43,12 @@ import ghidra.util.task.TaskMonitor;
|
||||||
/**
|
/**
|
||||||
* Model for editing a composite data type. Specific composite data type editors
|
* Model for editing a composite data type. Specific composite data type editors
|
||||||
* should extend this class.
|
* should extend this class.
|
||||||
|
*
|
||||||
|
* @param <T> Specific {@link Composite} type being managed
|
||||||
*/
|
*/
|
||||||
abstract public class CompositeEditorModel extends CompositeViewerModel {
|
abstract public class CompositeEditorModel<T extends Composite> extends CompositeViewerModel<T> {
|
||||||
|
|
||||||
|
// TODO: This class should be combined with CompositeViewerModel since we only support editor use
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not an apply is occurring. Need to ignore changes to the
|
* Whether or not an apply is occurring. Need to ignore changes to the
|
||||||
|
@ -71,7 +75,8 @@ abstract public class CompositeEditorModel extends CompositeViewerModel {
|
||||||
* Construct abstract composite editor model
|
* Construct abstract composite editor model
|
||||||
* @param provider composite editor provider
|
* @param provider composite editor provider
|
||||||
*/
|
*/
|
||||||
protected CompositeEditorModel(CompositeEditorProvider provider) {
|
protected CompositeEditorModel(
|
||||||
|
CompositeEditorProvider<T, ? extends CompositeEditorModel<T>> provider) {
|
||||||
super(provider);
|
super(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +93,7 @@ abstract public class CompositeEditorModel extends CompositeViewerModel {
|
||||||
endFieldEditing();
|
endFieldEditing();
|
||||||
}
|
}
|
||||||
|
|
||||||
CompositeViewerDataTypeManager oldViewDTM = viewDTM;
|
CompositeViewerDataTypeManager<T> oldViewDTM = viewDTM;
|
||||||
|
|
||||||
originalComposite = viewDTM.getResolvedViewComposite();
|
originalComposite = viewDTM.getResolvedViewComposite();
|
||||||
originalCompositeId = DataTypeManager.NULL_DATATYPE_ID;
|
originalCompositeId = DataTypeManager.NULL_DATATYPE_ID;
|
||||||
|
@ -96,8 +101,8 @@ abstract public class CompositeEditorModel extends CompositeViewerModel {
|
||||||
currentName = originalComposite.getName();
|
currentName = originalComposite.getName();
|
||||||
|
|
||||||
// Use temporary standalone view datatype manager
|
// Use temporary standalone view datatype manager
|
||||||
viewDTM = new CompositeViewerDataTypeManager(viewDTM.getName(),
|
viewDTM = new CompositeViewerDataTypeManager<>(viewDTM.getName(),
|
||||||
viewDTM.getResolvedViewComposite(), () -> restoreEditor());
|
viewDTM.getResolvedViewComposite(), this::componentEdited, this::restoreEditor);
|
||||||
|
|
||||||
viewComposite = viewDTM.getResolvedViewComposite();
|
viewComposite = viewDTM.getResolvedViewComposite();
|
||||||
|
|
||||||
|
@ -108,7 +113,9 @@ abstract public class CompositeEditorModel extends CompositeViewerModel {
|
||||||
// as they get resolved into the view datatype manager. This may result in the incorrect
|
// as they get resolved into the view datatype manager. This may result in the incorrect
|
||||||
// underlying datatype default setting value being presented when adjusting component
|
// underlying datatype default setting value being presented when adjusting component
|
||||||
// default settings.
|
// default settings.
|
||||||
cloneAllComponentSettings(originalComposite, viewComposite);
|
viewDTM.withTransaction("Load Settings",
|
||||||
|
() -> cloneAllComponentSettings(originalComposite, viewComposite));
|
||||||
|
viewDTM.clearUndo();
|
||||||
|
|
||||||
// Dispose previous view DTM
|
// Dispose previous view DTM
|
||||||
oldViewDTM.close();
|
oldViewDTM.close();
|
||||||
|
@ -124,7 +131,7 @@ abstract public class CompositeEditorModel extends CompositeViewerModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load(Composite dataType) {
|
public void load(T dataType) {
|
||||||
Objects.requireNonNull(dataType);
|
Objects.requireNonNull(dataType);
|
||||||
|
|
||||||
DataTypeManager dtm = dataType.getDataTypeManager();
|
DataTypeManager dtm = dataType.getDataTypeManager();
|
||||||
|
@ -179,19 +186,30 @@ abstract public class CompositeEditorModel extends CompositeViewerModel {
|
||||||
currentName = viewComposite.getName();
|
currentName = viewComposite.getName();
|
||||||
updateAndCheckChangeState();
|
updateAndCheckChangeState();
|
||||||
|
|
||||||
clearStatus();
|
|
||||||
compositeInfoChanged();
|
compositeInfoChanged();
|
||||||
fireTableDataChanged();
|
fireTableDataChanged();
|
||||||
componentDataChanged();
|
componentDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void componentEdited() {
|
||||||
|
|
||||||
|
// NOTE: This method relies heavily on the viewDTM with transaction support
|
||||||
|
// and this method specified as the changeCallback method. If viewDTM has been
|
||||||
|
// instantiated with a single open transaction this method will never be used
|
||||||
|
// and provisions must be made for proper notification when changes are made.
|
||||||
|
|
||||||
|
updateAndCheckChangeState(); // Update the composite's change state information.
|
||||||
|
fireTableDataChanged();
|
||||||
|
componentDataChanged();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create {@code viewComposite} and associated view datatype manager ({@code viewDTM}) and
|
* Create {@code viewComposite} and associated view datatype manager ({@code viewDTM}) and
|
||||||
* changes listener(s) if required.
|
* changes listener(s) if required.
|
||||||
*
|
*
|
||||||
* @param original original composite being loaded
|
* @param original original composite being loaded
|
||||||
*/
|
*/
|
||||||
protected void createViewCompositeFromOriginalComposite(Composite original) {
|
protected void createViewCompositeFromOriginalComposite(T original) {
|
||||||
|
|
||||||
if (viewDTM != null) {
|
if (viewDTM != null) {
|
||||||
viewDTM.close();
|
viewDTM.close();
|
||||||
|
@ -199,8 +217,8 @@ abstract public class CompositeEditorModel extends CompositeViewerModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use temporary standalone view datatype manager
|
// Use temporary standalone view datatype manager
|
||||||
viewDTM = new CompositeViewerDataTypeManager(original.getDataTypeManager().getName(),
|
viewDTM = new CompositeViewerDataTypeManager<>(original.getDataTypeManager().getName(),
|
||||||
original, () -> restoreEditor());
|
original, this::componentEdited, this::restoreEditor);
|
||||||
|
|
||||||
viewComposite = viewDTM.getResolvedViewComposite();
|
viewComposite = viewDTM.getResolvedViewComposite();
|
||||||
|
|
||||||
|
@ -211,7 +229,7 @@ abstract public class CompositeEditorModel extends CompositeViewerModel {
|
||||||
// as they get resolved into the view datatype manager. This may result in the incorrect
|
// as they get resolved into the view datatype manager. This may result in the incorrect
|
||||||
// underlying datatype default setting value being presented when adjusting component
|
// underlying datatype default setting value being presented when adjusting component
|
||||||
// default settings.
|
// default settings.
|
||||||
viewDTM.withTransaction("Apply Settings",
|
viewDTM.withTransaction("Load Settings",
|
||||||
() -> cloneAllComponentSettings(original, viewComposite));
|
() -> cloneAllComponentSettings(original, viewComposite));
|
||||||
viewDTM.clearUndo();
|
viewDTM.clearUndo();
|
||||||
}
|
}
|
||||||
|
@ -236,7 +254,7 @@ abstract public class CompositeEditorModel extends CompositeViewerModel {
|
||||||
* Returns the docking windows component provider associated with this edit model.
|
* Returns the docking windows component provider associated with this edit model.
|
||||||
* @return the component provider
|
* @return the component provider
|
||||||
*/
|
*/
|
||||||
protected CompositeEditorProvider getProvider() {
|
protected CompositeEditorProvider<T, ?> getProvider() {
|
||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1485,7 +1503,7 @@ abstract public class CompositeEditorModel extends CompositeViewerModel {
|
||||||
* Get the composite edtor's datatype manager
|
* Get the composite edtor's datatype manager
|
||||||
* @return composite edtor's datatype manager
|
* @return composite edtor's datatype manager
|
||||||
*/
|
*/
|
||||||
public CompositeViewerDataTypeManager getViewDataTypeManager() {
|
public CompositeViewerDataTypeManager<T> getViewDataTypeManager() {
|
||||||
return viewDTM;
|
return viewDTM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -53,16 +52,6 @@ public interface CompositeEditorModelListener extends CompositeViewerModelListen
|
||||||
*/
|
*/
|
||||||
public abstract void compositeEditStateChanged(int type);
|
public abstract void compositeEditStateChanged(int type);
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Called when the data type for one of our components changes.
|
|
||||||
// * This means that any component that has this data type may have consumed
|
|
||||||
// * undefined bytes which followed it. Therefore any change that has been
|
|
||||||
// * started, but not finished yet, may not be allowable and should be
|
|
||||||
// * cancelled.
|
|
||||||
// * @param dt the data type that has changed.
|
|
||||||
// */
|
|
||||||
// public abstract void componentDataTypeChanged(DataType dt);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the model wants to end cell editing that is in progress.
|
* Called when the model wants to end cell editing that is in progress.
|
||||||
* This is due to an attempt to modify the composite data type in the
|
* This is due to an attempt to modify the composite data type in the
|
||||||
|
|
|
@ -32,7 +32,6 @@ import javax.swing.text.JTextComponent;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import docking.DockingWindowManager;
|
|
||||||
import docking.actions.KeyBindingUtils;
|
import docking.actions.KeyBindingUtils;
|
||||||
import docking.dnd.DropTgtAdapter;
|
import docking.dnd.DropTgtAdapter;
|
||||||
import docking.dnd.Droppable;
|
import docking.dnd.Droppable;
|
||||||
|
@ -64,14 +63,18 @@ import help.HelpService;
|
||||||
* This provides a table with cell edit functionality and drag and drop capability.
|
* This provides a table with cell edit functionality and drag and drop capability.
|
||||||
* Below the table is an information area for non-component information about the
|
* Below the table is an information area for non-component information about the
|
||||||
* composite data type. To add your own info panel override the createInfoPanel() method.
|
* composite data type. To add your own info panel override the createInfoPanel() method.
|
||||||
|
*
|
||||||
|
* @param <T> Specific {@link Composite} type being edited
|
||||||
|
* @param <M> Specific {@link CompositeEditorModel} implementation which supports editing T
|
||||||
*/
|
*/
|
||||||
public abstract class CompositeEditorPanel extends JPanel
|
public abstract class CompositeEditorPanel<T extends Composite, M extends CompositeEditorModel<T>>
|
||||||
|
extends JPanel
|
||||||
implements CompositeEditorModelListener, ComponentCellEditorListener, Droppable {
|
implements CompositeEditorModelListener, ComponentCellEditorListener, Droppable {
|
||||||
|
|
||||||
protected static final Border BEVELED_BORDER = BorderFactory.createLoweredBevelBorder();
|
protected static final Border BEVELED_BORDER = BorderFactory.createLoweredBevelBorder();
|
||||||
|
|
||||||
protected CompositeEditorProvider provider;
|
protected CompositeEditorProvider<T, M> provider;
|
||||||
protected CompositeEditorModel model;
|
protected M model;
|
||||||
protected GTable table;
|
protected GTable table;
|
||||||
private JLabel statusLabel;
|
private JLabel statusLabel;
|
||||||
|
|
||||||
|
@ -90,7 +93,7 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||||
|
|
||||||
protected SearchControlPanel searchPanel;
|
protected SearchControlPanel searchPanel;
|
||||||
|
|
||||||
public CompositeEditorPanel(CompositeEditorModel model, CompositeEditorProvider provider) {
|
public CompositeEditorPanel(M model, CompositeEditorProvider<T, M> provider) {
|
||||||
super(new BorderLayout());
|
super(new BorderLayout());
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
this.model = model;
|
this.model = model;
|
||||||
|
@ -145,7 +148,7 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CompositeEditorModel getModel() {
|
protected M getModel() {
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,30 +168,10 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||||
table.setDefaultRenderer(DataTypeInstance.class, dtiCellRenderer);
|
table.setDefaultRenderer(DataTypeInstance.class, dtiCellRenderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean launchBitFieldEditor(int modelRow, int modelColumn) {
|
boolean launchBitFieldEditor(int modelRow, int modelColumn) {
|
||||||
if (model.viewComposite instanceof Structure && !model.viewComposite.isPackingEnabled() &&
|
|
||||||
model.getDataTypeColumn() == modelColumn && modelRow < model.getNumComponents()) {
|
|
||||||
// check if we are attempting to edit a bitfield
|
|
||||||
DataTypeComponent dtComponent = model.getComponent(modelRow);
|
|
||||||
if (dtComponent.isBitFieldComponent()) {
|
|
||||||
table.getCellEditor().cancelCellEditing();
|
|
||||||
CompEditorModel editorModel = (CompEditorModel) model;
|
|
||||||
BitFieldEditorDialog dlg = new BitFieldEditorDialog(model.viewComposite,
|
|
||||||
provider.dtmService, modelRow, model.showHexNumbers,
|
|
||||||
ordinal -> refreshTableAndSelection(editorModel, ordinal));
|
|
||||||
Component c = provider.getComponent();
|
|
||||||
DockingWindowManager.showDialog(c, dlg);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshTableAndSelection(CompEditorModel editorModel, int ordinal) {
|
|
||||||
editorModel.notifyCompositeChanged();
|
|
||||||
editorModel.setSelection(new int[] { ordinal, ordinal });
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupTableCellEditor() {
|
private void setupTableCellEditor() {
|
||||||
|
|
||||||
table.addPropertyChangeListener("tableCellEditor", evt -> {
|
table.addPropertyChangeListener("tableCellEditor", evt -> {
|
||||||
|
|
|
@ -17,7 +17,8 @@ package ghidra.app.plugin.core.compositeeditor;
|
||||||
|
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.Icon;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
|
||||||
import docking.*;
|
import docking.*;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
|
@ -41,16 +42,20 @@ import utilities.util.reflection.ReflectionUtilities;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Editor provider for a Composite Data Type.
|
* Editor provider for a Composite Data Type.
|
||||||
|
*
|
||||||
|
* @param <T> Specific {@link Composite} type being edited
|
||||||
|
* @param <M> Specific {@link CompositeEditorModel} implementation which supports editing T
|
||||||
*/
|
*/
|
||||||
public abstract class CompositeEditorProvider extends ComponentProviderAdapter
|
public abstract class CompositeEditorProvider<T extends Composite, M extends CompositeEditorModel<T>>
|
||||||
|
extends ComponentProviderAdapter
|
||||||
implements EditorProvider, EditorActionListener {
|
implements EditorProvider, EditorActionListener {
|
||||||
|
|
||||||
protected static final Icon EDITOR_ICON = new GIcon("icon.plugin.composite.editor.provider");
|
protected static final Icon EDITOR_ICON = new GIcon("icon.plugin.composite.editor.provider");
|
||||||
|
|
||||||
protected Plugin plugin;
|
protected Plugin plugin;
|
||||||
protected Category category;
|
protected Category category;
|
||||||
protected CompositeEditorPanel editorPanel;
|
protected CompositeEditorPanel<T, M> editorPanel;
|
||||||
protected CompositeEditorModel editorModel;
|
protected CompositeEditorModel<T> editorModel;
|
||||||
protected WeakSet<EditorListener> listeners; // listeners for the editor closing.
|
protected WeakSet<EditorListener> listeners; // listeners for the editor closing.
|
||||||
|
|
||||||
protected DataTypeManagerService dtmService;
|
protected DataTypeManagerService dtmService;
|
||||||
|
@ -90,7 +95,7 @@ public abstract class CompositeEditorProvider extends ComponentProviderAdapter
|
||||||
setTitle(getName() + " - " + getProviderSubTitle(editorModel.originalComposite));
|
setTitle(getName() + " - " + getProviderSubTitle(editorModel.originalComposite));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CompositeEditorModel getModel() {
|
protected CompositeEditorModel<T> getModel() {
|
||||||
return this.editorModel;
|
return this.editorModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +183,7 @@ public abstract class CompositeEditorProvider extends ComponentProviderAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JComponent getComponent() {
|
public CompositeEditorPanel<T, M> getComponent() {
|
||||||
return editorPanel;
|
return editorPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,8 @@ abstract public class CompositeEditorTableAction extends DockingAction {
|
||||||
static final String COMPONENT_ACTION_GROUP = "4_COMPONENT_EDITOR_ACTION";
|
static final String COMPONENT_ACTION_GROUP = "4_COMPONENT_EDITOR_ACTION";
|
||||||
static final String BITFIELD_ACTION_GROUP = "5_COMPONENT_EDITOR_ACTION";
|
static final String BITFIELD_ACTION_GROUP = "5_COMPONENT_EDITOR_ACTION";
|
||||||
|
|
||||||
protected CompositeEditorProvider provider;
|
protected CompositeEditorProvider<?, ?> provider;
|
||||||
protected CompositeEditorModel model;
|
protected CompositeEditorModel<?> model;
|
||||||
protected String tooltip;
|
protected String tooltip;
|
||||||
protected ImageIcon icon;
|
protected ImageIcon icon;
|
||||||
protected ActionListener listener;
|
protected ActionListener listener;
|
||||||
|
@ -53,12 +53,13 @@ abstract public class CompositeEditorTableAction extends DockingAction {
|
||||||
|
|
||||||
// note: Only call this constructor if you know you do not want to use the shared editor prefix;
|
// note: Only call this constructor if you know you do not want to use the shared editor prefix;
|
||||||
// If you call this, then you must manage your own menu/popup/toolbar data installation
|
// If you call this, then you must manage your own menu/popup/toolbar data installation
|
||||||
protected CompositeEditorTableAction(CompositeEditorProvider provider, String name) {
|
protected CompositeEditorTableAction(CompositeEditorProvider<?, ?> provider, String name) {
|
||||||
super(name, provider.plugin.getName());
|
super(name, provider.plugin.getName());
|
||||||
init(provider);
|
init(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompositeEditorTableAction(CompositeEditorProvider provider, String name, String group,
|
public CompositeEditorTableAction(CompositeEditorProvider<?, ?> provider, String name,
|
||||||
|
String group,
|
||||||
String[] popupPath, String[] menuPath, Icon icon) {
|
String[] popupPath, String[] menuPath, Icon icon) {
|
||||||
super(name, provider.plugin.getName(), KeyBindingType.SHARED);
|
super(name, provider.plugin.getName(), KeyBindingType.SHARED);
|
||||||
init(provider);
|
init(provider);
|
||||||
|
@ -73,7 +74,7 @@ abstract public class CompositeEditorTableAction extends DockingAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init(CompositeEditorProvider editorProvider) {
|
private void init(CompositeEditorProvider<?, ?> editorProvider) {
|
||||||
this.provider = editorProvider;
|
this.provider = editorProvider;
|
||||||
this.model = provider.getModel();
|
this.model = provider.getModel();
|
||||||
this.plugin = provider.plugin;
|
this.plugin = provider.plugin;
|
||||||
|
|
|
@ -23,6 +23,7 @@ import db.util.ErrorHandler;
|
||||||
import ghidra.program.database.DatabaseObject;
|
import ghidra.program.database.DatabaseObject;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.lang.ProgramArchitecture;
|
import ghidra.program.model.lang.ProgramArchitecture;
|
||||||
|
import ghidra.util.Swing;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
@ -30,11 +31,12 @@ import utility.function.Callback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link CompositeViewerDataTypeManager} provides a data type manager that the structure editor
|
* {@link CompositeViewerDataTypeManager} provides a data type manager that the structure editor
|
||||||
* will use internally for updating the structure being edited and tracking all directly and
|
* will use internally for updating the structure being edited and tracks all directly and
|
||||||
* indirectly referenced datatypes. This manager also facilitates undo/redo support within
|
* indirectly referenced datatypes. This manager also facilitates undo/redo support within
|
||||||
* the editor.
|
* the editor.
|
||||||
|
* @param <T> Specific {@link Composite} type being managed
|
||||||
*/
|
*/
|
||||||
public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager
|
public class CompositeViewerDataTypeManager<T extends Composite> extends StandAloneDataTypeManager
|
||||||
implements ErrorHandler {
|
implements ErrorHandler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,16 +44,18 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager
|
||||||
* This is where the edited datatype will be written back to.
|
* This is where the edited datatype will be written back to.
|
||||||
*/
|
*/
|
||||||
private final DataTypeManager originalDTM;
|
private final DataTypeManager originalDTM;
|
||||||
private final Composite originalComposite; // may be null if not resolved into this DTM
|
private final T originalComposite; // may be null if not resolved into this DTM
|
||||||
private final Composite viewComposite; // may be null if not resolved into this DTM
|
private final T viewComposite; // may be null if not resolved into this DTM
|
||||||
|
|
||||||
// Database-backed datatype ID map, view to/from original DTM
|
// Database-backed datatype ID map, view to/from original DTM
|
||||||
// This is needed to account for datatype use and ID alterations across undo/redo
|
// This is needed to account for datatype use and ID alterations across undo/redo
|
||||||
private final IDMapDB dataTypeIDMap;
|
private final IDMapDB dataTypeIDMap;
|
||||||
|
|
||||||
// single editor transaction use only - undo/redo not supported when used
|
// Editor transaction use only - undo/redo not supported if restoreCallback is null
|
||||||
private Callback restoredCallback;
|
private Callback restoredCallback;
|
||||||
|
private Callback changeCallback;
|
||||||
private int transactionId = 0;
|
private int transactionId = 0;
|
||||||
|
private boolean dataTypeChanged;
|
||||||
|
|
||||||
// Modification count used to signal optional clearing of undo/redo stack at the end of a
|
// Modification count used to signal optional clearing of undo/redo stack at the end of a
|
||||||
// transaction should any database modifications occur.
|
// transaction should any database modifications occur.
|
||||||
|
@ -64,13 +68,13 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager
|
||||||
/**
|
/**
|
||||||
* Creates a data type manager that the structure editor will use internally for managing
|
* Creates a data type manager that the structure editor will use internally for managing
|
||||||
* dependencies for an unmanaged structure being edited. A single transaction will be started
|
* dependencies for an unmanaged structure being edited. A single transaction will be started
|
||||||
* with this instantiation and held open until this instance is closed and undo/redo will
|
* with this instantiation and held open until this instance is closed. Undo/redo is
|
||||||
* not be supported.
|
* not be supported.
|
||||||
* @param rootName the root name for this data type manager (usually the program name).
|
* @param rootName the root name for this data type manager (usually the program name).
|
||||||
* @param originalDTM the original data type manager.
|
* @param originalDTM the original data type manager.
|
||||||
*/
|
*/
|
||||||
public CompositeViewerDataTypeManager(String rootName, DataTypeManager originalDTM) {
|
public CompositeViewerDataTypeManager(String rootName, DataTypeManager originalDTM) {
|
||||||
this(rootName, originalDTM, null, null);
|
this(rootName, originalDTM, null, null, null);
|
||||||
clearUndo();
|
clearUndo();
|
||||||
transactionId = startTransaction("Composite Edit");
|
transactionId = startTransaction("Composite Edit");
|
||||||
}
|
}
|
||||||
|
@ -80,11 +84,13 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager
|
||||||
* structure being edited and its dependencies.
|
* structure being edited and its dependencies.
|
||||||
* @param rootName the root name for this data type manager (usually the program name).
|
* @param rootName the root name for this data type manager (usually the program name).
|
||||||
* @param originalComposite the original composite data type that is being edited.
|
* @param originalComposite the original composite data type that is being edited.
|
||||||
|
* @param changeCallback Callback will be invoked when any change is made to the view composite.
|
||||||
* @param restoredCallback Callback will be invoked following any undo/redo.
|
* @param restoredCallback Callback will be invoked following any undo/redo.
|
||||||
*/
|
*/
|
||||||
public CompositeViewerDataTypeManager(String rootName, Composite originalComposite,
|
public CompositeViewerDataTypeManager(String rootName, T originalComposite,
|
||||||
Callback restoredCallback) {
|
Callback changeCallback, Callback restoredCallback) {
|
||||||
this(rootName, originalComposite.getDataTypeManager(), originalComposite, restoredCallback);
|
this(rootName, originalComposite.getDataTypeManager(), originalComposite, changeCallback,
|
||||||
|
restoredCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,13 +98,15 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager
|
||||||
* @param rootName the root name for this data type manager (usually the program name).
|
* @param rootName the root name for this data type manager (usually the program name).
|
||||||
* @param originalDTM the original datatype manager
|
* @param originalDTM the original datatype manager
|
||||||
* @param originalComposite the original composite data type that is being edited. (may be null)
|
* @param originalComposite the original composite data type that is being edited. (may be null)
|
||||||
|
* @param changeCallback Callback will be invoked when any change is made to the view composite.
|
||||||
* @param restoredCallback Callback will be invoked following any undo/redo.
|
* @param restoredCallback Callback will be invoked following any undo/redo.
|
||||||
*/
|
*/
|
||||||
private CompositeViewerDataTypeManager(String rootName, DataTypeManager originalDTM,
|
private CompositeViewerDataTypeManager(String rootName, DataTypeManager originalDTM,
|
||||||
Composite originalComposite, Callback restoredCallback) {
|
T originalComposite, Callback changeCallback, Callback restoredCallback) {
|
||||||
super(rootName, originalDTM.getDataOrganization());
|
super(rootName, originalDTM.getDataOrganization());
|
||||||
this.originalDTM = originalDTM;
|
this.originalDTM = originalDTM;
|
||||||
this.originalComposite = originalComposite;
|
this.originalComposite = originalComposite;
|
||||||
|
this.changeCallback = changeCallback;
|
||||||
this.restoredCallback = restoredCallback;
|
this.restoredCallback = restoredCallback;
|
||||||
|
|
||||||
int txId = startTransaction("Setup for Edit");
|
int txId = startTransaction("Setup for Edit");
|
||||||
|
@ -113,8 +121,9 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager
|
||||||
clearUndo();
|
clearUndo();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Composite resolveViewComposite() {
|
@SuppressWarnings("unchecked")
|
||||||
return originalComposite != null ? (Composite) super.resolve(originalComposite, null)
|
private T resolveViewComposite() {
|
||||||
|
return originalComposite != null ? (T) super.resolve(originalComposite, null)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,10 +169,10 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the view composite if requested during instantiation.
|
* Return the view composite
|
||||||
* @return view composite or null if not resolved during instantiation.
|
* @return view composite or null if not resolved during instantiation.
|
||||||
*/
|
*/
|
||||||
public Composite getResolvedViewComposite() {
|
public T getResolvedViewComposite() {
|
||||||
return viewComposite;
|
return viewComposite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,15 +334,24 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyRestored() {
|
public void dataTypeChanged(DataType dt, boolean isAutoChange) {
|
||||||
super.notifyRestored();
|
super.dataTypeChanged(dt, isAutoChange);
|
||||||
if (restoredCallback != null) {
|
if (dt == viewComposite) {
|
||||||
restoredCallback.call();
|
// Set dataTypeChanged which will trigger changeCallback when transaction fully comitted
|
||||||
|
dataTypeChanged = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void endTransaction(int transactionID, boolean commit) {
|
public void notifyRestored() {
|
||||||
|
super.notifyRestored();
|
||||||
|
if (restoredCallback != null) {
|
||||||
|
Swing.runLater(() -> restoredCallback.call());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized boolean endTransaction(int transactionID, boolean commit) {
|
||||||
|
|
||||||
if (viewComposite != null && getTransactionCount() == 1) {
|
if (viewComposite != null && getTransactionCount() == 1) {
|
||||||
// Perform orphan removal only at the end of the outer-most transaction
|
// Perform orphan removal only at the end of the outer-most transaction
|
||||||
|
@ -342,7 +360,7 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.endTransaction(transactionID, commit);
|
boolean committed = super.endTransaction(transactionID, commit);
|
||||||
|
|
||||||
if (!isTransactionActive() && flattenModCount != -1) {
|
if (!isTransactionActive() && flattenModCount != -1) {
|
||||||
if (flattenModCount != dbHandle.getModCount()) {
|
if (flattenModCount != dbHandle.getModCount()) {
|
||||||
|
@ -351,6 +369,16 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager
|
||||||
}
|
}
|
||||||
flattenModCount = -1;
|
flattenModCount = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (committed && dataTypeChanged && changeCallback != null) {
|
||||||
|
Swing.runLater(() -> changeCallback.call());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getTransactionCount() == 0) {
|
||||||
|
dataTypeChanged = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return committed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkOrphansForRemoval(boolean cleanupIdMaps) {
|
private void checkOrphansForRemoval(boolean cleanupIdMaps) {
|
||||||
|
|
|
@ -27,11 +27,17 @@ import docking.widgets.fieldpanel.support.FieldSelection;
|
||||||
import ghidra.program.database.data.DataTypeUtilities;
|
import ghidra.program.database.data.DataTypeUtilities;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
|
import ghidra.util.exception.AssertException;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import utility.function.Callback;
|
import utility.function.Callback;
|
||||||
|
|
||||||
abstract class CompositeViewerModel extends AbstractTableModel
|
/**
|
||||||
|
* {@link CompositeViewerModel} provides the base composite viewer/editor implementation
|
||||||
|
*
|
||||||
|
* @param <T> Specific {@link Composite} type being managed
|
||||||
|
*/
|
||||||
|
abstract class CompositeViewerModel<T extends Composite> extends AbstractTableModel
|
||||||
implements DataTypeManagerChangeListener {
|
implements DataTypeManagerChangeListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,13 +46,13 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||||
*/
|
*/
|
||||||
protected boolean updatingSelection = false;
|
protected boolean updatingSelection = false;
|
||||||
|
|
||||||
protected Composite originalComposite;
|
protected T originalComposite;
|
||||||
protected DataTypePath originalDataTypePath;
|
protected DataTypePath originalDataTypePath;
|
||||||
protected long originalCompositeId;
|
protected long originalCompositeId;
|
||||||
protected DataTypeManager originalDTM;
|
protected DataTypeManager originalDTM;
|
||||||
|
|
||||||
protected Composite viewComposite;
|
protected T viewComposite;
|
||||||
protected CompositeViewerDataTypeManager viewDTM;
|
protected CompositeViewerDataTypeManager<T> viewDTM;
|
||||||
|
|
||||||
private List<CompositeViewerModelListener> modelListeners = new ArrayList<>();
|
private List<CompositeViewerModelListener> modelListeners = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -79,10 +85,11 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||||
protected int currentEditRow = -1;
|
protected int currentEditRow = -1;
|
||||||
/** the current column for a field edit */
|
/** the current column for a field edit */
|
||||||
protected int currentEditColumn = -1;
|
protected int currentEditColumn = -1;
|
||||||
protected CompositeEditorProvider provider;
|
|
||||||
protected boolean showHexNumbers = false;
|
protected boolean showHexNumbers = false;
|
||||||
|
|
||||||
CompositeViewerModel(CompositeEditorProvider provider) {
|
protected final CompositeEditorProvider<T, ?> provider;
|
||||||
|
|
||||||
|
CompositeViewerModel(CompositeEditorProvider<T, ?> provider) {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
selection = new FieldSelection();
|
selection = new FieldSelection();
|
||||||
adjustWidth();
|
adjustWidth();
|
||||||
|
@ -165,7 +172,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||||
*
|
*
|
||||||
* @param dataType the composite date type to be viewed.
|
* @param dataType the composite date type to be viewed.
|
||||||
*/
|
*/
|
||||||
protected abstract void load(Composite dataType);
|
protected abstract void load(T dataType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unloads the currently loaded composite data type.
|
* Unloads the currently loaded composite data type.
|
||||||
|
@ -276,8 +283,8 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||||
* @return the original composite being viewed or null if nothing is currently loaded in
|
* @return the original composite being viewed or null if nothing is currently loaded in
|
||||||
* the model.
|
* the model.
|
||||||
*/
|
*/
|
||||||
protected Composite getOriginalComposite() {
|
protected T getOriginalComposite() {
|
||||||
Composite existingOriginal = getExistingOriginalComposite();
|
T existingOriginal = getExistingOriginalComposite();
|
||||||
return existingOriginal != null ? existingOriginal : originalComposite;
|
return existingOriginal != null ? existingOriginal : originalComposite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,14 +299,15 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||||
return getExistingOriginalComposite() != null;
|
return getExistingOriginalComposite() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Composite getExistingOriginalComposite() {
|
@SuppressWarnings("unchecked")
|
||||||
|
private T getExistingOriginalComposite() {
|
||||||
long originalId = getCompositeID();
|
long originalId = getCompositeID();
|
||||||
if (originalId != DataTypeManager.NULL_DATATYPE_ID && originalDataTypePath != null &&
|
if (originalId != DataTypeManager.NULL_DATATYPE_ID && originalDataTypePath != null &&
|
||||||
originalDTM != null) {
|
originalDTM != null) {
|
||||||
DataType dt = originalDTM.getDataType(originalId);
|
DataType dt = originalDTM.getDataType(originalId);
|
||||||
if (dt instanceof Composite &&
|
if (dt instanceof Composite &&
|
||||||
DataTypeUtilities.isSameKindDataType(originalComposite, dt)) {
|
DataTypeUtilities.isSameKindDataType(originalComposite, dt)) {
|
||||||
return (Composite) dt;
|
return (T) dt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -729,7 +737,10 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||||
@Override
|
@Override
|
||||||
public void categoryRemoved(DataTypeManager dtm, CategoryPath path) {
|
public void categoryRemoved(DataTypeManager dtm, CategoryPath path) {
|
||||||
if (dtm != originalDTM) {
|
if (dtm != originalDTM) {
|
||||||
return; // Different DTM than the one for this data type.
|
throw new AssertException("Listener only supports original DTM");
|
||||||
|
}
|
||||||
|
if (!isLoaded()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (originalDataTypePath.isAncestor(path)) {
|
if (originalDataTypePath.isAncestor(path)) {
|
||||||
String msg = "\"" + originalDataTypePath.getDataTypeName() + "\" had its category \"" +
|
String msg = "\"" + originalDataTypePath.getDataTypeName() + "\" had its category \"" +
|
||||||
|
@ -754,7 +765,10 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||||
@Override
|
@Override
|
||||||
public void categoryRenamed(DataTypeManager dtm, CategoryPath oldPath, CategoryPath newPath) {
|
public void categoryRenamed(DataTypeManager dtm, CategoryPath oldPath, CategoryPath newPath) {
|
||||||
if (dtm != originalDTM) {
|
if (dtm != originalDTM) {
|
||||||
return; // Different DTM than the one for this data type.
|
throw new AssertException("Listener only supports original DTM");
|
||||||
|
}
|
||||||
|
if (!isLoaded()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (!viewDTM.containsCategory(oldPath)) {
|
if (!viewDTM.containsCategory(oldPath)) {
|
||||||
return;
|
return;
|
||||||
|
@ -782,7 +796,10 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||||
@Override
|
@Override
|
||||||
public void categoryMoved(DataTypeManager dtm, CategoryPath oldPath, CategoryPath newPath) {
|
public void categoryMoved(DataTypeManager dtm, CategoryPath oldPath, CategoryPath newPath) {
|
||||||
if (dtm != originalDTM) {
|
if (dtm != originalDTM) {
|
||||||
return; // Different DTM than the one for this data type.
|
throw new AssertException("Listener only supports original DTM");
|
||||||
|
}
|
||||||
|
if (!isLoaded()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (!viewDTM.containsCategory(oldPath)) {
|
if (!viewDTM.containsCategory(oldPath)) {
|
||||||
return;
|
return;
|
||||||
|
@ -1162,13 +1179,13 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||||
* A notify method to take the listens to notify, along with the method that should be called
|
* A notify method to take the listens to notify, along with the method that should be called
|
||||||
* on each listener.
|
* on each listener.
|
||||||
*
|
*
|
||||||
* @param <T> the type of the listener
|
* @param <L> the type of the listener
|
||||||
* @param listeners the listeners
|
* @param listeners the listeners
|
||||||
* @param method the method to call
|
* @param method the method to call
|
||||||
*/
|
*/
|
||||||
protected <T> void notify(List<T> listeners, Consumer<T> method) {
|
protected <L> void notify(List<L> listeners, Consumer<L> method) {
|
||||||
swing(() -> {
|
swing(() -> {
|
||||||
for (T listener : listeners) {
|
for (L listener : listeners) {
|
||||||
method.accept(listener);
|
method.accept(listener);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -30,7 +30,7 @@ public class CycleGroupAction extends CompositeEditorTableAction {
|
||||||
private final static String GROUP_NAME = DATA_ACTION_GROUP;
|
private final static String GROUP_NAME = DATA_ACTION_GROUP;
|
||||||
private CycleGroup cycleGroup;
|
private CycleGroup cycleGroup;
|
||||||
|
|
||||||
public CycleGroupAction(CompositeEditorProvider provider, CycleGroup cycleGroup) {
|
public CycleGroupAction(CompositeEditorProvider<?, ?> provider, CycleGroup cycleGroup) {
|
||||||
super(provider, cycleGroup.getName());
|
super(provider, cycleGroup.getName());
|
||||||
|
|
||||||
setMenuBarData(
|
setMenuBarData(
|
||||||
|
|
|
@ -75,7 +75,8 @@ public class DataTypeHelper {
|
||||||
* @throws UsrException if the specified data type can't be used at the
|
* @throws UsrException if the specified data type can't be used at the
|
||||||
* specified index in the composite.
|
* specified index in the composite.
|
||||||
*/
|
*/
|
||||||
public static DataType parseDataType(int index, String dtValue, CompositeEditorModel editModel,
|
public static DataType parseDataType(int index, String dtValue,
|
||||||
|
CompositeEditorModel<?> editModel,
|
||||||
DataTypeManager dtManager, DataTypeManagerService dtmService)
|
DataTypeManager dtManager, DataTypeManagerService dtmService)
|
||||||
throws InvalidDataTypeException, UsrException {
|
throws InvalidDataTypeException, UsrException {
|
||||||
|
|
||||||
|
@ -98,7 +99,7 @@ public class DataTypeHelper {
|
||||||
return newDt;
|
return newDt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DataTypeInstance getSizedDataType(CompositeEditorProvider provider, DataType dt,
|
static DataTypeInstance getSizedDataType(CompositeEditorProvider<?, ?> provider, DataType dt,
|
||||||
int defaultSize, int maxSize) throws InvalidDataTypeException {
|
int defaultSize, int maxSize) throws InvalidDataTypeException {
|
||||||
if (dt instanceof FactoryDataType) {
|
if (dt instanceof FactoryDataType) {
|
||||||
throw new InvalidDataTypeException("Factory data types are not allowed.");
|
throw new InvalidDataTypeException("Factory data types are not allowed.");
|
||||||
|
@ -137,7 +138,7 @@ public class DataTypeHelper {
|
||||||
provider.editorModel.usesAlignedLengthComponents());
|
provider.editorModel.usesAlignedLengthComponents());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int requestDtSize(CompositeEditorProvider provider, String dtName,
|
public static int requestDtSize(CompositeEditorProvider<?, ?> provider, String dtName,
|
||||||
int defaultSize, int maxBytes) throws CancelledException {
|
int defaultSize, int maxBytes) throws CancelledException {
|
||||||
NumberInputDialog dtSizeDialog =
|
NumberInputDialog dtSizeDialog =
|
||||||
new NumberInputDialog(dtName + " bytes", defaultSize, 1, maxBytes);
|
new NumberInputDialog(dtName + " bytes", defaultSize, 1, maxBytes);
|
||||||
|
@ -149,7 +150,7 @@ public class DataTypeHelper {
|
||||||
}
|
}
|
||||||
int resultBytes = dtSizeDialog.getValue();
|
int resultBytes = dtSizeDialog.getValue();
|
||||||
|
|
||||||
CompositeEditorModel model = provider.getModel();
|
CompositeEditorModel<?> model = provider.getModel();
|
||||||
model.setLastNumBytes(resultBytes);
|
model.setLastNumBytes(resultBytes);
|
||||||
|
|
||||||
return resultBytes;
|
return resultBytes;
|
||||||
|
@ -163,6 +164,7 @@ public class DataTypeHelper {
|
||||||
* will be returned unchanged. If the user cancels from the size dialog,
|
* will be returned unchanged. If the user cancels from the size dialog,
|
||||||
* then a null is returned.
|
* then a null is returned.
|
||||||
*
|
*
|
||||||
|
* @param model The composite editor model
|
||||||
* @param index the component index of where to add the data type.
|
* @param index the component index of where to add the data type.
|
||||||
* @param dt the data type to add
|
* @param dt the data type to add
|
||||||
* @param useAlignedLength if true a fixed-length primitive data type will use its
|
* @param useAlignedLength if true a fixed-length primitive data type will use its
|
||||||
|
@ -171,7 +173,7 @@ public class DataTypeHelper {
|
||||||
* @return the data type and its size or null if the user canceled when
|
* @return the data type and its size or null if the user canceled when
|
||||||
* prompted for a size.
|
* prompted for a size.
|
||||||
*/
|
*/
|
||||||
public static DataTypeInstance getFixedLength(CompositeEditorModel model, int index,
|
public static DataTypeInstance getFixedLength(CompositeEditorModel<?> model, int index,
|
||||||
DataType dt, boolean useAlignedLength) {
|
DataType dt, boolean useAlignedLength) {
|
||||||
if (dt instanceof FactoryDataType) {
|
if (dt instanceof FactoryDataType) {
|
||||||
model.setStatus("Factory data types are not allowed in a composite data type.");
|
model.setStatus("Factory data types are not allowed in a composite data type.");
|
||||||
|
@ -196,9 +198,9 @@ public class DataTypeHelper {
|
||||||
return DataTypeInstance.getDataTypeInstance(dt, length, useAlignedLength);
|
return DataTypeInstance.getDataTypeInstance(dt, length, useAlignedLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataTypeInstance requestBytes(CompositeEditorModel model, DataType dt,
|
public static DataTypeInstance requestBytes(CompositeEditorModel<?> model, DataType dt,
|
||||||
int maxBytes) {
|
int maxBytes) {
|
||||||
CompositeEditorProvider provider = model.getProvider();
|
CompositeEditorProvider<?, ?> provider = model.getProvider();
|
||||||
DataType actualDt = dt;
|
DataType actualDt = dt;
|
||||||
if (actualDt instanceof TypeDef) {
|
if (actualDt instanceof TypeDef) {
|
||||||
actualDt = ((TypeDef) actualDt).getBaseDataType();
|
actualDt = ((TypeDef) actualDt).getBaseDataType();
|
||||||
|
|
|
@ -36,7 +36,7 @@ public class DeleteAction extends CompositeEditorTableAction {
|
||||||
private final static String[] popupPath = new String[] { "Delete" };
|
private final static String[] popupPath = new String[] { "Delete" };
|
||||||
private final static KeyStroke KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0);
|
private final static KeyStroke KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0);
|
||||||
|
|
||||||
public DeleteAction(CompositeEditorProvider provider) {
|
public DeleteAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, popupPath, null, ICON);
|
super(provider, ACTION_NAME, GROUP_NAME, popupPath, null, ICON);
|
||||||
|
|
||||||
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
||||||
|
|
|
@ -214,11 +214,11 @@ public class DndTableCellRenderer implements TableCellRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param inserting true indicates that only the top of the row is highlighted for feedback.
|
* @param isInsert true indicates that only the top of the row is highlighted for feedback.
|
||||||
* false indicates that the entire selection should be bordered on all sides.
|
* false indicates that the entire selection should be bordered on all sides.
|
||||||
*/
|
*/
|
||||||
public void selectRange(boolean inserting) {
|
public void selectRange(boolean isInsert) {
|
||||||
this.inserting = inserting;
|
this.inserting = isInsert;
|
||||||
int tmpRow = rowForFeedback;
|
int tmpRow = rowForFeedback;
|
||||||
rowForFeedback = -1;
|
rowForFeedback = -1;
|
||||||
rangeMin = -1;
|
rangeMin = -1;
|
||||||
|
|
|
@ -40,7 +40,7 @@ public class DuplicateAction extends CompositeEditorTableAction {
|
||||||
private final static KeyStroke KEY_STROKE =
|
private final static KeyStroke KEY_STROKE =
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.ALT_DOWN_MASK);
|
KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.ALT_DOWN_MASK);
|
||||||
|
|
||||||
public DuplicateAction(CompositeEditorProvider provider) {
|
public DuplicateAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||||
setDescription(DESCRIPTION);
|
setDescription(DESCRIPTION);
|
||||||
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class DuplicateMultipleAction extends CompositeEditorTableAction {
|
||||||
|
|
||||||
private KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_M, InputEvent.ALT_DOWN_MASK);
|
private KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_M, InputEvent.ALT_DOWN_MASK);
|
||||||
|
|
||||||
public DuplicateMultipleAction(CompositeEditorProvider provider) {
|
public DuplicateMultipleAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||||
setDescription(DESCRIPTION);
|
setDescription(DESCRIPTION);
|
||||||
setKeyBindingData(new KeyBindingData(keyStroke));
|
setKeyBindingData(new KeyBindingData(keyStroke));
|
||||||
|
|
|
@ -25,7 +25,7 @@ public class EditBitFieldAction extends CompositeEditorTableAction {
|
||||||
private final static String DESCRIPTION = "Edit an existing bitfield";
|
private final static String DESCRIPTION = "Edit an existing bitfield";
|
||||||
private static String[] POPUP_PATH = new String[] { ACTION_NAME };
|
private static String[] POPUP_PATH = new String[] { ACTION_NAME };
|
||||||
|
|
||||||
public EditBitFieldAction(CompositeEditorProvider provider) {
|
public EditBitFieldAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, null);
|
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, null);
|
||||||
setDescription(DESCRIPTION);
|
setDescription(DESCRIPTION);
|
||||||
if (!(model instanceof CompEditorModel)) {
|
if (!(model instanceof CompEditorModel)) {
|
||||||
|
|
|
@ -33,7 +33,7 @@ public class EditComponentAction extends CompositeEditorTableAction {
|
||||||
private static String[] MENU_PATH = new String[] { ACTION_NAME };
|
private static String[] MENU_PATH = new String[] { ACTION_NAME };
|
||||||
private DataTypeManagerService dtmService;
|
private DataTypeManagerService dtmService;
|
||||||
|
|
||||||
public EditComponentAction(CompositeEditorProvider provider) {
|
public EditComponentAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, MENU_PATH, null);
|
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, MENU_PATH, null);
|
||||||
this.dtmService = provider.dtmService;
|
this.dtmService = provider.dtmService;
|
||||||
setDescription(DESCRIPTION);
|
setDescription(DESCRIPTION);
|
||||||
|
|
|
@ -37,7 +37,7 @@ public class EditFieldAction extends CompositeEditorTableAction {
|
||||||
private static String[] POPUP_PATH = new String[] { ACTION_NAME };
|
private static String[] POPUP_PATH = new String[] { ACTION_NAME };
|
||||||
private static String[] MENU_PATH = new String[] { ACTION_NAME };
|
private static String[] MENU_PATH = new String[] { ACTION_NAME };
|
||||||
|
|
||||||
public EditFieldAction(CompositeEditorProvider provider) {
|
public EditFieldAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, MENU_PATH, null);
|
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, MENU_PATH, null);
|
||||||
setDescription(DESCRIPTION);
|
setDescription(DESCRIPTION);
|
||||||
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
package ghidra.app.plugin.core.compositeeditor;
|
package ghidra.app.plugin.core.compositeeditor;
|
||||||
|
|
||||||
import docking.ComponentProvider;
|
import docking.ComponentProvider;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.DataTypeManager;
|
||||||
|
import ghidra.program.model.data.DataTypePath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface implemented by data type editors.
|
* Interface implemented by data type editors.
|
||||||
|
@ -42,8 +43,7 @@ public interface EditorProvider {
|
||||||
public ComponentProvider getComponentProvider();
|
public ComponentProvider getComponentProvider();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the datatype manager associated with this editor.
|
* {@return the edited datatype's original datatype manager.}
|
||||||
* @return the datatype manager associated with this editor
|
|
||||||
*/
|
*/
|
||||||
public DataTypeManager getDataTypeManager();
|
public DataTypeManager getDataTypeManager();
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ public class FavoritesAction extends CompositeEditorTableAction {
|
||||||
* @param provider the provider that owns this action
|
* @param provider the provider that owns this action
|
||||||
* @param dt the favorite data type
|
* @param dt the favorite data type
|
||||||
*/
|
*/
|
||||||
public FavoritesAction(CompositeEditorProvider provider, DataType dt) {
|
public FavoritesAction(CompositeEditorProvider<?, ?> provider, DataType dt) {
|
||||||
super(provider, dt.getDisplayName());
|
super(provider, dt.getDisplayName());
|
||||||
this.dataType = dt;
|
this.dataType = dt;
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ public class FindReferencesToStructureFieldAction extends CompositeEditorTableAc
|
||||||
private final static String ACTION_NAME = "Find Uses of";
|
private final static String ACTION_NAME = "Find Uses of";
|
||||||
private final static String DESCRIPTION = "Find uses of field in the selected row";
|
private final static String DESCRIPTION = "Find uses of field in the selected row";
|
||||||
|
|
||||||
public FindReferencesToStructureFieldAction(CompositeEditorProvider provider) {
|
public FindReferencesToStructureFieldAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, BASIC_ACTION_GROUP, new String[] { ACTION_NAME }, null, null);
|
super(provider, ACTION_NAME, BASIC_ACTION_GROUP, new String[] { ACTION_NAME }, null, null);
|
||||||
setDescription(DESCRIPTION);
|
setDescription(DESCRIPTION);
|
||||||
setHelpLocation(new HelpLocation(HelpTopics.FIND_REFERENCES, "Data_Types"));
|
setHelpLocation(new HelpLocation(HelpTopics.FIND_REFERENCES, "Data_Types"));
|
||||||
|
|
|
@ -35,7 +35,7 @@ public class HexNumbersAction extends CompositeEditorTableAction implements Togg
|
||||||
private static String[] PATH = new String[] { DESCRIPTION };
|
private static String[] PATH = new String[] { DESCRIPTION };
|
||||||
private boolean isSelected;
|
private boolean isSelected;
|
||||||
|
|
||||||
public HexNumbersAction(CompositeEditorProvider provider) {
|
public HexNumbersAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, PATH, PATH, null);
|
super(provider, ACTION_NAME, GROUP_NAME, PATH, PATH, null);
|
||||||
setDescription(DESCRIPTION);
|
setDescription(DESCRIPTION);
|
||||||
setSelected(model.isShowingNumbersInHex());
|
setSelected(model.isShowingNumbersInHex());
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class InsertUndefinedAction extends CompositeEditorTableAction {
|
||||||
private final static KeyStroke KEY_STROKE =
|
private final static KeyStroke KEY_STROKE =
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_U, InputEvent.ALT_DOWN_MASK);
|
KeyStroke.getKeyStroke(KeyEvent.VK_U, InputEvent.ALT_DOWN_MASK);
|
||||||
|
|
||||||
public InsertUndefinedAction(CompositeEditorProvider provider) {
|
public InsertUndefinedAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||||
setDescription(DESCRIPTION);
|
setDescription(DESCRIPTION);
|
||||||
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class MoveDownAction extends CompositeEditorTableAction {
|
||||||
private final static KeyStroke KEY_STROKE =
|
private final static KeyStroke KEY_STROKE =
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.ALT_DOWN_MASK);
|
KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.ALT_DOWN_MASK);
|
||||||
|
|
||||||
public MoveDownAction(CompositeEditorProvider provider) {
|
public MoveDownAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||||
setDescription(DESCRIPTION);
|
setDescription(DESCRIPTION);
|
||||||
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class MoveUpAction extends CompositeEditorTableAction {
|
||||||
private final static KeyStroke KEY_STROKE =
|
private final static KeyStroke KEY_STROKE =
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.ALT_DOWN_MASK);
|
KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.ALT_DOWN_MASK);
|
||||||
|
|
||||||
public MoveUpAction(CompositeEditorProvider provider) {
|
public MoveUpAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||||
setDescription(DESCRIPTION);
|
setDescription(DESCRIPTION);
|
||||||
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class PointerAction extends CompositeEditorTableAction {
|
||||||
private final static String DESCRIPTION = "Create a pointer(s) on the selection";
|
private final static String DESCRIPTION = "Create a pointer(s) on the selection";
|
||||||
private final static DataType POINTER_DT = new PointerDataType();
|
private final static DataType POINTER_DT = new PointerDataType();
|
||||||
|
|
||||||
public PointerAction(CompositeEditorProvider provider) {
|
public PointerAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, null, null, null);
|
super(provider, ACTION_NAME, GROUP_NAME, null, null, null);
|
||||||
setDescription(DESCRIPTION);
|
setDescription(DESCRIPTION);
|
||||||
setKeyBindingData(new KeyBindingData(KeyEvent.VK_P, 0));
|
setKeyBindingData(new KeyBindingData(KeyEvent.VK_P, 0));
|
||||||
|
|
|
@ -32,7 +32,7 @@ public class RedoChangeAction extends CompositeEditorTableAction {
|
||||||
private final static Icon ICON = new GIcon("icon.redo");
|
private final static Icon ICON = new GIcon("icon.redo");
|
||||||
private final static String[] POPUP_PATH = new String[] { DESCRIPTION };
|
private final static String[] POPUP_PATH = new String[] { DESCRIPTION };
|
||||||
|
|
||||||
public RedoChangeAction(CompositeEditorProvider provider) {
|
public RedoChangeAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||||
setKeyBindingData(new KeyBindingData("ctrl shift Z"));
|
setKeyBindingData(new KeyBindingData("ctrl shift Z"));
|
||||||
setDescription("Redo editor change");
|
setDescription("Redo editor change");
|
||||||
|
@ -43,8 +43,10 @@ public class RedoChangeAction extends CompositeEditorTableAction {
|
||||||
if (!isEnabledForContext(context)) {
|
if (!isEnabledForContext(context)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CompositeViewerDataTypeManager viewDTM = model.getViewDataTypeManager();
|
CompositeViewerDataTypeManager<?> viewDTM = model.getViewDataTypeManager();
|
||||||
viewDTM.redo();
|
viewDTM.redo();
|
||||||
|
|
||||||
|
model.clearStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -52,7 +54,7 @@ public class RedoChangeAction extends CompositeEditorTableAction {
|
||||||
if (hasIncompleteFieldEntry()) {
|
if (hasIncompleteFieldEntry()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
CompositeViewerDataTypeManager viewDTM = model.getViewDataTypeManager();
|
CompositeViewerDataTypeManager<?> viewDTM = model.getViewDataTypeManager();
|
||||||
boolean canRedo = viewDTM.canRedo();
|
boolean canRedo = viewDTM.canRedo();
|
||||||
setEnabled(canRedo);
|
setEnabled(canRedo);
|
||||||
String description = DESCRIPTION + (canRedo ? (": " + viewDTM.getRedoName()) : "");
|
String description = DESCRIPTION + (canRedo ? (": " + viewDTM.getRedoName()) : "");
|
||||||
|
|
|
@ -31,13 +31,13 @@ public class SearchControlPanel extends JPanel {
|
||||||
|
|
||||||
private static final Icon NEXT_ICON = new GIcon("icon.plugin.composite.editor.search.next");
|
private static final Icon NEXT_ICON = new GIcon("icon.plugin.composite.editor.search.next");
|
||||||
private static final Icon PREV_ICON = new GIcon("icon.plugin.composite.editor.search.previous");
|
private static final Icon PREV_ICON = new GIcon("icon.plugin.composite.editor.search.previous");
|
||||||
private CompositeEditorPanel editorPanel;
|
private CompositeEditorPanel<?, ?> editorPanel;
|
||||||
private JTextField textField;
|
private JTextField textField;
|
||||||
|
|
||||||
private EmptyBorderButton searchNext;
|
private EmptyBorderButton searchNext;
|
||||||
private EmptyBorderButton searchPrevious;
|
private EmptyBorderButton searchPrevious;
|
||||||
|
|
||||||
public SearchControlPanel(CompositeEditorPanel editorPanel) {
|
public SearchControlPanel(CompositeEditorPanel<?, ?> editorPanel) {
|
||||||
this.editorPanel = editorPanel;
|
this.editorPanel = editorPanel;
|
||||||
|
|
||||||
setLayout(new BorderLayout());
|
setLayout(new BorderLayout());
|
||||||
|
|
|
@ -32,7 +32,7 @@ public class ShowComponentPathAction extends CompositeEditorTableAction {
|
||||||
private static String[] POPUP_PATH = new String[] { ACTION_NAME };
|
private static String[] POPUP_PATH = new String[] { ACTION_NAME };
|
||||||
private static String[] MENU_PATH = new String[] { ACTION_NAME };
|
private static String[] MENU_PATH = new String[] { ACTION_NAME };
|
||||||
|
|
||||||
public ShowComponentPathAction(CompositeEditorProvider provider) {
|
public ShowComponentPathAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, MENU_PATH, null);
|
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, MENU_PATH, null);
|
||||||
setDescription(DESCRIPTION);
|
setDescription(DESCRIPTION);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ public class ShowDataTypeInTreeAction extends CompositeEditorTableAction {
|
||||||
private static final String TOOLBAR_GROUP = "4_COMPONENT_EDITOR_ACTION";
|
private static final String TOOLBAR_GROUP = "4_COMPONENT_EDITOR_ACTION";
|
||||||
private static final Icon ICON = new GIcon("icon.plugin.composite.editor.show.type");
|
private static final Icon ICON = new GIcon("icon.plugin.composite.editor.show.type");
|
||||||
|
|
||||||
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));
|
setToolBarData(new ToolBarData(ICON, TOOLBAR_GROUP));
|
||||||
|
|
|
@ -33,7 +33,7 @@ import ghidra.util.exception.*;
|
||||||
import ghidra.util.task.TaskLauncher;
|
import ghidra.util.task.TaskLauncher;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
class StructureEditorModel extends CompEditorModel {
|
class StructureEditorModel extends CompEditorModel<Structure> {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static final int OFFSET = 0;
|
private static final int OFFSET = 0;
|
||||||
|
@ -184,14 +184,13 @@ class StructureEditorModel extends CompEditorModel {
|
||||||
if (rowIndex < 0 || rowIndex == numComponents) {
|
if (rowIndex < 0 || rowIndex == numComponents) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Structure viewStruct = (Structure) viewComposite;
|
|
||||||
if (rowIndex > numComponents) {
|
if (rowIndex > numComponents) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (isShowingUndefinedBytes()) {
|
if (isShowingUndefinedBytes()) {
|
||||||
return viewComposite.getComponent(rowIndex);
|
return viewComposite.getComponent(rowIndex);
|
||||||
}
|
}
|
||||||
DataTypeComponent[] definedComponents = viewStruct.getDefinedComponents();
|
DataTypeComponent[] definedComponents = viewComposite.getDefinedComponents();
|
||||||
return definedComponents[rowIndex];
|
return definedComponents[rowIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,8 +214,7 @@ class StructureEditorModel extends CompEditorModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
viewDTM.withTransaction("Set Size", () -> {
|
viewDTM.withTransaction("Set Size", () -> {
|
||||||
Structure structure = (Structure) viewComposite;
|
viewComposite.setLength(size);
|
||||||
structure.setLength(size);
|
|
||||||
});
|
});
|
||||||
notifyCompositeChanged();
|
notifyCompositeChanged();
|
||||||
}
|
}
|
||||||
|
@ -278,7 +276,7 @@ class StructureEditorModel extends CompEditorModel {
|
||||||
}
|
}
|
||||||
boolean isSelected = selection.containsEntirely(BigInteger.valueOf(indices[i]));
|
boolean isSelected = selection.containsEntirely(BigInteger.valueOf(indices[i]));
|
||||||
int numBytes = comp.getLength();
|
int numBytes = comp.getLength();
|
||||||
((Structure) viewComposite).clearComponent(indices[i]);
|
viewComposite.clearComponent(indices[i]);
|
||||||
|
|
||||||
// Adjust the selection due to the clear.
|
// Adjust the selection due to the clear.
|
||||||
adjustSelection(indices[i] + 1, numBytes - 1);
|
adjustSelection(indices[i] + 1, numBytes - 1);
|
||||||
|
@ -291,7 +289,6 @@ class StructureEditorModel extends CompEditorModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
componentEdited();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -366,7 +363,6 @@ class StructureEditorModel extends CompEditorModel {
|
||||||
// Ensure that last added component is selected to allow for repeated duplication
|
// Ensure that last added component is selected to allow for repeated duplication
|
||||||
setSelection(new int[] { index + multiple });
|
setSelection(new int[] { index + multiple });
|
||||||
|
|
||||||
componentEdited();
|
|
||||||
lastNumDuplicates = multiple;
|
lastNumDuplicates = multiple;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,7 +481,6 @@ class StructureEditorModel extends CompEditorModel {
|
||||||
int newIndex = startRowIndex - 1;
|
int newIndex = startRowIndex - 1;
|
||||||
moved = shiftComponentsUp(startRowIndex, endRowIndex);
|
moved = shiftComponentsUp(startRowIndex, endRowIndex);
|
||||||
if (moved) {
|
if (moved) {
|
||||||
componentEdited();
|
|
||||||
FieldSelection tmpFieldSelection = new FieldSelection();
|
FieldSelection tmpFieldSelection = new FieldSelection();
|
||||||
tmpFieldSelection.addRange(newIndex, newIndex + numSelected);
|
tmpFieldSelection.addRange(newIndex, newIndex + numSelected);
|
||||||
setSelection(tmpFieldSelection);
|
setSelection(tmpFieldSelection);
|
||||||
|
@ -509,7 +504,6 @@ class StructureEditorModel extends CompEditorModel {
|
||||||
int newIndex = startIndex + 1;
|
int newIndex = startIndex + 1;
|
||||||
moved = shiftComponentsDown(startIndex, endIndex);
|
moved = shiftComponentsDown(startIndex, endIndex);
|
||||||
if (moved) {
|
if (moved) {
|
||||||
componentEdited();
|
|
||||||
FieldSelection tmpFieldSelection = new FieldSelection();
|
FieldSelection tmpFieldSelection = new FieldSelection();
|
||||||
tmpFieldSelection.addRange(newIndex, newIndex + numSelected);
|
tmpFieldSelection.addRange(newIndex, newIndex + numSelected);
|
||||||
setSelection(tmpFieldSelection);
|
setSelection(tmpFieldSelection);
|
||||||
|
@ -865,7 +859,7 @@ class StructureEditorModel extends CompEditorModel {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
BitFieldDataType bitfield = (BitFieldDataType) dataType;
|
BitFieldDataType bitfield = (BitFieldDataType) dataType;
|
||||||
dtc = ((Structure) viewComposite).insertBitField(rowIndex, length,
|
dtc = viewComposite.insertBitField(rowIndex, length,
|
||||||
bitfield.getBitOffset(), bitfield.getBaseDataType(),
|
bitfield.getBitOffset(), bitfield.getBaseDataType(),
|
||||||
bitfield.getDeclaredBitSize(), name, comment);
|
bitfield.getDeclaredBitSize(), name, comment);
|
||||||
}
|
}
|
||||||
|
@ -927,7 +921,7 @@ class StructureEditorModel extends CompEditorModel {
|
||||||
if (!isPackingEnabled() && !isAtEnd(rowIndex)) {
|
if (!isPackingEnabled() && !isAtEnd(rowIndex)) {
|
||||||
int origLen = getComponent(rowIndex).getLength();
|
int origLen = getComponent(rowIndex).getLength();
|
||||||
dtc = viewDTM.withTransaction("Replace Component", () -> {
|
dtc = viewDTM.withTransaction("Replace Component", () -> {
|
||||||
return ((Structure) viewComposite).replace(componentOrdinal, dataType, length,
|
return viewComposite.replace(componentOrdinal, dataType, length,
|
||||||
name, comment);
|
name, comment);
|
||||||
});
|
});
|
||||||
diffLen = origLen - dtc.getLength();
|
diffLen = origLen - dtc.getLength();
|
||||||
|
@ -948,16 +942,15 @@ class StructureEditorModel extends CompEditorModel {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dtc = viewDTM.withTransaction("Replace Component", () -> {
|
dtc = viewDTM.withTransaction("Replace Component", () -> {
|
||||||
Structure struct = (Structure) viewComposite;
|
|
||||||
DataTypeComponent comp = getComponent(rowIndex);
|
DataTypeComponent comp = getComponent(rowIndex);
|
||||||
if (!isPackingEnabled()) {
|
if (!isPackingEnabled()) {
|
||||||
// We are at end with packing disabled - grow structure if needed
|
// We are at end with packing disabled - grow structure if needed
|
||||||
int avail = comp.getLength() + getNumUndefinedBytesAfter(comp);
|
int avail = comp.getLength() + getNumUndefinedBytesAfter(comp);
|
||||||
if (length > avail) {
|
if (length > avail) {
|
||||||
struct.growStructure(length - avail);
|
viewComposite.growStructure(length - avail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ((Structure) viewComposite).replace(componentOrdinal, dataType, length,
|
return viewComposite.replace(componentOrdinal, dataType, length,
|
||||||
name, comment);
|
name, comment);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1052,9 +1045,8 @@ class StructureEditorModel extends CompEditorModel {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void replaceOriginalComponents() {
|
protected void replaceOriginalComponents() {
|
||||||
Structure dt = (Structure) getOriginalComposite();
|
if (originalComposite != null) {
|
||||||
if (dt != null) {
|
originalComposite.replaceWith(viewComposite);
|
||||||
dt.replaceWith(viewComposite);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new RuntimeException("ERROR: Couldn't replace structure components in " +
|
throw new RuntimeException("ERROR: Couldn't replace structure components in " +
|
||||||
|
@ -1302,8 +1294,6 @@ class StructureEditorModel extends CompEditorModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
viewDTM.withTransaction("Unpack Component", () -> {
|
viewDTM.withTransaction("Unpack Component", () -> {
|
||||||
Structure viewStruct = (Structure) viewComposite;
|
|
||||||
|
|
||||||
// Get the field name and comment before removing.
|
// Get the field name and comment before removing.
|
||||||
String fieldName = currentComp.getFieldName();
|
String fieldName = currentComp.getFieldName();
|
||||||
String comment = currentComp.getComment();
|
String comment = currentComp.getComment();
|
||||||
|
@ -1346,13 +1336,13 @@ class StructureEditorModel extends CompEditorModel {
|
||||||
if (!isPackingEnabled()) {
|
if (!isPackingEnabled()) {
|
||||||
if (dtc.isBitFieldComponent()) {
|
if (dtc.isBitFieldComponent()) {
|
||||||
BitFieldDataType bitfield = (BitFieldDataType) dt;
|
BitFieldDataType bitfield = (BitFieldDataType) dt;
|
||||||
viewStruct.insertBitFieldAt(currentOffset + dtc.getOffset(),
|
viewComposite.insertBitFieldAt(currentOffset + dtc.getOffset(),
|
||||||
compLength, bitfield.getBitOffset(), bitfield.getBaseDataType(),
|
compLength, bitfield.getBitOffset(), bitfield.getBaseDataType(),
|
||||||
bitfield.getDeclaredBitSize(), dtc.getFieldName(),
|
bitfield.getDeclaredBitSize(), dtc.getFieldName(),
|
||||||
dtc.getComment());
|
dtc.getComment());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
viewStruct.insertAtOffset(currentOffset + dtc.getOffset(), dt,
|
viewComposite.insertAtOffset(currentOffset + dtc.getOffset(), dt,
|
||||||
compLength, dtc.getFieldName(), dtc.getComment());
|
compLength, dtc.getFieldName(), dtc.getComment());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1379,7 +1369,6 @@ class StructureEditorModel extends CompEditorModel {
|
||||||
comp.setComment(comment);
|
comp.setComment(comment);
|
||||||
});
|
});
|
||||||
fixSelection();
|
fixSelection();
|
||||||
componentEdited();
|
|
||||||
selectionChanged();
|
selectionChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
/* ###
|
|
||||||
* IP: GHIDRA
|
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
|
|
||||||
public interface StructureEditorModelListener extends CompositeEditorModelListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called whenever the structure data type editor internal packing state changes
|
|
||||||
* for the data type being edited.
|
|
||||||
* Whether the structure is free form, aligned, or packed to a particular maximum alignment.
|
|
||||||
*
|
|
||||||
* @param type the new packing state: FREE_FORM, ALIGN, PACK, PACK2, PACK4, or PACK8.
|
|
||||||
*/
|
|
||||||
public abstract void internalAlignmentStateChanged(boolean aligned);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called whenever the structure data type editor internal packing state changes
|
|
||||||
* for the data type being edited.
|
|
||||||
* Whether the structure is free form, aligned, or packed to a particular maximum alignment.
|
|
||||||
*
|
|
||||||
* @param type the new packing state: FREE_FORM, ALIGN, PACK, PACK2, PACK4, or PACK8.
|
|
||||||
*/
|
|
||||||
public abstract void packStateChanged(long packingValue);
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
/* ###
|
||||||
|
* 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 java.awt.Component;
|
||||||
|
|
||||||
|
import docking.DockingWindowManager;
|
||||||
|
import ghidra.program.model.data.DataTypeComponent;
|
||||||
|
import ghidra.program.model.data.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Editor panel for Union datatype
|
||||||
|
*/
|
||||||
|
public class StructureEditorPanel extends CompEditorPanel<Structure, StructureEditorModel> {
|
||||||
|
|
||||||
|
public StructureEditorPanel(StructureEditorModel model, StructureEditorProvider provider) {
|
||||||
|
super(model, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean launchBitFieldEditor(int modelRow, int modelColumn) {
|
||||||
|
if (!model.viewComposite.isPackingEnabled() &&
|
||||||
|
model.getDataTypeColumn() == modelColumn && modelRow < model.getNumComponents()) {
|
||||||
|
// check if we are attempting to edit a bitfield
|
||||||
|
DataTypeComponent dtComponent = model.getComponent(modelRow);
|
||||||
|
if (dtComponent.isBitFieldComponent()) {
|
||||||
|
table.getCellEditor().cancelCellEditing();
|
||||||
|
BitFieldEditorDialog dlg = new BitFieldEditorDialog(model.viewComposite,
|
||||||
|
provider.dtmService, modelRow, model.showHexNumbers,
|
||||||
|
ordinal -> refreshTableAndSelection(model, ordinal));
|
||||||
|
Component c = provider.getComponent();
|
||||||
|
DockingWindowManager.showDialog(c, dlg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshTableAndSelection(StructureEditorModel editorModel, int ordinal) {
|
||||||
|
editorModel.notifyCompositeChanged();
|
||||||
|
editorModel.setSelection(new int[] { ordinal, ordinal });
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,7 +27,8 @@ 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<Structure, StructureEditorModel> {
|
||||||
|
|
||||||
private BitFieldEditorDialog bitFieldEditor;
|
private BitFieldEditorDialog bitFieldEditor;
|
||||||
|
|
||||||
|
@ -41,7 +42,7 @@ public class StructureEditorProvider extends CompositeEditorProvider {
|
||||||
editorModel = new StructureEditorModel(this, showHexNumbers);
|
editorModel = new StructureEditorModel(this, showHexNumbers);
|
||||||
editorModel.load(structureDataType);
|
editorModel.load(structureDataType);
|
||||||
initializeActions();
|
initializeActions();
|
||||||
editorPanel = new CompEditorPanel((StructureEditorModel) editorModel, this);
|
editorPanel = new StructureEditorPanel((StructureEditorModel) editorModel, this);
|
||||||
plugin.getTool().addComponentProvider(this, true);
|
plugin.getTool().addComponentProvider(this, true);
|
||||||
updateTitle();
|
updateTitle();
|
||||||
addActionsToTool();
|
addActionsToTool();
|
||||||
|
|
|
@ -32,7 +32,7 @@ public class UndoChangeAction extends CompositeEditorTableAction {
|
||||||
private final static Icon ICON = new GIcon("icon.undo");
|
private final static Icon ICON = new GIcon("icon.undo");
|
||||||
private final static String[] POPUP_PATH = new String[] { DESCRIPTION };
|
private final static String[] POPUP_PATH = new String[] { DESCRIPTION };
|
||||||
|
|
||||||
public UndoChangeAction(CompositeEditorProvider provider) {
|
public UndoChangeAction(CompositeEditorProvider<?, ?> provider) {
|
||||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||||
setKeyBindingData(new KeyBindingData("ctrl Z"));
|
setKeyBindingData(new KeyBindingData("ctrl Z"));
|
||||||
setDescription(DESCRIPTION);
|
setDescription(DESCRIPTION);
|
||||||
|
@ -43,8 +43,10 @@ public class UndoChangeAction extends CompositeEditorTableAction {
|
||||||
if (!isEnabledForContext(context)) {
|
if (!isEnabledForContext(context)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CompositeViewerDataTypeManager viewDTM = model.getViewDataTypeManager();
|
CompositeViewerDataTypeManager<?> viewDTM = model.getViewDataTypeManager();
|
||||||
viewDTM.undo();
|
viewDTM.undo();
|
||||||
|
|
||||||
|
model.clearStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -52,7 +54,7 @@ public class UndoChangeAction extends CompositeEditorTableAction {
|
||||||
if (hasIncompleteFieldEntry()) {
|
if (hasIncompleteFieldEntry()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
CompositeViewerDataTypeManager viewDTM = model.getViewDataTypeManager();
|
CompositeViewerDataTypeManager<?> viewDTM = model.getViewDataTypeManager();
|
||||||
boolean canUndo = viewDTM.canUndo();
|
boolean canUndo = viewDTM.canUndo();
|
||||||
setEnabled(canUndo);
|
setEnabled(canUndo);
|
||||||
String description = DESCRIPTION + (canUndo ? (": " + viewDTM.getUndoName()) : "");
|
String description = DESCRIPTION + (canUndo ? (": " + viewDTM.getUndoName()) : "");
|
||||||
|
|
|
@ -48,7 +48,7 @@ import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.exception.UsrException;
|
import ghidra.util.exception.UsrException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
class UnionEditorModel extends CompEditorModel {
|
class UnionEditorModel extends CompEditorModel<Union> {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static final int LENGTH = 0;
|
private static final int LENGTH = 0;
|
||||||
|
@ -465,7 +465,6 @@ class UnionEditorModel extends CompEditorModel {
|
||||||
selection.addRange(rowIndex, rowIndex + 1);
|
selection.addRange(rowIndex, rowIndex + 1);
|
||||||
fixSelection();
|
fixSelection();
|
||||||
}
|
}
|
||||||
componentEdited();
|
|
||||||
return dtc;
|
return dtc;
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException exc) {
|
catch (IllegalArgumentException exc) {
|
||||||
|
|
|
@ -17,9 +17,15 @@ package ghidra.app.plugin.core.compositeeditor;
|
||||||
|
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
public class UnionEditorPanel extends CompEditorPanel {
|
import ghidra.program.model.data.Union;
|
||||||
|
|
||||||
public UnionEditorPanel(UnionEditorModel model, CompositeEditorProvider provider) {
|
/**
|
||||||
|
* Editor panel for Union datatype
|
||||||
|
*/
|
||||||
|
public class UnionEditorPanel extends CompEditorPanel<Union, UnionEditorModel> {
|
||||||
|
|
||||||
|
public UnionEditorPanel(UnionEditorModel model,
|
||||||
|
CompositeEditorProvider<Union, UnionEditorModel> provider) {
|
||||||
super(model, provider);
|
super(model, provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ import ghidra.program.model.data.Union;
|
||||||
/**
|
/**
|
||||||
* Editor for a Union Data Type.
|
* Editor for a Union Data Type.
|
||||||
*/
|
*/
|
||||||
public class UnionEditorProvider extends CompositeEditorProvider {
|
public class UnionEditorProvider extends CompositeEditorProvider<Union, UnionEditorModel> {
|
||||||
|
|
||||||
protected static final Icon UNION_EDITOR_ICON =
|
protected static final Icon UNION_EDITOR_ICON =
|
||||||
new GIcon("icon.plugin.composite.editor.provider.union");
|
new GIcon("icon.plugin.composite.editor.provider.union");
|
||||||
|
|
|
@ -23,8 +23,10 @@ import ghidra.program.model.data.*;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BiDirectionDataType is a special structure data type that allows both positive and negative
|
* {@link BiDirectionDataType} is a special structure data type that allows both positive and
|
||||||
* offset values.
|
* negative offset values.
|
||||||
|
* <P>
|
||||||
|
* NOTE: This special purpose datatype does not support resolving with a {@link DataTypeManager}
|
||||||
*/
|
*/
|
||||||
public abstract class BiDirectionDataType extends StructureDataType
|
public abstract class BiDirectionDataType extends StructureDataType
|
||||||
implements BiDirectionStructure {
|
implements BiDirectionStructure {
|
||||||
|
@ -36,8 +38,12 @@ public abstract class BiDirectionDataType extends StructureDataType
|
||||||
protected int splitOffset; // division offset between negative/positive halves
|
protected int splitOffset; // division offset between negative/positive halves
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param name
|
* Construct {@link BiDirectionDataType}
|
||||||
* @param length
|
* @param name data type display name
|
||||||
|
* @param negativeLength negative allocation size
|
||||||
|
* @param positiveLength positive allocation size
|
||||||
|
* @param splitOffset division offset between negative/positive halves
|
||||||
|
* @param dtm associated datatype manager for component datatypes
|
||||||
*/
|
*/
|
||||||
protected BiDirectionDataType(String name, int negativeLength, int positiveLength,
|
protected BiDirectionDataType(String name, int negativeLength, int positiveLength,
|
||||||
int splitOffset, DataTypeManager dtm) {
|
int splitOffset, DataTypeManager dtm) {
|
||||||
|
@ -47,14 +53,6 @@ public abstract class BiDirectionDataType extends StructureDataType
|
||||||
this.splitOffset = splitOffset;
|
this.splitOffset = splitOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BiDirectionDataType(CategoryPath catPath, String name, int negativeLength,
|
|
||||||
int positiveLength, int splitOffset, DataTypeManager dtm) {
|
|
||||||
super(catPath, name, negativeLength + positiveLength, dtm);
|
|
||||||
this.negativeLength = negativeLength;
|
|
||||||
this.positiveLength = positiveLength;
|
|
||||||
this.splitOffset = splitOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DataType validateDataType(DataType dataType) {
|
protected DataType validateDataType(DataType dataType) {
|
||||||
if (DataTypeComponent.usesZeroLengthComponent(dataType)) {
|
if (DataTypeComponent.usesZeroLengthComponent(dataType)) {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -35,7 +34,7 @@ public interface BiDirectionStructure extends Structure {
|
||||||
/**
|
/**
|
||||||
* Get the component offset which represents the division point
|
* Get the component offset which represents the division point
|
||||||
* between the positive and negative halves of the structure.
|
* between the positive and negative halves of the structure.
|
||||||
* @return
|
* @return split offset
|
||||||
*/
|
*/
|
||||||
public abstract int getSplitOffset();
|
public abstract int getSplitOffset();
|
||||||
|
|
||||||
|
|
|
@ -15,12 +15,13 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.stackeditor;
|
package ghidra.app.plugin.core.stackeditor;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
import ghidra.app.plugin.core.compositeeditor.EditorListener;
|
import ghidra.app.plugin.core.compositeeditor.EditorListener;
|
||||||
import ghidra.app.plugin.core.compositeeditor.EditorProvider;
|
import ghidra.app.plugin.core.compositeeditor.EditorProvider;
|
||||||
import ghidra.framework.model.DomainObject;
|
import ghidra.framework.model.DomainObject;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.Function;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages edit sessions of function stack frames for multiple open programs.
|
* Manages edit sessions of function stack frames for multiple open programs.
|
||||||
|
@ -33,7 +34,6 @@ public class StackEditorManager implements EditorListener {
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param plugin the plugin that owns this manager.
|
* @param plugin the plugin that owns this manager.
|
||||||
* @param program the active program
|
|
||||||
*/
|
*/
|
||||||
public StackEditorManager(StackEditorManagerPlugin plugin) {
|
public StackEditorManager(StackEditorManagerPlugin plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
@ -51,6 +51,7 @@ public class StackEditorManager implements EditorListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pop up the editor dialog for the given stack frame.
|
* Pop up the editor dialog for the given stack frame.
|
||||||
|
* @param function function whose stack frame is to be edited
|
||||||
*/
|
*/
|
||||||
public void edit(Function function) {
|
public void edit(Function function) {
|
||||||
StackEditorProvider editor = editorMap.get(function);
|
StackEditorProvider editor = editorMap.get(function);
|
||||||
|
@ -67,28 +68,12 @@ public class StackEditorManager implements EditorListener {
|
||||||
/**
|
/**
|
||||||
* Subclass should override this method if it is interested in
|
* Subclass should override this method if it is interested in
|
||||||
* close program events.
|
* close program events.
|
||||||
|
* @param closedProgram program which was closed
|
||||||
*/
|
*/
|
||||||
protected void programClosed(Program closedProgram) {
|
protected void programClosed(Program closedProgram) {
|
||||||
dismissEditors(closedProgram);
|
dismissEditors(closedProgram);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the stack editor provider that is currently editing the stack frame
|
|
||||||
* of the named function.
|
|
||||||
* @param functionName the name of the function
|
|
||||||
* @return the stack frame editor provider or null if it isn't being edited.
|
|
||||||
*/
|
|
||||||
StackEditorProvider getProvider(Program program, String functionName) {
|
|
||||||
Iterator<Function> iter = editorMap.keySet().iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
Function function = iter.next();
|
|
||||||
if (program == function.getProgram() && function.getName().equals(functionName)) {
|
|
||||||
return editorMap.get(function);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if there is at least one stack frame editor in use.
|
* Returns true if there is at least one stack frame editor in use.
|
||||||
* @return true if editing stack frame(s).
|
* @return true if editing stack frame(s).
|
||||||
|
@ -99,6 +84,7 @@ public class StackEditorManager implements EditorListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dismiss all open stack frame editors for the indicated program.
|
* Dismiss all open stack frame editors for the indicated program.
|
||||||
|
* @param program program whose editors should close
|
||||||
*/
|
*/
|
||||||
void dismissEditors(Program program) {
|
void dismissEditors(Program program) {
|
||||||
List<Function> list = new ArrayList<Function>(editorMap.keySet());
|
List<Function> list = new ArrayList<Function>(editorMap.keySet());
|
||||||
|
@ -138,14 +124,12 @@ public class StackEditorManager implements EditorListener {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void closed(EditorProvider editor) {
|
public void closed(EditorProvider editor) {
|
||||||
StackEditorProvider stackEditorProvider = (StackEditorProvider) editor;
|
StackEditorProvider stackEditorProvider = (StackEditorProvider) editor;
|
||||||
editorMap.remove(stackEditorProvider.getFunction());
|
editorMap.remove(stackEditorProvider.getFunction());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see ghidra.framework.plugintool.Plugin#canCloseDomainObject(DomainObject)
|
|
||||||
*/
|
|
||||||
protected boolean canCloseDomainObject(DomainObject dObj) {
|
protected boolean canCloseDomainObject(DomainObject dObj) {
|
||||||
if (!(dObj instanceof Program)) {
|
if (!(dObj instanceof Program)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -153,9 +137,6 @@ public class StackEditorManager implements EditorListener {
|
||||||
return checkEditors((Program) dObj);
|
return checkEditors((Program) dObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see ghidra.framework.plugintool.Plugin#canClose()
|
|
||||||
*/
|
|
||||||
protected boolean canClose() {
|
protected boolean canClose() {
|
||||||
return checkEditors(null);
|
return checkEditors(null);
|
||||||
}
|
}
|
||||||
|
@ -167,14 +148,4 @@ public class StackEditorManager implements EditorListener {
|
||||||
editorMap.clear();
|
editorMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current editor for the specified function
|
|
||||||
* @param function the function
|
|
||||||
* @return the stack editor if the function's stack is being edited.
|
|
||||||
* Otherwise, returns null if not being edited.
|
|
||||||
*/
|
|
||||||
public StackEditorProvider getProvider(Function function) {
|
|
||||||
return editorMap.get(function.getStackFrame());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ package ghidra.app.plugin.core.stackeditor;
|
||||||
import ghidra.app.CorePluginPackage;
|
import ghidra.app.CorePluginPackage;
|
||||||
import ghidra.app.events.ProgramClosedPluginEvent;
|
import ghidra.app.events.ProgramClosedPluginEvent;
|
||||||
import ghidra.app.plugin.PluginCategoryNames;
|
import ghidra.app.plugin.PluginCategoryNames;
|
||||||
import ghidra.app.plugin.core.compositeeditor.CompositeEditorProvider;
|
|
||||||
import ghidra.app.services.DataTypeManagerService;
|
import ghidra.app.services.DataTypeManagerService;
|
||||||
import ghidra.framework.model.DomainObject;
|
import ghidra.framework.model.DomainObject;
|
||||||
import ghidra.framework.options.*;
|
import ghidra.framework.options.*;
|
||||||
|
@ -129,10 +128,6 @@ public class StackEditorManagerPlugin extends Plugin
|
||||||
return editorMgr.canCloseDomainObject(dObj);
|
return editorMgr.canCloseDomainObject(dObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompositeEditorProvider getProvider(Program pgm, String functionName) {
|
|
||||||
return editorMgr.getProvider(pgm, functionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
|
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
|
||||||
Object newValue) {
|
Object newValue) {
|
||||||
setOptions(options);
|
setOptions(options);
|
||||||
|
|
|
@ -45,7 +45,7 @@ import ghidra.util.*;
|
||||||
import ghidra.util.exception.*;
|
import ghidra.util.exception.*;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class StackEditorModel extends CompositeEditorModel {
|
public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
public static final int OFFSET = 0;
|
public static final int OFFSET = 0;
|
||||||
|
@ -58,7 +58,6 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
private static final int MAX_PARAM_SIZE = Integer.MAX_VALUE;
|
private static final int MAX_PARAM_SIZE = Integer.MAX_VALUE;
|
||||||
|
|
||||||
private StackFrame originalStack;
|
private StackFrame originalStack;
|
||||||
private DataTypeManager dtm;
|
|
||||||
|
|
||||||
private boolean stackChangedExternally;
|
private boolean stackChangedExternally;
|
||||||
|
|
||||||
|
@ -68,7 +67,6 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
columnWidths = new int[] { 40, 40, 100, 100, 150 };
|
columnWidths = new int[] { 40, 40, 100, 100, 150 };
|
||||||
columnOffsets = new int[headers.length];
|
columnOffsets = new int[headers.length];
|
||||||
adjustOffsets();
|
adjustOffsets();
|
||||||
dtm = provider.getProgram().getDataTypeManager();
|
|
||||||
Plugin plugin = provider.getPlugin();
|
Plugin plugin = provider.getPlugin();
|
||||||
if (plugin instanceof StackEditorOptionManager) {
|
if (plugin instanceof StackEditorOptionManager) {
|
||||||
showHexNumbers = ((StackEditorOptionManager) plugin).showStackNumbersInHex();
|
showHexNumbers = ((StackEditorOptionManager) plugin).showStackNumbersInHex();
|
||||||
|
@ -99,19 +97,20 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
|
|
||||||
void load(Function function) {
|
void load(Function function) {
|
||||||
originalStack = function.getStackFrame();
|
originalStack = function.getStackFrame();
|
||||||
|
ProgramBasedDataTypeManager dtm = function.getProgram().getDataTypeManager();
|
||||||
StackFrameDataType stackFrameDataType = new StackFrameDataType(originalStack, dtm);
|
StackFrameDataType stackFrameDataType = new StackFrameDataType(originalStack, dtm);
|
||||||
stackFrameDataType.setCategoryPath(dtm.getRootCategory().getCategoryPath());
|
stackFrameDataType.setCategoryPath(dtm.getRootCategory().getCategoryPath());
|
||||||
load(stackFrameDataType);
|
load(stackFrameDataType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load(Composite dataType) {
|
public void load(StackFrameDataType dataType) {
|
||||||
stackChangedExternally(false);
|
stackChangedExternally(false);
|
||||||
super.load(dataType);
|
super.load(dataType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void createViewCompositeFromOriginalComposite(Composite original) {
|
protected void createViewCompositeFromOriginalComposite(StackFrameDataType original) {
|
||||||
|
|
||||||
if (viewDTM != null) {
|
if (viewDTM != null) {
|
||||||
viewDTM.close();
|
viewDTM.close();
|
||||||
|
@ -119,10 +118,10 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use temporary standalone view datatype manager which will not manage the viewComposite
|
// Use temporary standalone view datatype manager which will not manage the viewComposite
|
||||||
viewDTM = new CompositeViewerDataTypeManager(originalDTM.getName(), originalDTM);
|
viewDTM = new CompositeViewerDataTypeManager<>(originalDTM.getName(), originalDTM);
|
||||||
|
|
||||||
// NOTE: StackFrameDataType cannot be resolved
|
// NOTE: StackFrameDataType cannot be resolved but all of its element datatypes must be
|
||||||
viewComposite = (Composite) original.copy(viewDTM);
|
viewComposite = original.copy(viewDTM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -130,16 +129,12 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
throw new UnsupportedOperationException("undo/redo not supported");
|
throw new UnsupportedOperationException("undo/redo not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
StackFrameDataType getViewComposite() {
|
|
||||||
return (StackFrameDataType) viewComposite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean updateAndCheckChangeState() {
|
public boolean updateAndCheckChangeState() {
|
||||||
if (originalIsChanging) {
|
if (originalIsChanging) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
StackFrameDataType sfdt = (StackFrameDataType) viewComposite;
|
StackFrameDataType sfdt = viewComposite;
|
||||||
int editReturnAddressOffset = sfdt.getReturnAddressOffset();
|
int editReturnAddressOffset = sfdt.getReturnAddressOffset();
|
||||||
int editLocalSize = sfdt.getLocalSize();
|
int editLocalSize = sfdt.getLocalSize();
|
||||||
int editParamOffset = sfdt.getParameterOffset();
|
int editParamOffset = sfdt.getParameterOffset();
|
||||||
|
@ -215,7 +210,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
return DataTypeInstance.getDataTypeInstance(dt,
|
return DataTypeInstance.getDataTypeInstance(dt,
|
||||||
(dtLen > 0) ? dtLen : element.getLength(), usesAlignedLengthComponents());
|
(dtLen > 0) ? dtLen : element.getLength(), usesAlignedLengthComponents());
|
||||||
case NAME:
|
case NAME:
|
||||||
String fieldName = getFieldNameAtRow(rowIndex, (StackFrameDataType) viewComposite);
|
String fieldName = getFieldNameAtRow(rowIndex, viewComposite);
|
||||||
if (fieldName == null) {
|
if (fieldName == null) {
|
||||||
fieldName = "";
|
fieldName = "";
|
||||||
}
|
}
|
||||||
|
@ -265,7 +260,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
if (modelColumnIndex == OFFSET) {
|
if (modelColumnIndex == OFFSET) {
|
||||||
int svOffset = Integer.decode((String) aValue).intValue();
|
int svOffset = Integer.decode((String) aValue).intValue();
|
||||||
DataTypeComponent dtc =
|
DataTypeComponent dtc =
|
||||||
((StackFrameDataType) viewComposite).getComponentAt(svOffset);
|
(viewComposite).getComponentAt(svOffset);
|
||||||
offsetSelection = new OffsetPairs();
|
offsetSelection = new OffsetPairs();
|
||||||
offsetSelection.addPair(svOffset, dtc.getEndOffset());
|
offsetSelection.addPair(svOffset, dtc.getEndOffset());
|
||||||
}
|
}
|
||||||
|
@ -327,7 +322,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
public void validateComponentOffset(int index, String offset) throws UsrException {
|
public void validateComponentOffset(int index, String offset) throws UsrException {
|
||||||
try {
|
try {
|
||||||
int newOffset = Integer.decode(offset).intValue();
|
int newOffset = Integer.decode(offset).intValue();
|
||||||
StackFrameDataType sfdt = (StackFrameDataType) viewComposite;
|
StackFrameDataType sfdt = viewComposite;
|
||||||
if ((newOffset < sfdt.getMinOffset()) || (newOffset > sfdt.getMaxOffset())) {
|
if ((newOffset < sfdt.getMinOffset()) || (newOffset > sfdt.getMaxOffset())) {
|
||||||
throw new UsrException(offset + " is not an offset in this stack frame.");
|
throw new UsrException(offset + " is not an offset in this stack frame.");
|
||||||
}
|
}
|
||||||
|
@ -391,15 +386,13 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
if (offset == svOffset) {
|
if (offset == svOffset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DataTypeComponent newElement =
|
DataTypeComponent newElement = viewComposite.setOffset(rowIndex, svOffset);
|
||||||
((StackFrameDataType) viewComposite).setOffset(rowIndex, svOffset);
|
|
||||||
setSelection(new int[] { newElement.getOrdinal() });
|
setSelection(new int[] { newElement.getOrdinal() });
|
||||||
notifyCompositeChanged();
|
notifyCompositeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||||
StackFrameDataType stackDt = (StackFrameDataType) viewComposite;
|
|
||||||
if (getNumSelectedRows() > 1) {
|
if (getNumSelectedRows() > 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -412,11 +405,11 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
if (columnIndex < 0 || columnIndex >= getColumnCount()) {
|
if (columnIndex < 0 || columnIndex >= getColumnCount()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
DataTypeComponent dtc = stackDt.getComponent(rowIndex);
|
DataTypeComponent dtc = viewComposite.getComponent(rowIndex);
|
||||||
if (dtc == null) {
|
if (dtc == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
boolean notDefined = (stackDt.getDefinedComponentAtOrdinal(rowIndex) == null);
|
boolean notDefined = (viewComposite.getDefinedComponentAtOrdinal(rowIndex) == null);
|
||||||
return !(notDefined && (columnIndex == OFFSET));
|
return !(notDefined && (columnIndex == OFFSET));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,11 +417,11 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
if (ordinal < 0 || ordinal >= viewComposite.getNumComponents()) {
|
if (ordinal < 0 || ordinal >= viewComposite.getNumComponents()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (((StackFrameDataType) viewComposite).getDefinedComponentAtOrdinal(ordinal) != null);
|
return viewComposite.getDefinedComponentAtOrdinal(ordinal) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean hasVariableAtOffset(int offset) {
|
boolean hasVariableAtOffset(int offset) {
|
||||||
return (((StackFrameDataType) viewComposite).getDefinedComponentAtOffset(offset) != null);
|
return viewComposite.getDefinedComponentAtOffset(offset) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
StackFrame getOriginalStack() {
|
StackFrame getOriginalStack() {
|
||||||
|
@ -436,7 +429,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
StackFrameDataType getEditorStack() {
|
StackFrameDataType getEditorStack() {
|
||||||
return (StackFrameDataType) viewComposite;
|
return viewComposite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -461,8 +454,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
endOffset = getComponent(range.getEnd().getIndex().intValue()).getOffset();
|
endOffset = getComponent(range.getEnd().getIndex().intValue()).getOffset();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
StackFrameDataType stf = (StackFrameDataType) viewComposite;
|
endOffset = viewComposite.getPositiveLength() + viewComposite.getParameterOffset();
|
||||||
endOffset = stf.getPositiveLength() + stf.getParameterOffset();
|
|
||||||
}
|
}
|
||||||
offsets.addPair(startOffset, endOffset);
|
offsets.addPair(startOffset, endOffset);
|
||||||
}
|
}
|
||||||
|
@ -475,8 +467,8 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
private void setRelOffsetSelection(OffsetPairs offsets) {
|
private void setRelOffsetSelection(OffsetPairs offsets) {
|
||||||
FieldSelection newSelection = new FieldSelection();
|
FieldSelection newSelection = new FieldSelection();
|
||||||
int num = offsets.getNumPairs();
|
int num = offsets.getNumPairs();
|
||||||
int min = ((StackFrameDataType) viewComposite).getMinOffset();
|
int min = viewComposite.getMinOffset();
|
||||||
int max = ((StackFrameDataType) viewComposite).getMaxOffset();
|
int max = viewComposite.getMaxOffset();
|
||||||
for (int i = 0; i < num; i++) {
|
for (int i = 0; i < num; i++) {
|
||||||
XYPair pair = offsets.getPair(i);
|
XYPair pair = offsets.getPair(i);
|
||||||
if ((pair.y < min) || (pair.x > max)) {
|
if ((pair.y < min) || (pair.x > max)) {
|
||||||
|
@ -485,8 +477,8 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
int x = (pair.x < min) ? min : pair.x;
|
int x = (pair.x < min) ? min : pair.x;
|
||||||
int y = (pair.y > max) ? max + 1 : pair.y;
|
int y = (pair.y > max) ? max + 1 : pair.y;
|
||||||
|
|
||||||
DataTypeComponent startDtc = ((StackFrameDataType) viewComposite).getComponentAt(x);
|
DataTypeComponent startDtc = viewComposite.getComponentAt(x);
|
||||||
DataTypeComponent endDtc = ((StackFrameDataType) viewComposite).getComponentAt(y - 1);
|
DataTypeComponent endDtc = viewComposite.getComponentAt(y - 1);
|
||||||
if (startDtc == null || endDtc == null) {
|
if (startDtc == null || endDtc == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -499,7 +491,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
endIndex = ((StackFrameDataType) viewComposite).getNumComponents();
|
endIndex = viewComposite.getNumComponents();
|
||||||
}
|
}
|
||||||
newSelection.addRange(startIndex, endIndex);
|
newSelection.addRange(startIndex, endIndex);
|
||||||
}
|
}
|
||||||
|
@ -547,7 +539,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
throw new UsrException(
|
throw new UsrException(
|
||||||
"Local size cannot exceed 0x" + Integer.toHexString(MAX_LOCAL_SIZE) + ".");
|
"Local size cannot exceed 0x" + Integer.toHexString(MAX_LOCAL_SIZE) + ".");
|
||||||
}
|
}
|
||||||
((StackFrameDataType) viewComposite).setLocalSize(size);
|
viewComposite.setLocalSize(size);
|
||||||
notifyCompositeChanged();
|
notifyCompositeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,28 +551,28 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
throw new UsrException(
|
throw new UsrException(
|
||||||
"Parameter size cannot exceed 0x" + Integer.toHexString(MAX_PARAM_SIZE) + ".");
|
"Parameter size cannot exceed 0x" + Integer.toHexString(MAX_PARAM_SIZE) + ".");
|
||||||
}
|
}
|
||||||
((StackFrameDataType) viewComposite).setParameterSize(size);
|
viewComposite.setParameterSize(size);
|
||||||
notifyCompositeChanged();
|
notifyCompositeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
int getFrameSize() {
|
int getFrameSize() {
|
||||||
return ((StackFrameDataType) viewComposite).getFrameSize();
|
return viewComposite.getFrameSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
int getLocalSize() {
|
int getLocalSize() {
|
||||||
return ((StackFrameDataType) viewComposite).getLocalSize();
|
return viewComposite.getLocalSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
int getParameterSize() {
|
int getParameterSize() {
|
||||||
return ((StackFrameDataType) viewComposite).getParameterSize();
|
return viewComposite.getParameterSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
int getParameterOffset() {
|
int getParameterOffset() {
|
||||||
return ((StackFrameDataType) viewComposite).getParameterOffset();
|
return viewComposite.getParameterOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
int getReturnAddressOffset() {
|
int getReturnAddressOffset() {
|
||||||
return ((StackFrameDataType) viewComposite).getReturnAddressOffset();
|
return viewComposite.getReturnAddressOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -591,7 +583,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
@Override
|
@Override
|
||||||
public int getMaxReplaceLength(int currentIndex) {
|
public int getMaxReplaceLength(int currentIndex) {
|
||||||
int offset = viewComposite.getComponent(currentIndex).getOffset();
|
int offset = viewComposite.getComponent(currentIndex).getOffset();
|
||||||
return ((StackFrameDataType) viewComposite).getMaxLength(offset);
|
return viewComposite.getMaxLength(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -653,7 +645,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
// return false;
|
// return false;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
int maxBytes = ((StackFrameDataType) viewComposite).getMaxLength(offset);
|
int maxBytes = viewComposite.getMaxLength(offset);
|
||||||
if (newLength > maxBytes) {
|
if (newLength > maxBytes) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -674,7 +666,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
if (index < 0 || index >= viewComposite.getNumComponents()) {
|
if (index < 0 || index >= viewComposite.getNumComponents()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (((StackFrameDataType) viewComposite).getDefinedComponentAtOrdinal(index) != null);
|
return viewComposite.getDefinedComponentAtOrdinal(index) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -730,7 +722,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int offset = getComponent(currentIndex).getOffset();
|
int offset = getComponent(currentIndex).getOffset();
|
||||||
int maxBytes = ((StackFrameDataType) viewComposite).getMaxLength(offset);
|
int maxBytes = viewComposite.getMaxLength(offset);
|
||||||
if (dataType.getLength() > maxBytes) {
|
if (dataType.getLength() > maxBytes) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -738,8 +730,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void adjustComponents(DataType dataType) {
|
private void adjustComponents(DataType dataType) {
|
||||||
StackFrameDataType stackDt = (StackFrameDataType) viewComposite;
|
DataTypeComponent[] comps = viewComposite.getDefinedComponents();
|
||||||
DataTypeComponent[] comps = stackDt.getDefinedComponents();
|
|
||||||
String msg = "";
|
String msg = "";
|
||||||
for (DataTypeComponent component : comps) {
|
for (DataTypeComponent component : comps) {
|
||||||
DataType compDt = component.getDataType();
|
DataType compDt = component.getDataType();
|
||||||
|
@ -749,7 +740,8 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
len = component.getLength();
|
len = component.getLength();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
stackDt.replace(component.getOrdinal(), compDt, len, component.getFieldName(),
|
viewComposite.replace(component.getOrdinal(), compDt, len,
|
||||||
|
component.getFieldName(),
|
||||||
component.getComment());
|
component.getComment());
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e) {
|
catch (IllegalArgumentException e) {
|
||||||
|
@ -765,8 +757,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void replaceComponents(DataType oldDataType, DataType newDataType) {
|
private void replaceComponents(DataType oldDataType, DataType newDataType) {
|
||||||
StackFrameDataType stackDt = (StackFrameDataType) viewComposite;
|
DataTypeComponent[] comps = viewComposite.getDefinedComponents();
|
||||||
DataTypeComponent[] comps = stackDt.getDefinedComponents();
|
|
||||||
String msg = "";
|
String msg = "";
|
||||||
for (DataTypeComponent component : comps) {
|
for (DataTypeComponent component : comps) {
|
||||||
DataType compDt = component.getDataType();
|
DataType compDt = component.getDataType();
|
||||||
|
@ -776,7 +767,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
len = component.getLength();
|
len = component.getLength();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
stackDt.replace(component.getOrdinal(), newDataType, len,
|
viewComposite.replace(component.getOrdinal(), newDataType, len,
|
||||||
component.getFieldName(), component.getComment());
|
component.getFieldName(), component.getComment());
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e) {
|
catch (IllegalArgumentException e) {
|
||||||
|
@ -795,7 +786,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
public void setComponentDataTypeInstance(int index, DataType dt, int length)
|
public void setComponentDataTypeInstance(int index, DataType dt, int length)
|
||||||
throws UsrException {
|
throws UsrException {
|
||||||
checkIsAllowableDataType(dt);
|
checkIsAllowableDataType(dt);
|
||||||
((StackFrameDataType) viewComposite).setDataType(index, dt, length);
|
viewComposite.setDataType(index, dt, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -815,7 +806,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
|
|
||||||
// prevent user names that are default values, unless the value is the original name
|
// prevent user names that are default values, unless the value is the original name
|
||||||
String nameInEditor = (String) getValueAt(rowIndex, NAME);
|
String nameInEditor = (String) getValueAt(rowIndex, NAME);
|
||||||
StackFrameDataType stackFrameDataType = ((StackFrameDataType) viewComposite);
|
StackFrameDataType stackFrameDataType = viewComposite;
|
||||||
if (stackFrameDataType.isDefaultName(newName) && !isOriginalFieldName(newName, rowIndex)) {
|
if (stackFrameDataType.isDefaultName(newName) && !isOriginalFieldName(newName, rowIndex)) {
|
||||||
if (Objects.equals(nameInEditor, newName)) {
|
if (Objects.equals(nameInEditor, newName)) {
|
||||||
return false; // same as current name in the table; do nothing
|
return false; // same as current name in the table; do nothing
|
||||||
|
@ -841,7 +832,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setComponentComment(int currentIndex, String comment) {
|
public boolean setComponentComment(int currentIndex, String comment) {
|
||||||
if (((StackFrameDataType) viewComposite).setComment(currentIndex, comment)) {
|
if (viewComposite.setComment(currentIndex, comment)) {
|
||||||
updateAndCheckChangeState();
|
updateAndCheckChangeState();
|
||||||
fireTableRowsUpdated(currentIndex, currentIndex);
|
fireTableRowsUpdated(currentIndex, currentIndex);
|
||||||
componentDataChanged();
|
componentDataChanged();
|
||||||
|
@ -973,7 +964,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
for (Variable sv : newVars) {
|
for (Variable sv : newVars) {
|
||||||
Variable newSv = null;
|
Variable newSv = null;
|
||||||
try {
|
try {
|
||||||
DataType dt = dtm.resolve(sv.getDataType(), null);
|
DataType dt = originalDTM.resolve(sv.getDataType(), null);
|
||||||
Variable var = original.getVariableContaining(sv.getStackOffset());
|
Variable var = original.getVariableContaining(sv.getStackOffset());
|
||||||
// TODO: Handle case where new size is smaller but stack alignment will prevent variable shuffle on setDataType - could be problamatic
|
// TODO: Handle case where new size is smaller but stack alignment will prevent variable shuffle on setDataType - could be problamatic
|
||||||
if (var != null && var.getStackOffset() == sv.getStackOffset() &&
|
if (var != null && var.getStackOffset() == sv.getStackOffset() &&
|
||||||
|
@ -1017,7 +1008,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
newSv.setComment(comment);
|
newSv.setComment(comment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
load(new StackFrameDataType(original, viewDTM));
|
load(new StackFrameDataType(original, originalDTM));
|
||||||
clearStatus();
|
clearStatus();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1135,8 +1126,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
setStatus("Can only create arrays on a defined stack variable.", true);
|
setStatus("Can only create arrays on a defined stack variable.", true);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
DataTypeComponent dtc =
|
DataTypeComponent dtc = viewComposite.getDefinedComponentAtOrdinal(index);
|
||||||
((StackFrameDataType) viewComposite).getDefinedComponentAtOrdinal(index);
|
|
||||||
if (dtc == null) {
|
if (dtc == null) {
|
||||||
setStatus("Can only create arrays on a defined stack variable.", true);
|
setStatus("Can only create arrays on a defined stack variable.", true);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1179,12 +1169,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (reload) {
|
if (reload) {
|
||||||
|
load(function);
|
||||||
StackFrame stack = function.getStackFrame();
|
|
||||||
StackFrameDataType newSfdt =
|
|
||||||
new StackFrameDataType(stack, function.getProgram().getDataTypeManager());
|
|
||||||
|
|
||||||
load(newSfdt); // reload the stack model based on current stack frame
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
refresh();
|
refresh();
|
||||||
|
@ -1193,7 +1178,12 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dataTypeChanged(DataTypeManager dataTypeManager, DataTypePath path) {
|
public void dataTypeChanged(DataTypeManager dataTypeManager, DataTypePath path) {
|
||||||
if (isLoaded()) {
|
if (dataTypeManager != originalDTM) {
|
||||||
|
throw new AssertException("Listener only supports original DTM");
|
||||||
|
}
|
||||||
|
if (!isLoaded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
DataType dataType = dataTypeManager.getDataType(path);
|
DataType dataType = dataTypeManager.getDataType(path);
|
||||||
OffsetPairs offsetSelection = getRelOffsetSelection();
|
OffsetPairs offsetSelection = getRelOffsetSelection();
|
||||||
adjustComponents(dataType);
|
adjustComponents(dataType);
|
||||||
|
@ -1201,11 +1191,13 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
componentDataChanged();
|
componentDataChanged();
|
||||||
setRelOffsetSelection(offsetSelection);
|
setRelOffsetSelection(offsetSelection);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dataTypeMoved(DataTypeManager dataTypeManager, DataTypePath oldPath,
|
public void dataTypeMoved(DataTypeManager dataTypeManager, DataTypePath oldPath,
|
||||||
DataTypePath newPath) {
|
DataTypePath newPath) {
|
||||||
|
if (dataTypeManager != originalDTM) {
|
||||||
|
throw new AssertException("Listener only supports original DTM");
|
||||||
|
}
|
||||||
if (!isLoaded()) {
|
if (!isLoaded()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1219,7 +1211,12 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dataTypeRemoved(DataTypeManager dataTypeManager, DataTypePath path) {
|
public void dataTypeRemoved(DataTypeManager dataTypeManager, DataTypePath path) {
|
||||||
if (isLoaded()) {
|
if (dataTypeManager != originalDTM) {
|
||||||
|
throw new AssertException("Listener only supports original DTM");
|
||||||
|
}
|
||||||
|
if (!isLoaded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
OffsetPairs offsetSelection = getRelOffsetSelection();
|
OffsetPairs offsetSelection = getRelOffsetSelection();
|
||||||
DataType dataType = dataTypeManager.getDataType(path);
|
DataType dataType = dataTypeManager.getDataType(path);
|
||||||
replaceComponents(dataType, DataType.DEFAULT);
|
replaceComponents(dataType, DataType.DEFAULT);
|
||||||
|
@ -1227,21 +1224,19 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
componentDataChanged();
|
componentDataChanged();
|
||||||
setRelOffsetSelection(offsetSelection);
|
setRelOffsetSelection(offsetSelection);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dataTypeRenamed(DataTypeManager dataTypeManager, DataTypePath oldPath,
|
public void dataTypeRenamed(DataTypeManager dataTypeManager, DataTypePath oldPath,
|
||||||
DataTypePath newPath) {
|
DataTypePath newPath) {
|
||||||
if (isLoaded()) {
|
if (dataTypeManager != originalDTM) {
|
||||||
DataTypeManager originalDataTypeManager = getOriginalDataTypeManager();
|
throw new AssertException("Listener only supports original DTM");
|
||||||
if (dataTypeManager != originalDataTypeManager) {
|
}
|
||||||
|
if (!isLoaded()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataTypePath originalPath = getOriginalDataTypePath();
|
DataTypePath originalPath = getOriginalDataTypePath();
|
||||||
if (originalDataTypeManager == null || originalPath == null) {
|
if (originalPath == null || !oldPath.equals(originalPath)) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!oldPath.equals(originalPath)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1252,12 +1247,16 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
componentDataChanged();
|
componentDataChanged();
|
||||||
setRelOffsetSelection(offsetSelection);
|
setRelOffsetSelection(offsetSelection);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dataTypeReplaced(DataTypeManager dataTypeManager, DataTypePath oldPath,
|
public void dataTypeReplaced(DataTypeManager dataTypeManager, DataTypePath oldPath,
|
||||||
DataTypePath newPath, DataType newDataType) {
|
DataTypePath newPath, DataType newDataType) {
|
||||||
if (isLoaded()) {
|
if (dataTypeManager != originalDTM) {
|
||||||
|
throw new AssertException("Listener only supports original DTM");
|
||||||
|
}
|
||||||
|
if (!isLoaded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
DataType oldDataType = viewDTM.getDataType(oldPath);
|
DataType oldDataType = viewDTM.getDataType(oldPath);
|
||||||
OffsetPairs offsetSelection = getRelOffsetSelection();
|
OffsetPairs offsetSelection = getRelOffsetSelection();
|
||||||
replaceComponents(oldDataType, newDataType);
|
replaceComponents(oldDataType, newDataType);
|
||||||
|
@ -1265,15 +1264,10 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
componentDataChanged();
|
componentDataChanged();
|
||||||
setRelOffsetSelection(offsetSelection);
|
setRelOffsetSelection(offsetSelection);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the stack frame model datatype being edited
|
|
||||||
* @return stack frame model datatype
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
protected StackFrameDataType getOriginalComposite() {
|
protected StackFrameDataType getOriginalComposite() {
|
||||||
return (StackFrameDataType) originalComposite;
|
return originalComposite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1305,8 +1299,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshComponents() {
|
private void refreshComponents() {
|
||||||
StackFrameDataType stackDt = (StackFrameDataType) viewComposite;
|
DataTypeComponent[] comps = viewComposite.getDefinedComponents();
|
||||||
DataTypeComponent[] comps = stackDt.getDefinedComponents();
|
|
||||||
for (int i = comps.length - 1; i >= 0; i--) {
|
for (int i = comps.length - 1; i >= 0; i--) {
|
||||||
DataTypeComponent component = comps[i];
|
DataTypeComponent component = comps[i];
|
||||||
DataType compDt = component.getDataType();
|
DataType compDt = component.getDataType();
|
||||||
|
@ -1326,7 +1319,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||||
@Override
|
@Override
|
||||||
protected void clearComponents(int[] rows) {
|
protected void clearComponents(int[] rows) {
|
||||||
for (int i = rows.length - 1; i >= 0; i--) {
|
for (int i = rows.length - 1; i >= 0; i--) {
|
||||||
((StackFrameDataType) viewComposite).clearComponent(rows[i]);
|
viewComposite.clearComponent(rows[i]);
|
||||||
}
|
}
|
||||||
notifyCompositeChanged();
|
notifyCompositeChanged();
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ import ghidra.util.exception.UsrException;
|
||||||
/**
|
/**
|
||||||
* Panel for editing a function stack.
|
* Panel for editing a function stack.
|
||||||
*/
|
*/
|
||||||
public class StackEditorPanel extends CompositeEditorPanel {
|
public class StackEditorPanel extends CompositeEditorPanel<StackFrameDataType, StackEditorModel> {
|
||||||
|
|
||||||
private JTextField frameSizeField;
|
private JTextField frameSizeField;
|
||||||
private JTextField localSizeField;
|
private JTextField localSizeField;
|
||||||
|
@ -42,7 +42,7 @@ public class StackEditorPanel extends CompositeEditorPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private StackEditorModel getStackModel() {
|
private StackEditorModel getStackModel() {
|
||||||
return (StackEditorModel) model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -37,7 +37,9 @@ import ghidra.util.Msg;
|
||||||
/**
|
/**
|
||||||
* Editor for a Function Stack.
|
* Editor for a Function Stack.
|
||||||
*/
|
*/
|
||||||
public class StackEditorProvider extends CompositeEditorProvider implements DomainObjectListener {
|
public class StackEditorProvider
|
||||||
|
extends CompositeEditorProvider<StackFrameDataType, StackEditorModel>
|
||||||
|
implements DomainObjectListener {
|
||||||
|
|
||||||
private Program program;
|
private Program program;
|
||||||
private Function function;
|
private Function function;
|
||||||
|
@ -136,7 +138,7 @@ public class StackEditorProvider extends CompositeEditorProvider implements Doma
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected CompositeEditorModel getModel() {
|
protected StackEditorModel getModel() {
|
||||||
return stackModel;
|
return stackModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +149,7 @@ public class StackEditorProvider extends CompositeEditorProvider implements Doma
|
||||||
|
|
||||||
private void refreshName() {
|
private void refreshName() {
|
||||||
StackFrameDataType origDt = stackModel.getOriginalComposite();
|
StackFrameDataType origDt = stackModel.getOriginalComposite();
|
||||||
StackFrameDataType viewDt = stackModel.getViewComposite();
|
StackFrameDataType viewDt = stackModel.getEditorStack();
|
||||||
String oldName = origDt.getName();
|
String oldName = origDt.getName();
|
||||||
String newName = function.getName();
|
String newName = function.getName();
|
||||||
if (oldName.equals(newName)) {
|
if (oldName.equals(newName)) {
|
||||||
|
|
|
@ -34,7 +34,6 @@ import ghidra.util.exception.InvalidInputException;
|
||||||
*/
|
*/
|
||||||
public class StackFrameDataType extends BiDirectionDataType {
|
public class StackFrameDataType extends BiDirectionDataType {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
static String DUMMY_FUNCTION_NAME = "StackWithoutFunction";
|
static String DUMMY_FUNCTION_NAME = "StackWithoutFunction";
|
||||||
private static final String UNKNOWN_PREFIX = "unknown_";
|
private static final String UNKNOWN_PREFIX = "unknown_";
|
||||||
StackFrame stack;
|
StackFrame stack;
|
||||||
|
@ -44,8 +43,10 @@ public class StackFrameDataType extends BiDirectionDataType {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for an editable stack frame for use with the editor.
|
* Constructor for an editable stack frame for use with the editor.
|
||||||
|
* The specified stack will be copied into this new instance.
|
||||||
*
|
*
|
||||||
* @param stack the function stack frame to be edited.
|
* @param stack the function stack frame to be replicated.
|
||||||
|
* @param dtm datatype manager (required)
|
||||||
*/
|
*/
|
||||||
public StackFrameDataType(StackFrame stack, DataTypeManager dtm) {
|
public StackFrameDataType(StackFrame stack, DataTypeManager dtm) {
|
||||||
super(
|
super(
|
||||||
|
@ -57,12 +58,14 @@ public class StackFrameDataType extends BiDirectionDataType {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for an editable stack frame for use with the editor.
|
* Constructor for an editable stack frame for use with the editor.
|
||||||
|
* The specified stackDt will be copied into this new instance.
|
||||||
*
|
*
|
||||||
* @param stack the function stack frame to be edited.
|
* @param stackDt the function stack frame to be replicated.
|
||||||
|
* @param dtm datatype manager (required)
|
||||||
*/
|
*/
|
||||||
public StackFrameDataType(StackFrameDataType stackDt, DataTypeManager dtm) {
|
public StackFrameDataType(StackFrameDataType stackDt, DataTypeManager dtm) {
|
||||||
super(stackDt.getCategoryPath(), stackDt.getName(), stackDt.getNegativeLength(),
|
super(stackDt.getName(), stackDt.getNegativeLength(), stackDt.getPositiveLength(),
|
||||||
stackDt.getPositiveLength(), stackDt.splitOffset, dtm);
|
stackDt.splitOffset, dtm);
|
||||||
setDescription(stackDt.getDescription());
|
setDescription(stackDt.getDescription());
|
||||||
this.function = stackDt.function;
|
this.function = stackDt.function;
|
||||||
this.growsNegative = stackDt.growsNegative;
|
this.growsNegative = stackDt.growsNegative;
|
||||||
|
@ -156,7 +159,7 @@ public class StackFrameDataType extends BiDirectionDataType {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataType copy(DataTypeManager dtm) {
|
public StackFrameDataType copy(DataTypeManager dtm) {
|
||||||
return new StackFrameDataType(this, dtm);
|
return new StackFrameDataType(this, dtm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,18 +105,22 @@ public class StackPieceDataType extends DataTypeImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dataTypeSizeChanged(DataType dt) {
|
public void dataTypeSizeChanged(DataType dt) {
|
||||||
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dataTypeDeleted(DataType dt) {
|
public void dataTypeDeleted(DataType dt) {
|
||||||
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
|
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
|
||||||
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dataTypeNameChanged(DataType dt, String oldName) {
|
public void dataTypeNameChanged(DataType dt, String oldName) {
|
||||||
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -55,8 +55,8 @@ import utilities.util.reflection.ReflectionUtilities;
|
||||||
public abstract class AbstractEditorTest extends AbstractGhidraHeadedIntegrationTest {
|
public abstract class AbstractEditorTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
protected String languageName;
|
protected String languageName;
|
||||||
protected String compilerSpecID;
|
protected String compilerSpecID;
|
||||||
protected CompositeEditorProvider provider;
|
protected CompositeEditorProvider<?, ?> provider;
|
||||||
protected CompositeEditorModel model;
|
protected CompositeEditorModel<?> model;
|
||||||
protected TestEnv env;
|
protected TestEnv env;
|
||||||
protected ProgramBuilder builder;
|
protected ProgramBuilder builder;
|
||||||
protected Program program;
|
protected Program program;
|
||||||
|
@ -129,7 +129,7 @@ public abstract class AbstractEditorTest extends AbstractGhidraHeadedIntegration
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void installProvider(CompositeEditorProvider newProvider) {
|
protected void installProvider(CompositeEditorProvider<?, ?> newProvider) {
|
||||||
assertNotNull(newProvider);
|
assertNotNull(newProvider);
|
||||||
this.provider = newProvider;
|
this.provider = newProvider;
|
||||||
runSwing(() -> removeTableCellEditorsFocusLostListener());
|
runSwing(() -> removeTableCellEditorsFocusLostListener());
|
||||||
|
@ -393,12 +393,12 @@ public abstract class AbstractEditorTest extends AbstractGhidraHeadedIntegration
|
||||||
return (dtc != null) ? dtc.getComment() : null;
|
return (dtc != null) ? dtc.getComment() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CompositeEditorPanel getPanel() {
|
protected CompositeEditorPanel<?, ?> getPanel() {
|
||||||
return (CompositeEditorPanel) provider.getComponent();
|
return provider.getComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JTable getTable() {
|
protected JTable getTable() {
|
||||||
return ((CompositeEditorPanel) provider.getComponent()).table;
|
return provider.getComponent().table;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Window getWindow() {
|
protected Window getWindow() {
|
||||||
|
@ -789,37 +789,72 @@ public abstract class AbstractEditorTest extends AbstractGhidraHeadedIntegration
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertIsPackingEnabled(boolean aligned) {
|
protected void assertIsPackingEnabled(boolean aligned) {
|
||||||
assertEquals(aligned, ((CompEditorModel) model).isPackingEnabled());
|
if (model instanceof CompEditorModel compModel) {
|
||||||
|
assertEquals(aligned, compModel.isPackingEnabled());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fail("Model does not support packing concept");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertDefaultPacked() {
|
protected void assertDefaultPacked() {
|
||||||
assertEquals(PackingType.DEFAULT, ((CompEditorModel) model).getPackingType());
|
if (model instanceof CompEditorModel compModel) {
|
||||||
|
assertEquals(PackingType.DEFAULT, compModel.getPackingType());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fail("Model does not support packing concept");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertPacked(int pack) {
|
protected void assertPacked(int pack) {
|
||||||
assertEquals(PackingType.EXPLICIT, ((CompEditorModel) model).getPackingType());
|
if (model instanceof CompEditorModel compModel) {
|
||||||
assertEquals(pack, ((CompEditorModel) model).getExplicitPackingValue());
|
assertEquals(PackingType.EXPLICIT, compModel.getPackingType());
|
||||||
|
assertEquals(pack, compModel.getExplicitPackingValue());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fail("Model does not support packing concept");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertIsDefaultAligned() {
|
protected void assertIsDefaultAligned() {
|
||||||
assertEquals(AlignmentType.DEFAULT, ((CompEditorModel) model).getAlignmentType());
|
if (model instanceof CompEditorModel compModel) {
|
||||||
|
assertEquals(AlignmentType.DEFAULT, compModel.getAlignmentType());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fail("Model does not support alignment concept");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertIsMachineAligned() {
|
protected void assertIsMachineAligned() {
|
||||||
assertEquals(AlignmentType.MACHINE, ((CompEditorModel) model).getAlignmentType());
|
if (model instanceof CompEditorModel compModel) {
|
||||||
|
assertEquals(AlignmentType.MACHINE, compModel.getAlignmentType());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fail("Model does not support alignment concept");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertExplicitAlignment(int alignment) {
|
protected void assertExplicitAlignment(int alignment) {
|
||||||
assertEquals(AlignmentType.EXPLICIT, ((CompEditorModel) model).getAlignmentType());
|
if (model instanceof CompEditorModel compModel) {
|
||||||
assertEquals(alignment, ((CompEditorModel) model).getExplicitMinimumAlignment());
|
assertEquals(AlignmentType.EXPLICIT, compModel.getAlignmentType());
|
||||||
|
assertEquals(alignment, compModel.getExplicitMinimumAlignment());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fail("Model does not support alignment concept");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertActualAlignment(int value) {
|
protected void assertActualAlignment(int value) {
|
||||||
assertEquals(value, ((CompEditorModel) model).getActualAlignment());
|
if (model instanceof CompEditorModel compModel) {
|
||||||
|
assertEquals(value, compModel.getActualAlignment());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fail("Model does not support alignment concept");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertLength(int value) {
|
protected void assertLength(int value) {
|
||||||
assertEquals(value, ((CompEditorModel) model).getLength());
|
assertEquals(value, model.getLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setOptions(String optionName, boolean b) {
|
protected void setOptions(String optionName, boolean b) {
|
||||||
|
|
|
@ -195,7 +195,7 @@ public class StructureEditorAlignmentTest extends AbstractStructureEditorTest {
|
||||||
public void testByValueAlignedStructure() throws Exception {
|
public void testByValueAlignedStructure() throws Exception {
|
||||||
init(emptyStructure, pgmRootCat, false);
|
init(emptyStructure, pgmRootCat, false);
|
||||||
|
|
||||||
CompEditorPanel editorPanel = (CompEditorPanel) getPanel();
|
StructureEditorPanel editorPanel = (StructureEditorPanel) getPanel();
|
||||||
|
|
||||||
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
||||||
addDataType(new ByteDataType());
|
addDataType(new ByteDataType());
|
||||||
|
@ -268,7 +268,7 @@ public class StructureEditorAlignmentTest extends AbstractStructureEditorTest {
|
||||||
emptyStructure.add(arrayDt);
|
emptyStructure.add(arrayDt);
|
||||||
|
|
||||||
init(emptyStructure, pgmRootCat, false);
|
init(emptyStructure, pgmRootCat, false);
|
||||||
CompEditorPanel editorPanel = (CompEditorPanel) getPanel();
|
StructureEditorPanel editorPanel = (StructureEditorPanel) getPanel();
|
||||||
|
|
||||||
JRadioButton explicitAlignButton =
|
JRadioButton explicitAlignButton =
|
||||||
(JRadioButton) getInstanceField("explicitAlignButton", editorPanel);
|
(JRadioButton) getInstanceField("explicitAlignButton", editorPanel);
|
||||||
|
@ -301,7 +301,7 @@ public class StructureEditorAlignmentTest extends AbstractStructureEditorTest {
|
||||||
emptyStructure.pack(pack);
|
emptyStructure.pack(pack);
|
||||||
|
|
||||||
init(emptyStructure, pgmRootCat, false);
|
init(emptyStructure, pgmRootCat, false);
|
||||||
CompEditorPanel editorPanel = (CompEditorPanel) getPanel();
|
StructureEditorPanel editorPanel = (StructureEditorPanel) getPanel();
|
||||||
|
|
||||||
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
||||||
addDataType(new ByteDataType());
|
addDataType(new ByteDataType());
|
||||||
|
@ -433,7 +433,7 @@ public class StructureEditorAlignmentTest extends AbstractStructureEditorTest {
|
||||||
|
|
||||||
init(emptyStructure, pgmRootCat, false);
|
init(emptyStructure, pgmRootCat, false);
|
||||||
|
|
||||||
CompEditorPanel editorPanel = (CompEditorPanel) getPanel();
|
StructureEditorPanel editorPanel = (StructureEditorPanel) getPanel();
|
||||||
|
|
||||||
JRadioButton byValueButton =
|
JRadioButton byValueButton =
|
||||||
(JRadioButton) findComponentByName(getPanel(), "Explicit Alignment");
|
(JRadioButton) findComponentByName(getPanel(), "Explicit Alignment");
|
||||||
|
|
|
@ -71,8 +71,8 @@ public class StructureEditorArchiveTest extends AbstractStructureEditorTest {
|
||||||
createStruct = getAction(plugin, "Structure");
|
createStruct = getAction(plugin, "Structure");
|
||||||
performAction(createStruct, plugin.getProvider(), true);
|
performAction(createStruct, plugin.getProvider(), true);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
CompEditorPanel editorPanel =
|
StructureEditorPanel editorPanel =
|
||||||
findComponent(tool.getToolFrame(), CompEditorPanel.class, true);
|
findComponent(tool.getToolFrame(), StructureEditorPanel.class, true);
|
||||||
model = editorPanel.model;
|
model = editorPanel.model;
|
||||||
installProvider(model.getProvider());
|
installProvider(model.getProvider());
|
||||||
archiveDTM = model.getOriginalDataTypeManager();
|
archiveDTM = model.getOriginalDataTypeManager();
|
||||||
|
@ -82,7 +82,7 @@ public class StructureEditorArchiveTest extends AbstractStructureEditorTest {
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
// Answer "No" to "Save Structure Editor Changes?".
|
// Answer "No" to "Save Structure Editor Changes?".
|
||||||
JDialog dialog = waitForJDialog(null, "Save Structure Editor Changes?", 2000);
|
JDialog dialog = waitForJDialog("Save Structure Editor Changes?");
|
||||||
assertNotNull(dialog);
|
assertNotNull(dialog);
|
||||||
pressButtonByText(dialog.getContentPane(), "No");
|
pressButtonByText(dialog.getContentPane(), "No");
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
@ -112,8 +112,7 @@ public class StructureEditorArchiveTest extends AbstractStructureEditorTest {
|
||||||
|
|
||||||
DataTypeTestUtils.performAction(action, dtTree, false);
|
DataTypeTestUtils.performAction(action, dtTree, false);
|
||||||
|
|
||||||
GhidraFileChooser chooser =
|
GhidraFileChooser chooser = waitForDialogComponent(GhidraFileChooser.class);
|
||||||
waitForDialogComponent(tool.getToolFrame(), GhidraFileChooser.class, 10000);
|
|
||||||
assertNotNull("Never found chooser!", chooser);
|
assertNotNull("Never found chooser!", chooser);
|
||||||
selectFileInChooser(chooser, archiveFile);
|
selectFileInChooser(chooser, archiveFile);
|
||||||
|
|
||||||
|
@ -162,8 +161,8 @@ public class StructureEditorArchiveTest extends AbstractStructureEditorTest {
|
||||||
createStruct = getAction(plugin, "Structure");
|
createStruct = getAction(plugin, "Structure");
|
||||||
performAction(createStruct, plugin.getProvider(), true);
|
performAction(createStruct, plugin.getProvider(), true);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
CompEditorPanel editorPanel =
|
StructureEditorPanel editorPanel =
|
||||||
findComponent(tool.getToolFrame(), CompEditorPanel.class, true);
|
findComponent(tool.getToolFrame(), StructureEditorPanel.class, true);
|
||||||
|
|
||||||
model = editorPanel.model;
|
model = editorPanel.model;
|
||||||
installProvider(model.getProvider());
|
installProvider(model.getProvider());
|
||||||
|
@ -199,7 +198,7 @@ public class StructureEditorArchiveTest extends AbstractStructureEditorTest {
|
||||||
selectNode(child);
|
selectNode(child);
|
||||||
|
|
||||||
performAction(closeArchive, plugin.getProvider(), false);
|
performAction(closeArchive, plugin.getProvider(), false);
|
||||||
OptionDialog dialog = waitForDialogComponent(tool.getToolFrame(), OptionDialog.class, 2000);
|
OptionDialog dialog = waitForDialogComponent(OptionDialog.class);
|
||||||
JButton button = findButtonByText(dialog, "No");
|
JButton button = findButtonByText(dialog, "No");
|
||||||
pressButton(button);
|
pressButton(button);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,7 @@ import javax.swing.*;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import docking.widgets.OptionDialog;
|
|
||||||
import ghidra.program.database.DatabaseObject;
|
import ghidra.program.database.DatabaseObject;
|
||||||
import ghidra.program.database.data.StructureDBTest;
|
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
|
||||||
public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTest {
|
public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTest {
|
||||||
|
@ -57,7 +55,7 @@ public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTes
|
||||||
|
|
||||||
addDataType(ByteDataType.dataType);
|
addDataType(ByteDataType.dataType);
|
||||||
addDataType(FloatDataType.dataType);
|
addDataType(FloatDataType.dataType);
|
||||||
addFlexDataType((Structure) structureModel.viewComposite, DWordDataType.dataType, null,
|
addFlexDataType(structureModel.viewComposite, DWordDataType.dataType, null,
|
||||||
null);
|
null);
|
||||||
|
|
||||||
assertEquals(3, structureModel.getNumComponents());
|
assertEquals(3, structureModel.getNumComponents());
|
||||||
|
@ -76,7 +74,7 @@ public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTes
|
||||||
|
|
||||||
addDataType(ByteDataType.dataType);
|
addDataType(ByteDataType.dataType);
|
||||||
addDataType(CharDataType.dataType);
|
addDataType(CharDataType.dataType);
|
||||||
addFlexDataType((Structure) structureModel.viewComposite, DWordDataType.dataType, null,
|
addFlexDataType(structureModel.viewComposite, DWordDataType.dataType, null,
|
||||||
null);
|
null);
|
||||||
|
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
@ -110,7 +108,7 @@ public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTes
|
||||||
|
|
||||||
addDataType(ByteDataType.dataType);
|
addDataType(ByteDataType.dataType);
|
||||||
addDataType(CharDataType.dataType);
|
addDataType(CharDataType.dataType);
|
||||||
addFlexDataType((Structure) structureModel.viewComposite, DWordDataType.dataType, null,
|
addFlexDataType(structureModel.viewComposite, DWordDataType.dataType, null,
|
||||||
null);
|
null);
|
||||||
|
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
@ -138,11 +136,11 @@ public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTes
|
||||||
public void testByValueAlignedStructure() throws Exception {
|
public void testByValueAlignedStructure() throws Exception {
|
||||||
init(emptyStructure, pgmRootCat, false);
|
init(emptyStructure, pgmRootCat, false);
|
||||||
|
|
||||||
CompEditorPanel editorPanel = (CompEditorPanel) getPanel();
|
StructureEditorPanel editorPanel = (StructureEditorPanel) getPanel();
|
||||||
|
|
||||||
addDataType(ByteDataType.dataType);
|
addDataType(ByteDataType.dataType);
|
||||||
addDataType(CharDataType.dataType);
|
addDataType(CharDataType.dataType);
|
||||||
addFlexDataType((Structure) structureModel.viewComposite, DWordDataType.dataType, null,
|
addFlexDataType(structureModel.viewComposite, DWordDataType.dataType, null,
|
||||||
null);
|
null);
|
||||||
|
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
@ -209,7 +207,7 @@ public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTes
|
||||||
addFlexDataType(emptyStructure, DWordDataType.dataType, null, null);
|
addFlexDataType(emptyStructure, DWordDataType.dataType, null, null);
|
||||||
|
|
||||||
init(emptyStructure, pgmRootCat, false);
|
init(emptyStructure, pgmRootCat, false);
|
||||||
CompEditorPanel editorPanel = (CompEditorPanel) getPanel();
|
StructureEditorPanel editorPanel = (StructureEditorPanel) getPanel();
|
||||||
|
|
||||||
JRadioButton explicitAlignButton =
|
JRadioButton explicitAlignButton =
|
||||||
(JRadioButton) getInstanceField("explicitAlignButton", editorPanel);
|
(JRadioButton) getInstanceField("explicitAlignButton", editorPanel);
|
||||||
|
@ -243,11 +241,11 @@ public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTes
|
||||||
emptyStructure.setExplicitPackingValue(value);
|
emptyStructure.setExplicitPackingValue(value);
|
||||||
|
|
||||||
init(emptyStructure, pgmRootCat, false);
|
init(emptyStructure, pgmRootCat, false);
|
||||||
CompEditorPanel editorPanel = (CompEditorPanel) getPanel();
|
StructureEditorPanel editorPanel = (StructureEditorPanel) getPanel();
|
||||||
|
|
||||||
addDataType(ByteDataType.dataType);
|
addDataType(ByteDataType.dataType);
|
||||||
addDataType(CharDataType.dataType);
|
addDataType(CharDataType.dataType);
|
||||||
addFlexDataType((Structure) structureModel.viewComposite, DWordDataType.dataType, null,
|
addFlexDataType(structureModel.viewComposite, DWordDataType.dataType, null,
|
||||||
null);
|
null);
|
||||||
|
|
||||||
JRadioButton byValuePackingButton =
|
JRadioButton byValuePackingButton =
|
||||||
|
|
|
@ -353,7 +353,7 @@ public class StructureEditorLockedActions3Test extends AbstractStructureEditorTe
|
||||||
@Test
|
@Test
|
||||||
public void testShowNumbersInHex() {
|
public void testShowNumbersInHex() {
|
||||||
init(complexStructure, pgmTestCat);
|
init(complexStructure, pgmTestCat);
|
||||||
CompEditorPanel panel = (CompEditorPanel) provider.getComponent();
|
StructureEditorPanel panel = (StructureEditorPanel) provider.getComponent();
|
||||||
|
|
||||||
assertEquals("", model.getStatus());
|
assertEquals("", model.getStatus());
|
||||||
|
|
||||||
|
|
|
@ -159,8 +159,7 @@ public class StructureEditorLockedDnDTest extends AbstractStructureEditorTest {
|
||||||
assertNotNull(dt4);
|
assertNotNull(dt4);
|
||||||
insertAtPoint(dt4, 0, 0);
|
insertAtPoint(dt4, 0, 0);
|
||||||
|
|
||||||
JDialog dialog =
|
JDialog dialog = waitForJDialog("Enter Number");
|
||||||
waitForJDialog(env.getTool().getToolFrame(), "Enter Number", DEFAULT_WINDOW_TIMEOUT);
|
|
||||||
assertNotNull(dialog);
|
assertNotNull(dialog);
|
||||||
JTextField textField = findComponent(dialog, JTextField.class);
|
JTextField textField = findComponent(dialog, JTextField.class);
|
||||||
triggerText(textField, "3");
|
triggerText(textField, "3");
|
||||||
|
|
|
@ -100,7 +100,7 @@ public class StructureEditorUnlockedActions5Test extends AbstractStructureEditor
|
||||||
|
|
||||||
assertTrue(model.isValidName());
|
assertTrue(model.isValidName());
|
||||||
|
|
||||||
CompEditorPanel panel = (CompEditorPanel) getPanel();
|
StructureEditorPanel panel = (StructureEditorPanel) getPanel();
|
||||||
assertFalse(panel.hasInvalidEntry());
|
assertFalse(panel.hasInvalidEntry());
|
||||||
assertFalse(panel.hasUncomittedEntry());
|
assertFalse(panel.hasUncomittedEntry());
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ public class StructureEditorUnlockedActions5Test extends AbstractStructureEditor
|
||||||
|
|
||||||
assertTrue(model.isValidName());
|
assertTrue(model.isValidName());
|
||||||
|
|
||||||
CompEditorPanel panel = (CompEditorPanel) getPanel();
|
StructureEditorPanel panel = (StructureEditorPanel) getPanel();
|
||||||
assertFalse(panel.hasInvalidEntry());
|
assertFalse(panel.hasInvalidEntry());
|
||||||
assertFalse(panel.hasUncomittedEntry());
|
assertFalse(panel.hasUncomittedEntry());
|
||||||
|
|
||||||
|
@ -657,7 +657,7 @@ public class StructureEditorUnlockedActions5Test extends AbstractStructureEditor
|
||||||
public void testUndoRename() throws Exception {
|
public void testUndoRename() throws Exception {
|
||||||
init(complexStructure, pgmTestCat);
|
init(complexStructure, pgmTestCat);
|
||||||
|
|
||||||
CompEditorPanel panel = (CompEditorPanel) getPanel();
|
StructureEditorPanel panel = (StructureEditorPanel) getPanel();
|
||||||
JTextField nameField = panel.nameTextField;
|
JTextField nameField = panel.nameTextField;
|
||||||
|
|
||||||
setText(nameField, "myStruct");
|
setText(nameField, "myStruct");
|
||||||
|
|
|
@ -74,7 +74,7 @@ public class StructureEditorUnlockedDnD2Test extends AbstractStructureEditorTest
|
||||||
|
|
||||||
assertNotNull(dt4);
|
assertNotNull(dt4);
|
||||||
addAtPoint(dt4, 3, 0);
|
addAtPoint(dt4, 3, 0);
|
||||||
dialog = env.waitForDialogComponent(NumberInputDialog.class, 1000);
|
dialog = waitForDialogComponent(NumberInputDialog.class);
|
||||||
assertNotNull(dialog);
|
assertNotNull(dialog);
|
||||||
okInput(dialog, 25);
|
okInput(dialog, 25);
|
||||||
dialog = null;
|
dialog = null;
|
||||||
|
|
|
@ -70,7 +70,7 @@ public class StructureEditorUnlockedDnD3Test extends AbstractStructureEditorTest
|
||||||
|
|
||||||
assertNotNull(dt4);
|
assertNotNull(dt4);
|
||||||
insertAtPoint(dt4, 0, 0);
|
insertAtPoint(dt4, 0, 0);
|
||||||
dialog = env.waitForDialogComponent(NumberInputDialog.class, 1000);
|
dialog = waitForDialogComponent(NumberInputDialog.class);
|
||||||
assertNotNull(dialog);
|
assertNotNull(dialog);
|
||||||
okInput(dialog, 25);
|
okInput(dialog, 25);
|
||||||
dialog = null;
|
dialog = null;
|
||||||
|
|
|
@ -254,7 +254,7 @@ public class StructureEditorUnlockedEnablementTest extends AbstractStructureEdit
|
||||||
init(complexStructure, pgmBbCat);
|
init(complexStructure, pgmBbCat);
|
||||||
|
|
||||||
structureModel.viewDTM.withTransaction("Add Bitfield",
|
structureModel.viewDTM.withTransaction("Add Bitfield",
|
||||||
() -> ((Structure) structureModel.viewComposite).insertBitField(2, 1, 4,
|
() -> structureModel.viewComposite.insertBitField(2, 1, 4,
|
||||||
CharDataType.dataType, 2, "bf1", null));
|
CharDataType.dataType, 2, "bf1", null));
|
||||||
|
|
||||||
setSelection(new int[] { 2 });
|
setSelection(new int[] { 2 });
|
||||||
|
@ -296,7 +296,7 @@ public class StructureEditorUnlockedEnablementTest extends AbstractStructureEdit
|
||||||
init(complexStructure, pgmBbCat);
|
init(complexStructure, pgmBbCat);
|
||||||
|
|
||||||
structureModel.viewDTM.withTransaction("Add Bitfield",
|
structureModel.viewDTM.withTransaction("Add Bitfield",
|
||||||
() -> ((Structure) structureModel.viewComposite).insertBitField(2, 1, 4,
|
() -> structureModel.viewComposite.insertBitField(2, 1, 4,
|
||||||
CharDataType.dataType, 2, "bf1", null));
|
CharDataType.dataType, 2, "bf1", null));
|
||||||
|
|
||||||
setSelection(new int[] { 2 });
|
setSelection(new int[] { 2 });
|
||||||
|
|
|
@ -810,7 +810,7 @@ public class UnionEditorActions1Test extends AbstractUnionEditorTest {
|
||||||
public void testApplyWithInvalidName() throws Exception {
|
public void testApplyWithInvalidName() throws Exception {
|
||||||
init(complexUnion, pgmTestCat, false);
|
init(complexUnion, pgmTestCat, false);
|
||||||
|
|
||||||
CompEditorPanel panel = (CompEditorPanel) getPanel();
|
UnionEditorPanel panel = (UnionEditorPanel) getPanel();
|
||||||
JTextField nameField = panel.nameTextField;
|
JTextField nameField = panel.nameTextField;
|
||||||
assertTrue(model.isValidName());
|
assertTrue(model.isValidName());
|
||||||
|
|
||||||
|
@ -875,7 +875,7 @@ public class UnionEditorActions1Test extends AbstractUnionEditorTest {
|
||||||
public void testShowNumbersInHex() {
|
public void testShowNumbersInHex() {
|
||||||
init(complexUnion, pgmTestCat, false);
|
init(complexUnion, pgmTestCat, false);
|
||||||
assertEquals("", model.getStatus());
|
assertEquals("", model.getStatus());
|
||||||
CompEditorPanel panel = (CompEditorPanel) provider.getComponent();
|
UnionEditorPanel panel = (UnionEditorPanel) provider.getComponent();
|
||||||
|
|
||||||
assertEquals(false, model.isShowingNumbersInHex());
|
assertEquals(false, model.isShowingNumbersInHex());
|
||||||
assertEquals("45", model.getValueAt(11, model.getLengthColumn()));
|
assertEquals("45", model.getValueAt(11, model.getLengthColumn()));
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.stackeditor;
|
package ghidra.app.plugin.core.stackeditor;
|
||||||
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ public abstract class AbstractStackEditorProviderTest extends AbstractStackEdito
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void chooseOverwrite() throws Exception {
|
protected void chooseOverwrite() throws Exception {
|
||||||
Window dialog = waitForWindow("Overwrite Program Changes?", DEFAULT_WINDOW_TIMEOUT);
|
Window dialog = waitForWindow("Overwrite Program Changes?");
|
||||||
assertNotNull("Did not get expected overwrite dialog prompt", dialog);
|
assertNotNull("Did not get expected overwrite dialog prompt", dialog);
|
||||||
pressButtonByText(dialog, "Overwrite");
|
pressButtonByText(dialog, "Overwrite");
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ public abstract class AbstractStackEditorProviderTest extends AbstractStackEdito
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void chooseCancel() throws Exception {
|
protected void chooseCancel() throws Exception {
|
||||||
Window dialog = waitForWindow("Overwrite Program Changes?", DEFAULT_WINDOW_TIMEOUT);
|
Window dialog = waitForWindow("Overwrite Program Changes?");
|
||||||
assertNotNull("Did not get expected overwrite dialog prompt", dialog);
|
assertNotNull("Did not get expected overwrite dialog prompt", dialog);
|
||||||
pressButtonByText(dialog, "Cancel");
|
pressButtonByText(dialog, "Cancel");
|
||||||
|
|
||||||
|
|
|
@ -362,10 +362,10 @@ public abstract class AbstractStackEditorTest extends AbstractEditorTest {
|
||||||
waitForBusyTool(tool);
|
waitForBusyTool(tool);
|
||||||
|
|
||||||
Function f = program.getFunctionManager().getFunctionAt(addr(address));
|
Function f = program.getFunctionManager().getFunctionAt(addr(address));
|
||||||
String funcName = f.getName();
|
stackEditorMgr.edit(f);
|
||||||
assertTrue(isProviderShown(tool.getToolFrame(), "Stack Editor",
|
CompositeEditorProvider<?, ?> p = getComponentProvider(CompositeEditorProvider.class);
|
||||||
StackEditorProvider.getProviderSubTitle(f)));
|
assertNotNull(p);
|
||||||
installProvider(stackEditorMgr.getProvider(program, funcName));
|
installProvider(p);
|
||||||
|
|
||||||
model = ((StackEditorProvider) provider).getModel();
|
model = ((StackEditorProvider) provider).getModel();
|
||||||
stackModel = (StackEditorModel) model;
|
stackModel = (StackEditorModel) model;
|
||||||
|
|
|
@ -25,6 +25,7 @@ import javax.swing.SwingUtilities;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
|
import ghidra.app.plugin.core.compositeeditor.CompositeEditorProvider;
|
||||||
import ghidra.app.util.datatype.EmptyCompositeException;
|
import ghidra.app.util.datatype.EmptyCompositeException;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
@ -173,9 +174,10 @@ public class StackEditorProvider1Test extends AbstractStackEditorProviderTest {
|
||||||
|
|
||||||
Function f = program.getFunctionManager().getFunctionAt(addr("0x200"));
|
Function f = program.getFunctionManager().getFunctionAt(addr("0x200"));
|
||||||
assertStackEditorShowing(f);
|
assertStackEditorShowing(f);
|
||||||
|
CompositeEditorProvider<?, ?> p = getComponentProvider(CompositeEditorProvider.class);
|
||||||
|
assertNotNull(p);
|
||||||
|
installProvider(p);
|
||||||
|
|
||||||
installProvider(stackEditorMgr.getProvider(program, "FUN_00000200"));
|
|
||||||
assertNotNull(provider);
|
|
||||||
model = ((StackEditorProvider) provider).getModel();
|
model = ((StackEditorProvider) provider).getModel();
|
||||||
assertNotNull(model);
|
assertNotNull(model);
|
||||||
|
|
||||||
|
|
|
@ -123,10 +123,10 @@ public class BackgroundCommandTaskTest extends AbstractGenericTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endTransaction(int transactionID, boolean commit) {
|
public boolean endTransaction(int transactionID, boolean commit) {
|
||||||
|
|
||||||
assertEquals(ID, transactionID);
|
assertEquals(ID, transactionID);
|
||||||
transactionCommited = commit;
|
transactionCommited = commit;
|
||||||
|
return transactionCommited;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean wasCommitted() {
|
boolean wasCommitted() {
|
||||||
|
|
|
@ -809,12 +809,13 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endTransaction(int transactionID, boolean commit) {
|
public boolean endTransaction(int transactionID, boolean commit) {
|
||||||
TransactionInfo transaction = getCurrentTransactionInfo();
|
TransactionInfo transaction = getCurrentTransactionInfo();
|
||||||
super.endTransaction(transactionID, commit);
|
boolean committed = super.endTransaction(transactionID, commit);
|
||||||
if (changeSetsModified && transaction.getStatus() == Status.COMMITTED) {
|
if (changeSetsModified && transaction.getStatus() == Status.COMMITTED) {
|
||||||
changeSetsModified = false;
|
changeSetsModified = false;
|
||||||
}
|
}
|
||||||
|
return committed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -165,9 +165,8 @@ public class EmptyVTSession implements VTSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endTransaction(int transactionID, boolean commit) {
|
public boolean endTransaction(int transactionID, boolean commit) {
|
||||||
// do nothing
|
throw new UnsupportedOperationException();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.util.function.Function;
|
||||||
import db.*;
|
import db.*;
|
||||||
import db.util.ErrorHandler;
|
import db.util.ErrorHandler;
|
||||||
import ghidra.framework.model.*;
|
import ghidra.framework.model.*;
|
||||||
|
import ghidra.framework.model.TransactionInfo.Status;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.options.SubOptions;
|
import ghidra.framework.options.SubOptions;
|
||||||
import ghidra.framework.store.LockException;
|
import ghidra.framework.store.LockException;
|
||||||
|
@ -358,8 +359,9 @@ public abstract class DomainObjectAdapterDB extends DomainObjectAdapter implemen
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endTransaction(int transactionID, boolean commit) throws IllegalStateException {
|
public boolean endTransaction(int transactionID, boolean commit) throws IllegalStateException {
|
||||||
transactionMgr.endTransaction(this, transactionID, commit, true);
|
TransactionInfo txInfo = transactionMgr.endTransaction(this, transactionID, commit, true);
|
||||||
|
return txInfo.getStatus() == Status.COMMITTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -500,11 +500,21 @@ public interface DomainObject {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminate the specified transaction for this domain object.
|
* Terminate the specified transaction for this domain object.
|
||||||
|
* <P>
|
||||||
|
* NOTE: If multiple transactions are outstanding the full transaction will not be ended
|
||||||
|
* until all transactions have been ended. If any of the transactions indicate a
|
||||||
|
* false for {@code commit} the transaction will ultimately be rolled-back when the final
|
||||||
|
* transaction is ended.
|
||||||
|
* <P>
|
||||||
|
* NOTE: Use of rollback ({@code commit=false} should be avoided unless absolutely
|
||||||
|
* neccessary since it will incur overhead to revert changes and may rollback multiple
|
||||||
|
* concurrent transactions if they exist.
|
||||||
* @param transactionID transaction ID obtained from startTransaction method
|
* @param transactionID transaction ID obtained from startTransaction method
|
||||||
* @param commit if true the changes made in this transaction will be marked for commit,
|
* @param commit if true the changes made in this transaction will be marked for commit,
|
||||||
* if false this and any concurrent transaction will be rolled-back.
|
* if false this and any concurrent transaction will be rolled-back.
|
||||||
|
* @return true if this invocation was the final transaction and all changes were comitted.
|
||||||
*/
|
*/
|
||||||
public void endTransaction(int transactionID, boolean commit);
|
public boolean endTransaction(int transactionID, boolean commit);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current transaction info
|
* Returns the current transaction info
|
||||||
|
@ -546,12 +556,12 @@ public interface DomainObject {
|
||||||
public void releaseSynchronizedDomainObject() throws LockException;
|
public void releaseSynchronizedDomainObject() throws LockException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if there is a previous state to "undo" to.
|
* {@return true if there is a previous state to "undo" to.}
|
||||||
*/
|
*/
|
||||||
boolean canUndo();
|
boolean canUndo();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if there is a later state to "redo" to.
|
* {@return true if there is a later state to "redo" to.}
|
||||||
*/
|
*/
|
||||||
boolean canRedo();
|
boolean canRedo();
|
||||||
|
|
||||||
|
|
|
@ -48,9 +48,10 @@ public class GenericDomainObjectDB extends DomainObjectAdapterDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endTransaction(int transactionID, boolean commit) {
|
public boolean endTransaction(int transactionID, boolean commit) {
|
||||||
super.endTransaction(transactionID, commit);
|
boolean committed = super.endTransaction(transactionID, commit);
|
||||||
transactionsList.add(currentTransaction);
|
transactionsList.add(currentTransaction);
|
||||||
currentTransaction = null;
|
currentTransaction = null;
|
||||||
|
return committed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,8 +212,8 @@ public class ProjectDataTypeManager extends StandAloneDataTypeManager
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endTransaction(int transactionID, boolean commit) {
|
public boolean endTransaction(int transactionID, boolean commit) {
|
||||||
dataTypeArchive.endTransaction(transactionID, commit);
|
return dataTypeArchive.endTransaction(transactionID, commit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -296,9 +296,8 @@ public class ProgramDataTypeManager extends ProgramBasedDataTypeManagerDB implem
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endTransaction(int transactionID, boolean commit) {
|
public boolean endTransaction(int transactionID, boolean commit) {
|
||||||
program.endTransaction(transactionID, commit);
|
return program.endTransaction(transactionID, commit);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -92,11 +92,11 @@ public final class BuiltInDataTypeManager extends StandAloneDataTypeManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void endTransaction(int transactionID, boolean commit) {
|
public synchronized boolean endTransaction(int transactionID, boolean commit) {
|
||||||
if (manager != null) {
|
if (manager != null) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
super.endTransaction(transactionID, commit);
|
return super.endTransaction(transactionID, commit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.program.model.data;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import db.Transaction;
|
import db.Transaction;
|
||||||
|
import ghidra.framework.model.DomainObject;
|
||||||
import ghidra.program.database.SpecExtension;
|
import ghidra.program.database.SpecExtension;
|
||||||
import ghidra.program.database.map.AddressMap;
|
import ghidra.program.database.map.AddressMap;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
|
@ -380,11 +381,27 @@ public interface DataTypeManager {
|
||||||
public int startTransaction(String description);
|
public int startTransaction(String description);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ends the current transaction
|
* Ends the current transaction.
|
||||||
|
* <P>
|
||||||
|
* NOTE: If multiple transactions are outstanding the full transaction will not be ended
|
||||||
|
* until all transactions have been ended. If any of the transactions indicate a
|
||||||
|
* false for {@code commit} the transaction will ultimately be rolled-back when the final
|
||||||
|
* transaction is ended.
|
||||||
|
* <P>
|
||||||
|
* NOTE: Use of rollback ({@code commit=false} should be avoided unless absolutely
|
||||||
|
* neccessary since it will incur overhead to revert changes and may rollback multiple
|
||||||
|
* concurrent transactions if they exist.
|
||||||
|
* <P>
|
||||||
|
* NOTE: If this manager is part of a larger {@link DomainObject} its transactions may become
|
||||||
|
* entangled with other transactions at a higher level. In such cases, use of the
|
||||||
|
* {@link DomainObject} transaction interface is preferred. The return value from this
|
||||||
|
* method cannot be relied on in such cases.
|
||||||
* @param transactionID id of the transaction to end
|
* @param transactionID id of the transaction to end
|
||||||
* @param commit true if changes are committed, false if changes in transaction are revoked
|
* @param commit true if changes are committed, false if changes in transaction should be
|
||||||
|
* rolled back.
|
||||||
|
* @return true if this invocation was the final transaction and all changes were comitted.
|
||||||
*/
|
*/
|
||||||
public void endTransaction(int transactionID, boolean commit);
|
public boolean endTransaction(int transactionID, boolean commit);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs the given callback inside of a transaction. Use this method in place of the more
|
* Performs the given callback inside of a transaction. Use this method in place of the more
|
||||||
|
|
|
@ -873,15 +873,15 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of active transactions
|
* Get the number of active datatype manager transactions
|
||||||
* @return number of active transactions
|
* @return number of active datatype manager transactions
|
||||||
*/
|
*/
|
||||||
protected int getTransactionCount() {
|
protected int getTransactionCount() {
|
||||||
return transactionCount;
|
return transactionCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endTransaction(int transactionID, boolean commit) {
|
public boolean endTransaction(int transactionID, boolean commit) {
|
||||||
boolean restored = false;
|
boolean restored = false;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (transaction == null) {
|
if (transaction == null) {
|
||||||
|
@ -917,6 +917,7 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos
|
||||||
invalidateCache();
|
invalidateCache();
|
||||||
notifyRestored();
|
notifyRestored();
|
||||||
}
|
}
|
||||||
|
return transaction == null && !restored;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void undo() {
|
public void undo() {
|
||||||
|
|
|
@ -60,7 +60,7 @@ public class StubProgram implements Program {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endTransaction(int transactionID, boolean commit) {
|
public boolean endTransaction(int transactionID, boolean commit) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -236,7 +236,7 @@ public class TestDoubleDataTypeManager implements DataTypeManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endTransaction(int transactionID, boolean commit) {
|
public boolean endTransaction(int transactionID, boolean commit) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -243,9 +243,9 @@ public class TestDummyDataTypeManager implements DataTypeManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endTransaction(int transactionID, boolean commit) {
|
public boolean endTransaction(int transactionID, boolean commit) {
|
||||||
// stub
|
// stub
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue