GP-5557 Composite editor transaction and update notification fixes

This commit is contained in:
ghidra1 2025-04-09 21:40:36 -04:00
parent 694b3b46ce
commit 0ef28cb54b
85 changed files with 703 additions and 633 deletions

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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

View file

@ -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

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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

View file

@ -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;
} }

View file

@ -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");

View file

@ -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));

View file

@ -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");

View file

@ -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;
} }
@ -990,7 +979,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);
@ -1014,7 +1002,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);
@ -1034,7 +1021,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;
} }
@ -1138,9 +1124,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;
@ -1279,7 +1263,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;
@ -1318,7 +1302,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());
@ -1375,7 +1363,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()) {
@ -1429,7 +1417,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);
@ -1463,20 +1455,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.
@ -1561,7 +1547,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()) {
@ -1727,15 +1713,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;
} }

View file

@ -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\">(&lt;F1&gt; for help)</font></html>"; "\" size=\"-2\">(&lt;F1&gt; 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);
} }

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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;

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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;

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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() {

View file

@ -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;
} }

View file

@ -1,13 +1,12 @@
/* ### /* ###
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -52,16 +51,6 @@ public interface CompositeEditorModelListener extends CompositeViewerModelListen
* COMPOSITE_LOADED, NO_COMPOSITE_LOADED, EDIT_STARTED, EDIT_ENDED. * COMPOSITE_LOADED, NO_COMPOSITE_LOADED, EDIT_STARTED, EDIT_ENDED.
*/ */
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.

View file

@ -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 -> {

View file

@ -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;
} }

View file

@ -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;

View file

@ -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) {

View file

@ -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);
} }
}); });

View file

@ -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(

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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;
@ -162,7 +163,8 @@ public class DataTypeHelper {
* index where it will be located. If the data type is a valid size, it * index where it will be located. If the data type is a valid size, it
* 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();

View file

@ -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));

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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;

View file

@ -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));

View file

@ -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));

View file

@ -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)) {

View file

@ -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);

View file

@ -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));

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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();

View file

@ -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;

View file

@ -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"));

View file

@ -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());

View file

@ -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));

View file

@ -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));

View file

@ -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));

View file

@ -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));

View file

@ -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()) : "");

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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());

View file

@ -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);
} }

View file

@ -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));

View file

@ -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 " +
@ -1329,8 +1321,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();
@ -1373,13 +1363,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());
} }
} }
@ -1406,7 +1396,6 @@ class StructureEditorModel extends CompEditorModel {
comp.setComment(comment); comp.setComment(comment);
}); });
fixSelection(); fixSelection();
componentEdited();
selectionChanged(); selectionChanged();
} }
} }

View file

@ -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);
}

View file

@ -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 });
}
}

View file

@ -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();

View file

@ -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()) : "");

View file

@ -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) {

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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);
} }

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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");

View file

@ -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)) {

View file

@ -1,13 +1,12 @@
/* ### /* ###
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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();

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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());
}
} }

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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);

View file

@ -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,19 +1178,26 @@ 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) {
DataType dataType = dataTypeManager.getDataType(path); throw new AssertException("Listener only supports original DTM");
OffsetPairs offsetSelection = getRelOffsetSelection();
adjustComponents(dataType);
fireTableDataChanged();
componentDataChanged();
setRelOffsetSelection(offsetSelection);
} }
if (!isLoaded()) {
return;
}
DataType dataType = dataTypeManager.getDataType(path);
OffsetPairs offsetSelection = getRelOffsetSelection();
adjustComponents(dataType);
fireTableDataChanged();
componentDataChanged();
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,61 +1211,63 @@ 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) {
OffsetPairs offsetSelection = getRelOffsetSelection(); throw new AssertException("Listener only supports original DTM");
DataType dataType = dataTypeManager.getDataType(path);
replaceComponents(dataType, DataType.DEFAULT);
fireTableDataChanged();
componentDataChanged();
setRelOffsetSelection(offsetSelection);
} }
if (!isLoaded()) {
return;
}
OffsetPairs offsetSelection = getRelOffsetSelection();
DataType dataType = dataTypeManager.getDataType(path);
replaceComponents(dataType, DataType.DEFAULT);
fireTableDataChanged();
componentDataChanged();
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) {
return;
}
DataTypePath originalPath = getOriginalDataTypePath();
if (originalDataTypeManager == null || originalPath == null) {
return;
}
if (!oldPath.equals(originalPath)) {
return;
}
// Don't try to actually rename, since we shouldn't get name change on a
// fabricated stack data type.
OffsetPairs offsetSelection = getRelOffsetSelection();
fireTableDataChanged();
componentDataChanged();
setRelOffsetSelection(offsetSelection);
} }
if (!isLoaded()) {
return;
}
DataTypePath originalPath = getOriginalDataTypePath();
if (originalPath == null || !oldPath.equals(originalPath)) {
return;
}
// Don't try to actually rename, since we shouldn't get name change on a
// fabricated stack data type.
OffsetPairs offsetSelection = getRelOffsetSelection();
fireTableDataChanged();
componentDataChanged();
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) {
DataType oldDataType = viewDTM.getDataType(oldPath); throw new AssertException("Listener only supports original DTM");
OffsetPairs offsetSelection = getRelOffsetSelection();
replaceComponents(oldDataType, newDataType);
fireTableDataChanged();
componentDataChanged();
setRelOffsetSelection(offsetSelection);
} }
if (!isLoaded()) {
return;
}
DataType oldDataType = viewDTM.getDataType(oldPath);
OffsetPairs offsetSelection = getRelOffsetSelection();
replaceComponents(oldDataType, newDataType);
fireTableDataChanged();
componentDataChanged();
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();
} }

View file

@ -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

View file

@ -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)) {

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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);
} }

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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

View file

@ -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) {

View file

@ -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");

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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);
} }

View file

@ -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 =

View file

@ -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());

View file

@ -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");

View file

@ -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");

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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;

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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;

View file

@ -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 });

View file

@ -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()));

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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");

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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;

View file

@ -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);

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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() {

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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

View file

@ -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;
} }
/** /**

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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();

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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;
} }
} }

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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

View file

@ -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() {

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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();
} }

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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();
} }

View file

@ -4,9 +4,9 @@
* 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.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -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