diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java index 832d6e0e50..6f510b2e29 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java @@ -4,9 +4,9 @@ * 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. @@ -217,8 +217,8 @@ public class DBTraceDataTypeManager extends ProgramBasedDataTypeManagerDB } @Override - public void endTransaction(int transactionID, boolean commit) { - trace.endTransaction(transactionID, commit); + public boolean endTransaction(int transactionID, boolean commit) { + return trace.endTransaction(transactionID, commit); } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java index 66db8ab1c5..8cdfa64106 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java @@ -1173,8 +1173,8 @@ public class DBTraceProgramView implements TraceProgramView { } @Override - public void endTransaction(int transactionID, boolean commit) { - trace.endTransaction(transactionID, commit); + public boolean endTransaction(int transactionID, boolean commit) { + return trace.endTransaction(transactionID, commit); } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRegisters.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRegisters.java index b707c517b3..36cb3c0f6b 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRegisters.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRegisters.java @@ -4,9 +4,9 @@ * 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. @@ -384,8 +384,8 @@ public class DBTraceProgramViewRegisters implements TraceProgramView { } @Override - public void endTransaction(int transactionID, boolean commit) { - view.endTransaction(transactionID, commit); + public boolean endTransaction(int transactionID, boolean commit) { + return view.endTransaction(transactionID, commit); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/AddBitFieldAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/AddBitFieldAction.java index 7ff80ee7db..9b84ce600e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/AddBitFieldAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/AddBitFieldAction.java @@ -26,7 +26,7 @@ public class AddBitFieldAction extends CompositeEditorTableAction { "Add a bitfield at the position of a selected component"; 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); setDescription(DESCRIPTION); if (!(model instanceof CompEditorModel)) { @@ -46,9 +46,9 @@ public class AddBitFieldAction extends CompositeEditorTableAction { return false; } boolean enabled = true; - CompEditorModel editorModel = (CompEditorModel) model; + CompEditorModel editorModel = (CompEditorModel) model; // Unions do not support non-packed manipulation of bitfields - if (!(provider instanceof StructureEditorProvider structProvider) || + if (!(provider instanceof StructureEditorProvider) || editorModel.isPackingEnabled() || editorModel.getNumSelectedRows() != 1) { enabled = false; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ApplyAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ApplyAction.java index d68abb2320..9c53c87e58 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ApplyAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ApplyAction.java @@ -32,7 +32,7 @@ public class ApplyAction extends CompositeEditorTableAction { private final static Icon ICON = new GIcon("icon.plugin.composite.editor.apply"); 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); setDescription("Apply editor changes"); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ArrayAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ArrayAction.java index 131ef80940..6a809c931b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ArrayAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ArrayAction.java @@ -38,7 +38,7 @@ public class ArrayAction extends CompositeEditorTableAction { private final static KeyStroke KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, 0); 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); setDescription(DESCRIPTION); setKeyBindingData(new KeyBindingData(KEY_STROKE)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ClearAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ClearAction.java index 8b3aaa1c59..8e5bddbe46 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ClearAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ClearAction.java @@ -33,7 +33,7 @@ public class ClearAction extends CompositeEditorTableAction { private final static String[] POPUP_PATH = new String[] { "Clear" }; 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); setDescription("Clear the selected components"); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompEditorModel.java index 417010fcc9..d7a69ecd28 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompEditorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompEditorModel.java @@ -29,7 +29,7 @@ import ghidra.util.*; import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; -public abstract class CompEditorModel extends CompositeEditorModel { +public abstract class CompEditorModel extends CompositeEditorModel { private volatile boolean consideringReplacedDataType = false; @@ -37,7 +37,7 @@ public abstract class CompEditorModel extends CompositeEditorModel { * Creates a model for editing a composite data type. * @param provider the provider that is using this model for editing. */ - CompEditorModel(CompositeEditorProvider provider) { + CompEditorModel(CompositeEditorProvider> provider) { super(provider); } @@ -54,7 +54,7 @@ public abstract class CompEditorModel extends CompositeEditorModel { * @param dataType the composite data type being edited. */ @Override - public void load(Composite dataType) { + public void load(T dataType) { super.load(dataType); fixSelection(); selectionChanged(); @@ -76,7 +76,7 @@ public abstract class CompEditorModel extends CompositeEditorModel { } FieldSelection saveSelection = new FieldSelection(selection); - Composite originalDt = getOriginalComposite(); + T originalDt = getOriginalComposite(); if (originalDt == null || originalDTM == null) { throw new IllegalStateException( "Can't apply edits without a data type or data type manager."); @@ -118,7 +118,8 @@ public abstract class CompEditorModel extends CompositeEditorModel { load(originalDt); } else { - Composite dt = (Composite) originalDTM.resolve(viewComposite, null); + @SuppressWarnings("unchecked") + T dt = (T) originalDTM.resolve(viewComposite, null); load(dt); } return true; @@ -376,7 +377,6 @@ public abstract class CompEditorModel extends CompositeEditorModel { int componentOrdinal = convertRowToOrdinal(rowIndex); delete(componentOrdinal); fixSelection(); - componentEdited(); selectionChanged(); } @@ -411,8 +411,6 @@ public abstract class CompEditorModel extends CompositeEditorModel { } viewDTM.withTransaction("Delete Components", () -> viewComposite.delete(ordinals)); fixSelection(); - componentEdited(); - notifyCompositeChanged(); selectionChanged(); } @@ -427,12 +425,7 @@ public abstract class CompEditorModel extends CompositeEditorModel { int[] selectedComponents = getSelectedComponentRows(); int firstRowIndex = !selection.isEmpty() ? selectedComponents[0] : getRowCount(); - try { - delete(selectedComponents); - } - finally { - componentEdited(); - } + delete(selectedComponents); selection.addRange(firstRowIndex, firstRowIndex + 1); fixSelection(); selectionChanged(); @@ -532,7 +525,6 @@ public abstract class CompEditorModel extends CompositeEditorModel { } DataTypeComponent dtc = insert(rowIndex, datatype, length, null, null); fixSelection(); - componentEdited(); selectionChanged(); return dtc; } @@ -562,7 +554,6 @@ public abstract class CompEditorModel extends CompositeEditorModel { checkIsAllowableDataType(dataType); insertMultiple(rowIndex, dataType, dtLen, multiple, monitor); fixSelection(); - componentEdited(); selectionChanged(); } @@ -601,7 +592,7 @@ public abstract class CompEditorModel extends CompositeEditorModel { }); fixSelection(); - componentEdited(); +// componentEdited(); selectionChanged(); return dtc; } @@ -637,7 +628,7 @@ public abstract class CompEditorModel extends CompositeEditorModel { } fixSelection(); - componentEdited(); + //componentEdited(); selectionChanged(); return dtc; } @@ -753,7 +744,6 @@ public abstract class CompEditorModel extends CompositeEditorModel { replace(rowIndex, datatype, newCompSize, oldDtc.getFieldName(), oldDtc.getComment()); fixSelection(); - componentEdited(); selectionChanged(); return dtc; } @@ -806,7 +796,6 @@ public abstract class CompEditorModel extends CompositeEditorModel { } dtc.setComment(oldDtc.getComment()); fixSelection(); - componentEdited(); selectionChanged(); return dtc; } @@ -994,7 +983,6 @@ public abstract class CompEditorModel extends CompositeEditorModel { int newIndex = startIndex - 1; moved = shiftComponentsUp(startIndex, endIndex); if (moved) { - componentEdited(); FieldSelection tmpFieldSelection = new FieldSelection(); tmpFieldSelection.addRange(newIndex, newIndex + numSelected); setSelection(tmpFieldSelection); @@ -1018,7 +1006,6 @@ public abstract class CompEditorModel extends CompositeEditorModel { int newIndex = startIndex + 1; moved = shiftComponentsDown(startIndex, endIndex); if (moved) { - componentEdited(); FieldSelection tmpFieldSelection = new FieldSelection(); tmpFieldSelection.addRange(newIndex, newIndex + numSelected); setSelection(tmpFieldSelection); @@ -1038,7 +1025,6 @@ public abstract class CompEditorModel extends CompositeEditorModel { // Adjust the selection since we added some components. Select last component added. setSelection(new int[] { rowIndex + multiple }); - componentEdited(); lastNumDuplicates = multiple; } @@ -1143,9 +1129,7 @@ public abstract class CompEditorModel extends CompositeEditorModel { public void setValueAt(Object aValue, int rowIndex, int modelColumnIndex) { try { settingValueAt = true; - if (fieldEdited(aValue, rowIndex, modelColumnIndex)) { - componentEdited(); - } + fieldEdited(aValue, rowIndex, modelColumnIndex); } finally { settingValueAt = false; @@ -1284,7 +1268,7 @@ public abstract class CompEditorModel extends CompositeEditorModel { return; } - Composite composite = getOriginalComposite(); + T composite = getOriginalComposite(); boolean reload = true; if (hasChanges || !viewComposite.isEquivalent(composite)) { hasChanges = true; @@ -1323,7 +1307,11 @@ public abstract class CompEditorModel extends CompositeEditorModel { public void dataTypeRemoved(DataTypeManager dtm, DataTypePath path) { 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()); @@ -1380,7 +1368,7 @@ public abstract class CompEditorModel extends CompositeEditorModel { public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) { if (dtm != originalDTM) { - return; // Different DTM than the one for this data type. + throw new AssertException("Listener only supports original DTM"); } if (!isLoaded()) { @@ -1434,7 +1422,11 @@ public abstract class CompEditorModel extends CompositeEditorModel { public void dataTypeMoved(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) { 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); @@ -1468,20 +1460,14 @@ public abstract class CompEditorModel extends CompositeEditorModel { public void dataTypeChanged(DataTypeManager dtm, DataTypePath path) { try { + if (dtm != originalDTM) { + throw new AssertException("Listener only supports original DTM"); + } + if (!isLoaded()) { 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 // the structure in the editor just changed, then show the changed // structure. @@ -1566,7 +1552,7 @@ public abstract class CompEditorModel extends CompositeEditorModel { DataType newDataType) { if (dtm != originalDTM) { - return; // Different DTM than the one for this data type. + throw new AssertException("Listener only supports original DTM"); } if (!isLoaded()) { @@ -1723,15 +1709,6 @@ public abstract class CompEditorModel extends CompositeEditorModel { 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) { return rowIndex; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompEditorPanel.java index 087be34bad..4215423be8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompEditorPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompEditorPanel.java @@ -32,7 +32,6 @@ import org.apache.commons.lang3.StringUtils; import docking.widgets.OptionDialog; import docking.widgets.button.GRadioButton; -import docking.widgets.fieldpanel.support.FieldSelection; import docking.widgets.label.GDLabel; import docking.widgets.textfield.GFormattedTextField; 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 * when in unlocked mode. + * + * @param Specific {@link Composite} type being edited + * @param Specific {@link CompEditorModel} implementation which supports editing T */ -public class CompEditorPanel extends CompositeEditorPanel { +public class CompEditorPanel> + extends CompositeEditorPanel { protected final static Insets LEFT_INSETS = new Insets(2, 3, 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 * the editor provider furnishing this panel for editing. */ - public CompEditorPanel(CompEditorModel model, CompositeEditorProvider provider) { + public CompEditorPanel(M model, CompositeEditorProvider provider) { super(model, provider); } @@ -356,6 +359,7 @@ public class CompEditorPanel extends CompositeEditorPanel { public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { e.consume(); + setStatus(""); // revert to model state when escape is hit setCompositeName(model.getCompositeName()); } @@ -406,6 +410,7 @@ public class CompEditorPanel extends CompositeEditorPanel { public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { e.consume(); + setStatus(""); // revert to model state when escape is hit setDescription(model.getDescription()); } @@ -523,7 +528,7 @@ public class CompEditorPanel extends CompositeEditorPanel { "setting and the alignment of each component data type."; defaultAlignButton.addActionListener(e -> { - ((CompEditorModel) model).setAlignmentType(AlignmentType.DEFAULT, -1); + model.setAlignmentType(AlignmentType.DEFAULT, -1); }); defaultAlignButton.setToolTipText(alignmentToolTip); @@ -532,7 +537,7 @@ public class CompEditorPanel extends CompositeEditorPanel { private void setupMachineMinAlignButton() { DataOrganization dataOrganization = - ((CompEditorModel) model).viewComposite.getDataOrganization(); + model.viewComposite.getDataOrganization(); int machineAlignment = dataOrganization.getMachineAlignment(); machineAlignButton = new GRadioButton("machine: " + machineAlignment); @@ -546,7 +551,7 @@ public class CompEditorPanel extends CompositeEditorPanel { machineAlignButton.setToolTipText(alignmentToolTip); machineAlignButton.addActionListener(e -> { - ((CompEditorModel) model).setAlignmentType(AlignmentType.MACHINE, -1); + model.setAlignmentType(AlignmentType.MACHINE, -1); }); provider.registerHelp(machineAlignButton, "Align"); @@ -634,7 +639,7 @@ public class CompEditorPanel extends CompositeEditorPanel { return; } try { - ((CompEditorModel) model).setAlignmentType(AlignmentType.EXPLICIT, minAlignment); + model.setAlignmentType(AlignmentType.EXPLICIT, minAlignment); adjustCompositeInfo(); } catch (IllegalArgumentException e1) { @@ -664,7 +669,7 @@ public class CompEditorPanel extends CompositeEditorPanel { infoPanel.add(actualAlignmentPanel, gridBagConstraints); actualAlignmentValueLabel = new JLabel(); - int actualAlignment = ((CompEditorModel) model).getActualAlignment(); + int actualAlignment = model.getActualAlignment(); actualAlignmentValueLabel.setText(Integer.toString(actualAlignment)); actualAlignmentValueLabel.setToolTipText(actualAlignmentToolTip); actualAlignmentValueLabel.setBackground(getBackground()); @@ -765,7 +770,7 @@ public class CompEditorPanel extends CompositeEditorPanel { "(<F1> for help)"; packingEnablementButton.addActionListener(e -> { - ((CompEditorModel) model).setPackingType( + model.setPackingType( packingEnablementButton.isSelected() ? PackingType.DEFAULT : PackingType.DISABLED, -1); }); @@ -783,7 +788,7 @@ public class CompEditorPanel extends CompositeEditorPanel { "Indicates default compiler packing rules should be applied."; defaultPackingButton.addActionListener(e -> { - ((CompEditorModel) model).setPackingType(PackingType.DEFAULT, -1); + model.setPackingType(PackingType.DEFAULT, -1); }); defaultPackingButton.setToolTipText(packingToolTipText); @@ -860,7 +865,7 @@ public class CompEditorPanel extends CompositeEditorPanel { } private void chooseByValuePacking() { - ((CompEditorModel) model).setPackingType(PackingType.EXPLICIT, 1); + model.setPackingType(PackingType.EXPLICIT, 1); explicitPackingTextField.selectAll(); explicitPackingTextField.requestFocus(); } @@ -873,7 +878,7 @@ public class CompEditorPanel extends CompositeEditorPanel { if (explicitPacking <= 0) { return; } - ((CompEditorModel) model).setPackingType(PackingType.EXPLICIT, explicitPacking); + model.setPackingType(PackingType.EXPLICIT, explicitPacking); adjustCompositeInfo(); } @@ -881,7 +886,7 @@ public class CompEditorPanel extends CompositeEditorPanel { * Sets the currently displayed structure packing value (maximum component alignment) */ public void refreshGUIPackingValue() { - PackingType packingType = ((CompEditorModel) model).getPackingType(); + PackingType packingType = model.getPackingType(); String packingString = ""; boolean packingEnabled = packingType != PackingType.DISABLED; @@ -895,7 +900,7 @@ public class CompEditorPanel extends CompositeEditorPanel { defaultPackingButton.setSelected(true); } else if (packingType == PackingType.EXPLICIT) { - int packValue = ((CompEditorModel) model).getExplicitPackingValue(); + int packValue = model.getExplicitPackingValue(); packingString = model.showHexNumbers ? CompositeViewerModel.getHexString(packValue, true) : Integer.toString(packValue); @@ -985,7 +990,7 @@ public class CompEditorPanel extends CompositeEditorPanel { return; } - if (!((CompEditorModel) model).isSizeEditable()) { + if (!model.isSizeEditable()) { return; } @@ -1022,13 +1027,13 @@ public class CompEditorPanel extends CompositeEditorPanel { } private void chooseExplicitAlign() { - if (((CompEditorModel) model).getAlignmentType() != AlignmentType.EXPLICIT) { - Composite viewComposite = ((CompEditorModel) model).viewComposite; + if (model.getAlignmentType() != AlignmentType.EXPLICIT) { + Composite viewComposite = model.viewComposite; int defaultValue = 1; if (viewComposite.isPackingEnabled()) { defaultValue = viewComposite.getDataOrganization().getMachineAlignment(); } - ((CompEditorModel) model).setAlignmentType(AlignmentType.EXPLICIT, defaultValue); + model.setAlignmentType(AlignmentType.EXPLICIT, defaultValue); } explicitAlignTextField.selectAll(); explicitAlignTextField.requestFocus(); @@ -1118,6 +1123,8 @@ public class CompEditorPanel extends CompositeEditorPanel { return; } + setStatus(""); + // Adjust the value. String newName = nameTextField.getText().trim(); if (!DataUtilities.isValidDataTypeName(newName)) { @@ -1163,6 +1170,8 @@ public class CompEditorPanel extends CompositeEditorPanel { return; } + setStatus(""); + String newValue = this.descriptionTextField.getText().trim(); if (!newValue.equals(model.getDescription())) { model.setDescription(newValue); @@ -1197,7 +1206,6 @@ public class CompEditorPanel extends CompositeEditorPanel { nameTextField.setText(name); nameTextField.setDefaultValue(name); nameTextField.setIsError(false); - setStatus(""); } /** @@ -1209,12 +1217,11 @@ public class CompEditorPanel extends CompositeEditorPanel { descriptionTextField.setText(description); descriptionTextField.setDefaultValue(description); descriptionTextField.setIsError(false); - setStatus(""); } public void refreshGUIMinimumAlignmentValue() { - AlignmentType alignmentType = ((CompEditorModel) model).getAlignmentType(); + AlignmentType alignmentType = model.getAlignmentType(); String minimumAlignmentStr = ""; if (alignmentType == AlignmentType.DEFAULT) { defaultAlignButton.setSelected(true); @@ -1224,7 +1231,7 @@ public class CompEditorPanel extends CompositeEditorPanel { } else { explicitAlignButton.setSelected(true); - int minimumAlignment = ((CompEditorModel) model).getExplicitMinimumAlignment(); + int minimumAlignment = model.getExplicitMinimumAlignment(); minimumAlignmentStr = model.showHexNumbers ? CompositeViewerModel.getHexString(minimumAlignment, true) : Integer.toString(minimumAlignment); @@ -1238,7 +1245,7 @@ public class CompEditorPanel extends CompositeEditorPanel { * Updates the GUI display of the actual alignment value. */ public void refreshGUIActualAlignmentValue() { - int actualAlignment = ((CompEditorModel) model).getActualAlignment(); + int actualAlignment = model.getActualAlignment(); String alignmentStr = model.showHexNumbers ? CompositeViewerModel.getHexString(actualAlignment, true) : Integer.toString(actualAlignment); @@ -1259,7 +1266,7 @@ public class CompEditorPanel extends CompositeEditorPanel { * @param size the new size */ private void setCompositeSize(int size) { - boolean sizeIsEditable = ((CompEditorModel) model).isSizeEditable(); + boolean sizeIsEditable = model.isSizeEditable(); if (sizeTextField.isEditable() != sizeIsEditable) { setSizeEditable(sizeIsEditable); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ComponentProgramActionContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ComponentProgramActionContext.java index a2411f58ea..d72a1fb7b9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ComponentProgramActionContext.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ComponentProgramActionContext.java @@ -4,9 +4,9 @@ * 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. @@ -29,7 +29,7 @@ public class ComponentProgramActionContext extends ProgramActionContext private DataTypeComponent component; private Composite composite; - public ComponentProgramActionContext(CompositeEditorProvider compositeEditorProvider, + public ComponentProgramActionContext(CompositeEditorProvider compositeEditorProvider, Program program, DataTypeComponent component) { super(compositeEditorProvider, program); this.component = component; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ComponentStandAloneActionContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ComponentStandAloneActionContext.java index 97a48993a7..39a607c761 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ComponentStandAloneActionContext.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ComponentStandAloneActionContext.java @@ -4,9 +4,9 @@ * 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. @@ -29,7 +29,7 @@ public class ComponentStandAloneActionContext extends DefaultActionContext private DataTypeComponent component; private Composite composite; - public ComponentStandAloneActionContext(CompositeEditorProvider compositeEditorProvider, + public ComponentStandAloneActionContext(CompositeEditorProvider compositeEditorProvider, DataTypeComponent component) { super(compositeEditorProvider); this.component = component; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorActionManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorActionManager.java index aaba8d57cc..890a3fb6d2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorActionManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorActionManager.java @@ -4,9 +4,9 @@ * 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. @@ -26,7 +26,7 @@ import ghidra.program.model.data.*; * Other CompositeEditorActions can be added for it to manage. */ public class CompositeEditorActionManager { - private CompositeEditorProvider provider; + private CompositeEditorProvider provider; private ArrayList editorActions = new ArrayList(); private ArrayList favoritesActions = @@ -45,7 +45,7 @@ public class CompositeEditorActionManager { * @param provider the provider that owns this composite editor action manager * favorites and cycle groups. */ - public CompositeEditorActionManager(CompositeEditorProvider provider) { + public CompositeEditorActionManager(CompositeEditorProvider provider) { this.provider = provider; this.dataTypeMgrService = provider.dtmService; adapter = new DataTypeManagerChangeListenerAdapter() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModel.java index 942bc35cf4..33e033a346 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModel.java @@ -43,8 +43,12 @@ import ghidra.util.task.TaskMonitor; /** * Model for editing a composite data type. Specific composite data type editors * should extend this class. + * + * @param Specific {@link Composite} type being managed */ -abstract public class CompositeEditorModel extends CompositeViewerModel { +abstract public class CompositeEditorModel extends CompositeViewerModel { + + // 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 @@ -71,7 +75,8 @@ abstract public class CompositeEditorModel extends CompositeViewerModel { * Construct abstract composite editor model * @param provider composite editor provider */ - protected CompositeEditorModel(CompositeEditorProvider provider) { + protected CompositeEditorModel( + CompositeEditorProvider> provider) { super(provider); } @@ -88,7 +93,7 @@ abstract public class CompositeEditorModel extends CompositeViewerModel { endFieldEditing(); } - CompositeViewerDataTypeManager oldViewDTM = viewDTM; + CompositeViewerDataTypeManager oldViewDTM = viewDTM; originalComposite = viewDTM.getResolvedViewComposite(); originalCompositeId = DataTypeManager.NULL_DATATYPE_ID; @@ -96,8 +101,8 @@ abstract public class CompositeEditorModel extends CompositeViewerModel { currentName = originalComposite.getName(); // Use temporary standalone view datatype manager - viewDTM = new CompositeViewerDataTypeManager(viewDTM.getName(), - viewDTM.getResolvedViewComposite(), () -> restoreEditor()); + viewDTM = new CompositeViewerDataTypeManager<>(viewDTM.getName(), + viewDTM.getResolvedViewComposite(), this::componentEdited, this::restoreEditor); 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 // underlying datatype default setting value being presented when adjusting component // default settings. - cloneAllComponentSettings(originalComposite, viewComposite); + viewDTM.withTransaction("Load Settings", + () -> cloneAllComponentSettings(originalComposite, viewComposite)); + viewDTM.clearUndo(); // Dispose previous view DTM oldViewDTM.close(); @@ -124,7 +131,7 @@ abstract public class CompositeEditorModel extends CompositeViewerModel { } @Override - public void load(Composite dataType) { + public void load(T dataType) { Objects.requireNonNull(dataType); DataTypeManager dtm = dataType.getDataTypeManager(); @@ -179,19 +186,30 @@ abstract public class CompositeEditorModel extends CompositeViewerModel { currentName = viewComposite.getName(); updateAndCheckChangeState(); - clearStatus(); compositeInfoChanged(); fireTableDataChanged(); 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 * changes listener(s) if required. * * @param original original composite being loaded */ - protected void createViewCompositeFromOriginalComposite(Composite original) { + protected void createViewCompositeFromOriginalComposite(T original) { if (viewDTM != null) { viewDTM.close(); @@ -199,8 +217,8 @@ abstract public class CompositeEditorModel extends CompositeViewerModel { } // Use temporary standalone view datatype manager - viewDTM = new CompositeViewerDataTypeManager(original.getDataTypeManager().getName(), - original, () -> restoreEditor()); + viewDTM = new CompositeViewerDataTypeManager<>(original.getDataTypeManager().getName(), + original, this::componentEdited, this::restoreEditor); 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 // underlying datatype default setting value being presented when adjusting component // default settings. - viewDTM.withTransaction("Apply Settings", + viewDTM.withTransaction("Load Settings", () -> cloneAllComponentSettings(original, viewComposite)); viewDTM.clearUndo(); } @@ -236,7 +254,7 @@ abstract public class CompositeEditorModel extends CompositeViewerModel { * Returns the docking windows component provider associated with this edit model. * @return the component provider */ - protected CompositeEditorProvider getProvider() { + protected CompositeEditorProvider getProvider() { return provider; } @@ -1485,7 +1503,7 @@ abstract public class CompositeEditorModel extends CompositeViewerModel { * Get the composite edtor's datatype manager * @return composite edtor's datatype manager */ - public CompositeViewerDataTypeManager getViewDataTypeManager() { + public CompositeViewerDataTypeManager getViewDataTypeManager() { return viewDTM; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModelListener.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModelListener.java index d86046ce1f..2471089650 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModelListener.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorModelListener.java @@ -1,13 +1,12 @@ /* ### * 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. @@ -52,16 +51,6 @@ public interface CompositeEditorModelListener extends CompositeViewerModelListen * COMPOSITE_LOADED, NO_COMPOSITE_LOADED, EDIT_STARTED, EDIT_ENDED. */ 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. diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java index 435ef41b7c..8c720ef3be 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java @@ -32,7 +32,6 @@ import javax.swing.text.JTextComponent; import org.apache.commons.lang3.StringUtils; -import docking.DockingWindowManager; import docking.actions.KeyBindingUtils; import docking.dnd.DropTgtAdapter; import docking.dnd.Droppable; @@ -64,14 +63,18 @@ import help.HelpService; * 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 * composite data type. To add your own info panel override the createInfoPanel() method. + * + * @param Specific {@link Composite} type being edited + * @param Specific {@link CompositeEditorModel} implementation which supports editing T */ -public abstract class CompositeEditorPanel extends JPanel +public abstract class CompositeEditorPanel> + extends JPanel implements CompositeEditorModelListener, ComponentCellEditorListener, Droppable { protected static final Border BEVELED_BORDER = BorderFactory.createLoweredBevelBorder(); - protected CompositeEditorProvider provider; - protected CompositeEditorModel model; + protected CompositeEditorProvider provider; + protected M model; protected GTable table; private JLabel statusLabel; @@ -90,7 +93,7 @@ public abstract class CompositeEditorPanel extends JPanel protected SearchControlPanel searchPanel; - public CompositeEditorPanel(CompositeEditorModel model, CompositeEditorProvider provider) { + public CompositeEditorPanel(M model, CompositeEditorProvider provider) { super(new BorderLayout()); this.provider = provider; this.model = model; @@ -145,7 +148,7 @@ public abstract class CompositeEditorPanel extends JPanel return table; } - protected CompositeEditorModel getModel() { + protected M getModel() { return model; } @@ -165,30 +168,10 @@ public abstract class CompositeEditorPanel extends JPanel table.setDefaultRenderer(DataTypeInstance.class, dtiCellRenderer); } - private 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; - } - } + boolean launchBitFieldEditor(int modelRow, int modelColumn) { return false; } - private void refreshTableAndSelection(CompEditorModel editorModel, int ordinal) { - editorModel.notifyCompositeChanged(); - editorModel.setSelection(new int[] { ordinal, ordinal }); - } - private void setupTableCellEditor() { table.addPropertyChangeListener("tableCellEditor", evt -> { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorProvider.java index deb7e36560..d9cdb76953 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorProvider.java @@ -17,7 +17,8 @@ package ghidra.app.plugin.core.compositeeditor; import java.awt.event.MouseEvent; -import javax.swing.*; +import javax.swing.Icon; +import javax.swing.JTable; import docking.*; import docking.widgets.OptionDialog; @@ -41,16 +42,20 @@ import utilities.util.reflection.ReflectionUtilities; /** * Editor provider for a Composite Data Type. + * + * @param Specific {@link Composite} type being edited + * @param Specific {@link CompositeEditorModel} implementation which supports editing T */ -public abstract class CompositeEditorProvider extends ComponentProviderAdapter +public abstract class CompositeEditorProvider> + extends ComponentProviderAdapter implements EditorProvider, EditorActionListener { protected static final Icon EDITOR_ICON = new GIcon("icon.plugin.composite.editor.provider"); protected Plugin plugin; protected Category category; - protected CompositeEditorPanel editorPanel; - protected CompositeEditorModel editorModel; + protected CompositeEditorPanel editorPanel; + protected CompositeEditorModel editorModel; protected WeakSet listeners; // listeners for the editor closing. protected DataTypeManagerService dtmService; @@ -90,7 +95,7 @@ public abstract class CompositeEditorProvider extends ComponentProviderAdapter setTitle(getName() + " - " + getProviderSubTitle(editorModel.originalComposite)); } - protected CompositeEditorModel getModel() { + protected CompositeEditorModel getModel() { return this.editorModel; } @@ -178,7 +183,7 @@ public abstract class CompositeEditorProvider extends ComponentProviderAdapter } @Override - public JComponent getComponent() { + public CompositeEditorPanel getComponent() { return editorPanel; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorTableAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorTableAction.java index 29ec596101..6bb4f31ad4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorTableAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorTableAction.java @@ -39,8 +39,8 @@ abstract public class CompositeEditorTableAction extends DockingAction { static final String COMPONENT_ACTION_GROUP = "4_COMPONENT_EDITOR_ACTION"; static final String BITFIELD_ACTION_GROUP = "5_COMPONENT_EDITOR_ACTION"; - protected CompositeEditorProvider provider; - protected CompositeEditorModel model; + protected CompositeEditorProvider provider; + protected CompositeEditorModel model; protected String tooltip; protected ImageIcon icon; 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; // 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()); init(provider); } - public CompositeEditorTableAction(CompositeEditorProvider provider, String name, String group, + public CompositeEditorTableAction(CompositeEditorProvider provider, String name, + String group, String[] popupPath, String[] menuPath, Icon icon) { super(name, provider.plugin.getName(), KeyBindingType.SHARED); 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.model = provider.getModel(); this.plugin = provider.plugin; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerDataTypeManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerDataTypeManager.java index 52a702bfb0..c6e891bee1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerDataTypeManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerDataTypeManager.java @@ -23,6 +23,7 @@ import db.util.ErrorHandler; import ghidra.program.database.DatabaseObject; import ghidra.program.model.data.*; import ghidra.program.model.lang.ProgramArchitecture; +import ghidra.util.Swing; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; @@ -30,11 +31,12 @@ import utility.function.Callback; /** * {@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 * the editor. + * @param Specific {@link Composite} type being managed */ -public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager +public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager implements ErrorHandler { /** @@ -42,16 +44,18 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager * This is where the edited datatype will be written back to. */ private final DataTypeManager originalDTM; - private final Composite 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 originalComposite; // 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 // This is needed to account for datatype use and ID alterations across undo/redo 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 changeCallback; private int transactionId = 0; + private boolean dataTypeChanged; // Modification count used to signal optional clearing of undo/redo stack at the end of a // 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 * 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. * @param rootName the root name for this data type manager (usually the program name). * @param originalDTM the original data type manager. */ public CompositeViewerDataTypeManager(String rootName, DataTypeManager originalDTM) { - this(rootName, originalDTM, null, null); + this(rootName, originalDTM, null, null, null); clearUndo(); transactionId = startTransaction("Composite Edit"); } @@ -80,11 +84,13 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager * structure being edited and its dependencies. * @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 changeCallback Callback will be invoked when any change is made to the view composite. * @param restoredCallback Callback will be invoked following any undo/redo. */ - public CompositeViewerDataTypeManager(String rootName, Composite originalComposite, - Callback restoredCallback) { - this(rootName, originalComposite.getDataTypeManager(), originalComposite, restoredCallback); + public CompositeViewerDataTypeManager(String rootName, T originalComposite, + Callback changeCallback, Callback 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 originalDTM the original datatype manager * @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. */ private CompositeViewerDataTypeManager(String rootName, DataTypeManager originalDTM, - Composite originalComposite, Callback restoredCallback) { + T originalComposite, Callback changeCallback, Callback restoredCallback) { super(rootName, originalDTM.getDataOrganization()); this.originalDTM = originalDTM; this.originalComposite = originalComposite; + this.changeCallback = changeCallback; this.restoredCallback = restoredCallback; int txId = startTransaction("Setup for Edit"); @@ -113,8 +121,9 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager clearUndo(); } - private Composite resolveViewComposite() { - return originalComposite != null ? (Composite) super.resolve(originalComposite, null) + @SuppressWarnings("unchecked") + private T resolveViewComposite() { + return originalComposite != null ? (T) super.resolve(originalComposite, 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. */ - public Composite getResolvedViewComposite() { + public T getResolvedViewComposite() { return viewComposite; } @@ -325,15 +334,24 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager } @Override - public void notifyRestored() { - super.notifyRestored(); - if (restoredCallback != null) { - restoredCallback.call(); + public void dataTypeChanged(DataType dt, boolean isAutoChange) { + super.dataTypeChanged(dt, isAutoChange); + if (dt == viewComposite) { + // Set dataTypeChanged which will trigger changeCallback when transaction fully comitted + dataTypeChanged = true; } } @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) { // 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 (flattenModCount != dbHandle.getModCount()) { @@ -351,6 +369,16 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager } flattenModCount = -1; } + + if (committed && dataTypeChanged && changeCallback != null) { + Swing.runLater(() -> changeCallback.call()); + } + + if (getTransactionCount() == 0) { + dataTypeChanged = false; + } + + return committed; } private void checkOrphansForRemoval(boolean cleanupIdMaps) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerModel.java index 009cab7a42..2f880213d6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeViewerModel.java @@ -27,11 +27,17 @@ import docking.widgets.fieldpanel.support.FieldSelection; import ghidra.program.database.data.DataTypeUtilities; import ghidra.program.model.data.*; import ghidra.util.*; +import ghidra.util.exception.AssertException; import ghidra.util.exception.DuplicateNameException; import ghidra.util.task.TaskMonitor; import utility.function.Callback; -abstract class CompositeViewerModel extends AbstractTableModel +/** + * {@link CompositeViewerModel} provides the base composite viewer/editor implementation + * + * @param Specific {@link Composite} type being managed + */ +abstract class CompositeViewerModel extends AbstractTableModel implements DataTypeManagerChangeListener { /** @@ -40,13 +46,13 @@ abstract class CompositeViewerModel extends AbstractTableModel */ protected boolean updatingSelection = false; - protected Composite originalComposite; + protected T originalComposite; protected DataTypePath originalDataTypePath; protected long originalCompositeId; protected DataTypeManager originalDTM; - protected Composite viewComposite; - protected CompositeViewerDataTypeManager viewDTM; + protected T viewComposite; + protected CompositeViewerDataTypeManager viewDTM; private List modelListeners = new ArrayList<>(); @@ -79,10 +85,11 @@ abstract class CompositeViewerModel extends AbstractTableModel protected int currentEditRow = -1; /** the current column for a field edit */ protected int currentEditColumn = -1; - protected CompositeEditorProvider provider; protected boolean showHexNumbers = false; - CompositeViewerModel(CompositeEditorProvider provider) { + protected final CompositeEditorProvider provider; + + CompositeViewerModel(CompositeEditorProvider provider) { this.provider = provider; selection = new FieldSelection(); adjustWidth(); @@ -165,7 +172,7 @@ abstract class CompositeViewerModel extends AbstractTableModel * * @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. @@ -276,8 +283,8 @@ abstract class CompositeViewerModel extends AbstractTableModel * @return the original composite being viewed or null if nothing is currently loaded in * the model. */ - protected Composite getOriginalComposite() { - Composite existingOriginal = getExistingOriginalComposite(); + protected T getOriginalComposite() { + T existingOriginal = getExistingOriginalComposite(); return existingOriginal != null ? existingOriginal : originalComposite; } @@ -292,14 +299,15 @@ abstract class CompositeViewerModel extends AbstractTableModel return getExistingOriginalComposite() != null; } - private Composite getExistingOriginalComposite() { + @SuppressWarnings("unchecked") + private T getExistingOriginalComposite() { long originalId = getCompositeID(); if (originalId != DataTypeManager.NULL_DATATYPE_ID && originalDataTypePath != null && originalDTM != null) { DataType dt = originalDTM.getDataType(originalId); if (dt instanceof Composite && DataTypeUtilities.isSameKindDataType(originalComposite, dt)) { - return (Composite) dt; + return (T) dt; } } return null; @@ -729,7 +737,10 @@ abstract class CompositeViewerModel extends AbstractTableModel @Override public void categoryRemoved(DataTypeManager dtm, CategoryPath path) { 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)) { String msg = "\"" + originalDataTypePath.getDataTypeName() + "\" had its category \"" + @@ -754,7 +765,10 @@ abstract class CompositeViewerModel extends AbstractTableModel @Override public void categoryRenamed(DataTypeManager dtm, CategoryPath oldPath, CategoryPath newPath) { 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)) { return; @@ -782,7 +796,10 @@ abstract class CompositeViewerModel extends AbstractTableModel @Override public void categoryMoved(DataTypeManager dtm, CategoryPath oldPath, CategoryPath newPath) { 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)) { 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 * on each listener. * - * @param the type of the listener + * @param the type of the listener * @param listeners the listeners * @param method the method to call */ - protected void notify(List listeners, Consumer method) { + protected void notify(List listeners, Consumer method) { swing(() -> { - for (T listener : listeners) { + for (L listener : listeners) { method.accept(listener); } }); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CycleGroupAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CycleGroupAction.java index 28206e6374..d9871f4478 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CycleGroupAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CycleGroupAction.java @@ -30,7 +30,7 @@ public class CycleGroupAction extends CompositeEditorTableAction { private final static String GROUP_NAME = DATA_ACTION_GROUP; private CycleGroup cycleGroup; - public CycleGroupAction(CompositeEditorProvider provider, CycleGroup cycleGroup) { + public CycleGroupAction(CompositeEditorProvider provider, CycleGroup cycleGroup) { super(provider, cycleGroup.getName()); setMenuBarData( diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DataTypeHelper.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DataTypeHelper.java index 74e6c4c0d1..3ceb5674a1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DataTypeHelper.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DataTypeHelper.java @@ -4,9 +4,9 @@ * 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. @@ -75,7 +75,8 @@ public class DataTypeHelper { * @throws UsrException if the specified data type can't be used at the * 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) throws InvalidDataTypeException, UsrException { @@ -98,7 +99,7 @@ public class DataTypeHelper { return newDt; } - static DataTypeInstance getSizedDataType(CompositeEditorProvider provider, DataType dt, + static DataTypeInstance getSizedDataType(CompositeEditorProvider provider, DataType dt, int defaultSize, int maxSize) throws InvalidDataTypeException { if (dt instanceof FactoryDataType) { throw new InvalidDataTypeException("Factory data types are not allowed."); @@ -137,7 +138,7 @@ public class DataTypeHelper { 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 { NumberInputDialog dtSizeDialog = new NumberInputDialog(dtName + " bytes", defaultSize, 1, maxBytes); @@ -149,7 +150,7 @@ public class DataTypeHelper { } int resultBytes = dtSizeDialog.getValue(); - CompositeEditorModel model = provider.getModel(); + CompositeEditorModel model = provider.getModel(); model.setLastNumBytes(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 * will be returned unchanged. If the user cancels from the size dialog, * then a null is returned. - * + * + * @param model The composite editor model * @param index the component index of where to add the data type. * @param dt the data type to add * @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 * prompted for a size. */ - public static DataTypeInstance getFixedLength(CompositeEditorModel model, int index, + public static DataTypeInstance getFixedLength(CompositeEditorModel model, int index, DataType dt, boolean useAlignedLength) { if (dt instanceof FactoryDataType) { 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); } - public static DataTypeInstance requestBytes(CompositeEditorModel model, DataType dt, + public static DataTypeInstance requestBytes(CompositeEditorModel model, DataType dt, int maxBytes) { - CompositeEditorProvider provider = model.getProvider(); + CompositeEditorProvider provider = model.getProvider(); DataType actualDt = dt; if (actualDt instanceof TypeDef) { actualDt = ((TypeDef) actualDt).getBaseDataType(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DeleteAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DeleteAction.java index 0868887482..6eefd0c9e6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DeleteAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DeleteAction.java @@ -36,7 +36,7 @@ public class DeleteAction extends CompositeEditorTableAction { private final static String[] popupPath = new String[] { "Delete" }; 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); setKeyBindingData(new KeyBindingData(KEY_STROKE)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DndTableCellRenderer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DndTableCellRenderer.java index 4e8f683111..986bc6c18b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DndTableCellRenderer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DndTableCellRenderer.java @@ -4,9 +4,9 @@ * 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. @@ -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. */ - public void selectRange(boolean inserting) { - this.inserting = inserting; + public void selectRange(boolean isInsert) { + this.inserting = isInsert; int tmpRow = rowForFeedback; rowForFeedback = -1; rangeMin = -1; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DuplicateAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DuplicateAction.java index 4fb3d12bf7..43b9bb5fa4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DuplicateAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DuplicateAction.java @@ -40,7 +40,7 @@ public class DuplicateAction extends CompositeEditorTableAction { private final static KeyStroke KEY_STROKE = 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); setDescription(DESCRIPTION); setKeyBindingData(new KeyBindingData(KEY_STROKE)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DuplicateMultipleAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DuplicateMultipleAction.java index e857455999..d7d49486df 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DuplicateMultipleAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/DuplicateMultipleAction.java @@ -44,7 +44,7 @@ public class DuplicateMultipleAction extends CompositeEditorTableAction { 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); setDescription(DESCRIPTION); setKeyBindingData(new KeyBindingData(keyStroke)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditBitFieldAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditBitFieldAction.java index a74e95daef..a884626c95 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditBitFieldAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditBitFieldAction.java @@ -25,7 +25,7 @@ public class EditBitFieldAction extends CompositeEditorTableAction { private final static String DESCRIPTION = "Edit an existing bitfield"; 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); setDescription(DESCRIPTION); if (!(model instanceof CompEditorModel)) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditComponentAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditComponentAction.java index 7b59836e42..f2d0eec3bd 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditComponentAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditComponentAction.java @@ -33,7 +33,7 @@ public class EditComponentAction extends CompositeEditorTableAction { private static String[] MENU_PATH = new String[] { ACTION_NAME }; private DataTypeManagerService dtmService; - public EditComponentAction(CompositeEditorProvider provider) { + public EditComponentAction(CompositeEditorProvider provider) { super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, MENU_PATH, null); this.dtmService = provider.dtmService; setDescription(DESCRIPTION); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditFieldAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditFieldAction.java index f907196753..573040e7ba 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditFieldAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditFieldAction.java @@ -37,7 +37,7 @@ public class EditFieldAction extends CompositeEditorTableAction { private static String[] POPUP_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); setDescription(DESCRIPTION); setKeyBindingData(new KeyBindingData(KEY_STROKE)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditorProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditorProvider.java index 74f1e32ef2..9b408efe6b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditorProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditorProvider.java @@ -4,9 +4,9 @@ * 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. @@ -16,7 +16,8 @@ package ghidra.app.plugin.core.compositeeditor; 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. @@ -42,8 +43,7 @@ public interface EditorProvider { public ComponentProvider getComponentProvider(); /** - * Get the datatype manager associated with this editor. - * @return the datatype manager associated with this editor + * {@return the edited datatype's original datatype manager.} */ public DataTypeManager getDataTypeManager(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/FavoritesAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/FavoritesAction.java index a07651bebc..0a9eafdd32 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/FavoritesAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/FavoritesAction.java @@ -35,7 +35,7 @@ public class FavoritesAction extends CompositeEditorTableAction { * @param provider the provider that owns this action * @param dt the favorite data type */ - public FavoritesAction(CompositeEditorProvider provider, DataType dt) { + public FavoritesAction(CompositeEditorProvider provider, DataType dt) { super(provider, dt.getDisplayName()); this.dataType = dt; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/FindReferencesToStructureFieldAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/FindReferencesToStructureFieldAction.java index 2b78f64499..44042d0832 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/FindReferencesToStructureFieldAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/FindReferencesToStructureFieldAction.java @@ -31,7 +31,7 @@ public class FindReferencesToStructureFieldAction extends CompositeEditorTableAc private final static String ACTION_NAME = "Find Uses of"; 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); setDescription(DESCRIPTION); setHelpLocation(new HelpLocation(HelpTopics.FIND_REFERENCES, "Data_Types")); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/HexNumbersAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/HexNumbersAction.java index 3e1a3f7815..b64539abd3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/HexNumbersAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/HexNumbersAction.java @@ -35,7 +35,7 @@ public class HexNumbersAction extends CompositeEditorTableAction implements Togg private static String[] PATH = new String[] { DESCRIPTION }; private boolean isSelected; - public HexNumbersAction(CompositeEditorProvider provider) { + public HexNumbersAction(CompositeEditorProvider provider) { super(provider, ACTION_NAME, GROUP_NAME, PATH, PATH, null); setDescription(DESCRIPTION); setSelected(model.isShowingNumbersInHex()); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/InsertUndefinedAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/InsertUndefinedAction.java index 53243b60d0..e0b580deeb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/InsertUndefinedAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/InsertUndefinedAction.java @@ -42,7 +42,7 @@ public class InsertUndefinedAction extends CompositeEditorTableAction { private final static KeyStroke KEY_STROKE = 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); setDescription(DESCRIPTION); setKeyBindingData(new KeyBindingData(KEY_STROKE)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/MoveDownAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/MoveDownAction.java index f4354baf3e..faa581e035 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/MoveDownAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/MoveDownAction.java @@ -41,7 +41,7 @@ public class MoveDownAction extends CompositeEditorTableAction { private final static KeyStroke KEY_STROKE = 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); setDescription(DESCRIPTION); setKeyBindingData(new KeyBindingData(KEY_STROKE)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/MoveUpAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/MoveUpAction.java index b17fd118df..488ead9d88 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/MoveUpAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/MoveUpAction.java @@ -41,7 +41,7 @@ public class MoveUpAction extends CompositeEditorTableAction { private final static KeyStroke KEY_STROKE = 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); setDescription(DESCRIPTION); setKeyBindingData(new KeyBindingData(KEY_STROKE)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/PointerAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/PointerAction.java index 6d5563ef9d..62e62ca124 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/PointerAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/PointerAction.java @@ -34,7 +34,7 @@ public class PointerAction extends CompositeEditorTableAction { private final static String DESCRIPTION = "Create a pointer(s) on the selection"; 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); setDescription(DESCRIPTION); setKeyBindingData(new KeyBindingData(KeyEvent.VK_P, 0)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/RedoChangeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/RedoChangeAction.java index 21990e6fff..0fd3cc6ba8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/RedoChangeAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/RedoChangeAction.java @@ -32,7 +32,7 @@ public class RedoChangeAction extends CompositeEditorTableAction { private final static Icon ICON = new GIcon("icon.redo"); 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); setKeyBindingData(new KeyBindingData("ctrl shift Z")); setDescription("Redo editor change"); @@ -43,8 +43,10 @@ public class RedoChangeAction extends CompositeEditorTableAction { if (!isEnabledForContext(context)) { return; } - CompositeViewerDataTypeManager viewDTM = model.getViewDataTypeManager(); + CompositeViewerDataTypeManager viewDTM = model.getViewDataTypeManager(); viewDTM.redo(); + + model.clearStatus(); } @Override @@ -52,7 +54,7 @@ public class RedoChangeAction extends CompositeEditorTableAction { if (hasIncompleteFieldEntry()) { return false; } - CompositeViewerDataTypeManager viewDTM = model.getViewDataTypeManager(); + CompositeViewerDataTypeManager viewDTM = model.getViewDataTypeManager(); boolean canRedo = viewDTM.canRedo(); setEnabled(canRedo); String description = DESCRIPTION + (canRedo ? (": " + viewDTM.getRedoName()) : ""); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/SearchControlPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/SearchControlPanel.java index e4dd8d4986..99e5dfe475 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/SearchControlPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/SearchControlPanel.java @@ -4,9 +4,9 @@ * 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. @@ -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 PREV_ICON = new GIcon("icon.plugin.composite.editor.search.previous"); - private CompositeEditorPanel editorPanel; + private CompositeEditorPanel editorPanel; private JTextField textField; private EmptyBorderButton searchNext; private EmptyBorderButton searchPrevious; - public SearchControlPanel(CompositeEditorPanel editorPanel) { + public SearchControlPanel(CompositeEditorPanel editorPanel) { this.editorPanel = editorPanel; setLayout(new BorderLayout()); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ShowComponentPathAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ShowComponentPathAction.java index 0e7ef8686d..81b50d7be6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ShowComponentPathAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ShowComponentPathAction.java @@ -32,7 +32,7 @@ public class ShowComponentPathAction extends CompositeEditorTableAction { private static String[] POPUP_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); setDescription(DESCRIPTION); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ShowDataTypeInTreeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ShowDataTypeInTreeAction.java index a524b99e9f..2e6ed2bed1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ShowDataTypeInTreeAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/ShowDataTypeInTreeAction.java @@ -35,7 +35,7 @@ public class ShowDataTypeInTreeAction extends CompositeEditorTableAction { private static final String TOOLBAR_GROUP = "4_COMPONENT_EDITOR_ACTION"; 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); setToolBarData(new ToolBarData(ICON, TOOLBAR_GROUP)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java index df8bf09d89..f3d316033a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java @@ -33,7 +33,7 @@ import ghidra.util.exception.*; import ghidra.util.task.TaskLauncher; import ghidra.util.task.TaskMonitor; -class StructureEditorModel extends CompEditorModel { +class StructureEditorModel extends CompEditorModel { private static final long serialVersionUID = 1L; private static final int OFFSET = 0; @@ -184,14 +184,13 @@ class StructureEditorModel extends CompEditorModel { if (rowIndex < 0 || rowIndex == numComponents) { return null; } - Structure viewStruct = (Structure) viewComposite; if (rowIndex > numComponents) { return null; } if (isShowingUndefinedBytes()) { return viewComposite.getComponent(rowIndex); } - DataTypeComponent[] definedComponents = viewStruct.getDefinedComponents(); + DataTypeComponent[] definedComponents = viewComposite.getDefinedComponents(); return definedComponents[rowIndex]; } @@ -215,8 +214,7 @@ class StructureEditorModel extends CompEditorModel { } viewDTM.withTransaction("Set Size", () -> { - Structure structure = (Structure) viewComposite; - structure.setLength(size); + viewComposite.setLength(size); }); notifyCompositeChanged(); } @@ -278,7 +276,7 @@ class StructureEditorModel extends CompEditorModel { } boolean isSelected = selection.containsEntirely(BigInteger.valueOf(indices[i])); int numBytes = comp.getLength(); - ((Structure) viewComposite).clearComponent(indices[i]); + viewComposite.clearComponent(indices[i]); // Adjust the selection due to the clear. adjustSelection(indices[i] + 1, numBytes - 1); @@ -291,7 +289,6 @@ class StructureEditorModel extends CompEditorModel { } } }); - componentEdited(); } @Override @@ -366,7 +363,6 @@ class StructureEditorModel extends CompEditorModel { // Ensure that last added component is selected to allow for repeated duplication setSelection(new int[] { index + multiple }); - componentEdited(); lastNumDuplicates = multiple; } @@ -485,7 +481,6 @@ class StructureEditorModel extends CompEditorModel { int newIndex = startRowIndex - 1; moved = shiftComponentsUp(startRowIndex, endRowIndex); if (moved) { - componentEdited(); FieldSelection tmpFieldSelection = new FieldSelection(); tmpFieldSelection.addRange(newIndex, newIndex + numSelected); setSelection(tmpFieldSelection); @@ -509,7 +504,6 @@ class StructureEditorModel extends CompEditorModel { int newIndex = startIndex + 1; moved = shiftComponentsDown(startIndex, endIndex); if (moved) { - componentEdited(); FieldSelection tmpFieldSelection = new FieldSelection(); tmpFieldSelection.addRange(newIndex, newIndex + numSelected); setSelection(tmpFieldSelection); @@ -865,7 +859,7 @@ class StructureEditorModel extends CompEditorModel { } else { BitFieldDataType bitfield = (BitFieldDataType) dataType; - dtc = ((Structure) viewComposite).insertBitField(rowIndex, length, + dtc = viewComposite.insertBitField(rowIndex, length, bitfield.getBitOffset(), bitfield.getBaseDataType(), bitfield.getDeclaredBitSize(), name, comment); } @@ -927,7 +921,7 @@ class StructureEditorModel extends CompEditorModel { if (!isPackingEnabled() && !isAtEnd(rowIndex)) { int origLen = getComponent(rowIndex).getLength(); dtc = viewDTM.withTransaction("Replace Component", () -> { - return ((Structure) viewComposite).replace(componentOrdinal, dataType, length, + return viewComposite.replace(componentOrdinal, dataType, length, name, comment); }); diffLen = origLen - dtc.getLength(); @@ -948,16 +942,15 @@ class StructureEditorModel extends CompEditorModel { } else { dtc = viewDTM.withTransaction("Replace Component", () -> { - Structure struct = (Structure) viewComposite; DataTypeComponent comp = getComponent(rowIndex); if (!isPackingEnabled()) { // We are at end with packing disabled - grow structure if needed int avail = comp.getLength() + getNumUndefinedBytesAfter(comp); 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); }); } @@ -1052,9 +1045,8 @@ class StructureEditorModel extends CompEditorModel { @Override protected void replaceOriginalComponents() { - Structure dt = (Structure) getOriginalComposite(); - if (dt != null) { - dt.replaceWith(viewComposite); + if (originalComposite != null) { + originalComposite.replaceWith(viewComposite); } else { throw new RuntimeException("ERROR: Couldn't replace structure components in " + @@ -1302,8 +1294,6 @@ class StructureEditorModel extends CompEditorModel { } viewDTM.withTransaction("Unpack Component", () -> { - Structure viewStruct = (Structure) viewComposite; - // Get the field name and comment before removing. String fieldName = currentComp.getFieldName(); String comment = currentComp.getComment(); @@ -1346,13 +1336,13 @@ class StructureEditorModel extends CompEditorModel { if (!isPackingEnabled()) { if (dtc.isBitFieldComponent()) { BitFieldDataType bitfield = (BitFieldDataType) dt; - viewStruct.insertBitFieldAt(currentOffset + dtc.getOffset(), + viewComposite.insertBitFieldAt(currentOffset + dtc.getOffset(), compLength, bitfield.getBitOffset(), bitfield.getBaseDataType(), bitfield.getDeclaredBitSize(), dtc.getFieldName(), dtc.getComment()); } else { - viewStruct.insertAtOffset(currentOffset + dtc.getOffset(), dt, + viewComposite.insertAtOffset(currentOffset + dtc.getOffset(), dt, compLength, dtc.getFieldName(), dtc.getComment()); } } @@ -1379,7 +1369,6 @@ class StructureEditorModel extends CompEditorModel { comp.setComment(comment); }); fixSelection(); - componentEdited(); selectionChanged(); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModelListener.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModelListener.java deleted file mode 100644 index a55a9e5797..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModelListener.java +++ /dev/null @@ -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); - -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorPanel.java new file mode 100644 index 0000000000..54dfa9366b --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorPanel.java @@ -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 { + + 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 }); + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorProvider.java index 63f1e25433..d9b745d4f1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorProvider.java @@ -27,7 +27,8 @@ import ghidra.util.Msg; /** * Editor for a Structure Data Type. */ -public class StructureEditorProvider extends CompositeEditorProvider { +public class StructureEditorProvider + extends CompositeEditorProvider { private BitFieldEditorDialog bitFieldEditor; @@ -41,7 +42,7 @@ public class StructureEditorProvider extends CompositeEditorProvider { editorModel = new StructureEditorModel(this, showHexNumbers); editorModel.load(structureDataType); initializeActions(); - editorPanel = new CompEditorPanel((StructureEditorModel) editorModel, this); + editorPanel = new StructureEditorPanel((StructureEditorModel) editorModel, this); plugin.getTool().addComponentProvider(this, true); updateTitle(); addActionsToTool(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UndoChangeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UndoChangeAction.java index aa44d786ed..9243b00440 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UndoChangeAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UndoChangeAction.java @@ -32,7 +32,7 @@ public class UndoChangeAction extends CompositeEditorTableAction { private final static Icon ICON = new GIcon("icon.undo"); 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); setKeyBindingData(new KeyBindingData("ctrl Z")); setDescription(DESCRIPTION); @@ -43,8 +43,10 @@ public class UndoChangeAction extends CompositeEditorTableAction { if (!isEnabledForContext(context)) { return; } - CompositeViewerDataTypeManager viewDTM = model.getViewDataTypeManager(); + CompositeViewerDataTypeManager viewDTM = model.getViewDataTypeManager(); viewDTM.undo(); + + model.clearStatus(); } @Override @@ -52,7 +54,7 @@ public class UndoChangeAction extends CompositeEditorTableAction { if (hasIncompleteFieldEntry()) { return false; } - CompositeViewerDataTypeManager viewDTM = model.getViewDataTypeManager(); + CompositeViewerDataTypeManager viewDTM = model.getViewDataTypeManager(); boolean canUndo = viewDTM.canUndo(); setEnabled(canUndo); String description = DESCRIPTION + (canUndo ? (": " + viewDTM.getUndoName()) : ""); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorModel.java index 86898c9551..4ccd5e79ca 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorModel.java @@ -48,7 +48,7 @@ import ghidra.util.exception.CancelledException; import ghidra.util.exception.UsrException; import ghidra.util.task.TaskMonitor; -class UnionEditorModel extends CompEditorModel { +class UnionEditorModel extends CompEditorModel { private static final long serialVersionUID = 1L; private static final int LENGTH = 0; @@ -465,7 +465,6 @@ class UnionEditorModel extends CompEditorModel { selection.addRange(rowIndex, rowIndex + 1); fixSelection(); } - componentEdited(); return dtc; } catch (IllegalArgumentException exc) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorPanel.java index 32c5925f7f..5400bae823 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorPanel.java @@ -4,9 +4,9 @@ * 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. @@ -17,9 +17,15 @@ package ghidra.app.plugin.core.compositeeditor; 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 { + + public UnionEditorPanel(UnionEditorModel model, + CompositeEditorProvider provider) { super(model, provider); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorProvider.java index a4c6edd7e0..3b070953bd 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorProvider.java @@ -4,9 +4,9 @@ * 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. @@ -24,7 +24,7 @@ import ghidra.program.model.data.Union; /** * Editor for a Union Data Type. */ -public class UnionEditorProvider extends CompositeEditorProvider { +public class UnionEditorProvider extends CompositeEditorProvider { protected static final Icon UNION_EDITOR_ICON = new GIcon("icon.plugin.composite.editor.provider.union"); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/BiDirectionDataType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/BiDirectionDataType.java index 462d812d07..9294843b53 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/BiDirectionDataType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/BiDirectionDataType.java @@ -23,8 +23,10 @@ import ghidra.program.model.data.*; import ghidra.util.exception.AssertException; /** - * BiDirectionDataType is a special structure data type that allows both positive and negative - * offset values. + * {@link BiDirectionDataType} is a special structure data type that allows both positive and + * negative offset values. + *

+ * NOTE: This special purpose datatype does not support resolving with a {@link DataTypeManager} */ public abstract class BiDirectionDataType extends StructureDataType implements BiDirectionStructure { @@ -36,8 +38,12 @@ public abstract class BiDirectionDataType extends StructureDataType protected int splitOffset; // division offset between negative/positive halves /** - * @param name - * @param length + * Construct {@link BiDirectionDataType} + * @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, int splitOffset, DataTypeManager dtm) { @@ -47,14 +53,6 @@ public abstract class BiDirectionDataType extends StructureDataType 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 protected DataType validateDataType(DataType dataType) { if (DataTypeComponent.usesZeroLengthComponent(dataType)) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/BiDirectionStructure.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/BiDirectionStructure.java index 72770b8aee..b5b62cc6a5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/BiDirectionStructure.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/BiDirectionStructure.java @@ -1,13 +1,12 @@ /* ### * 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. @@ -35,7 +34,7 @@ public interface BiDirectionStructure extends Structure { /** * Get the component offset which represents the division point * between the positive and negative halves of the structure. - * @return + * @return split offset */ public abstract int getSplitOffset(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorManager.java index b4910e1387..ffb8c99676 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorManager.java @@ -4,9 +4,9 @@ * 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. @@ -15,12 +15,13 @@ */ package ghidra.app.plugin.core.stackeditor; +import java.util.*; + import ghidra.app.plugin.core.compositeeditor.EditorListener; import ghidra.app.plugin.core.compositeeditor.EditorProvider; import ghidra.framework.model.DomainObject; -import ghidra.program.model.listing.*; - -import java.util.*; +import ghidra.program.model.listing.Function; +import ghidra.program.model.listing.Program; /** * Manages edit sessions of function stack frames for multiple open programs. @@ -33,7 +34,6 @@ public class StackEditorManager implements EditorListener { /** * Constructor * @param plugin the plugin that owns this manager. - * @param program the active program */ public StackEditorManager(StackEditorManagerPlugin plugin) { this.plugin = plugin; @@ -51,6 +51,7 @@ public class StackEditorManager implements EditorListener { /** * 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) { StackEditorProvider editor = editorMap.get(function); @@ -67,28 +68,12 @@ public class StackEditorManager implements EditorListener { /** * Subclass should override this method if it is interested in * close program events. + * @param closedProgram program which was closed */ protected void programClosed(Program 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 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. * @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. + * @param program program whose editors should close */ void dismissEditors(Program program) { List list = new ArrayList(editorMap.keySet()); @@ -138,14 +124,12 @@ public class StackEditorManager implements EditorListener { return true; } + @Override public void closed(EditorProvider editor) { StackEditorProvider stackEditorProvider = (StackEditorProvider) editor; editorMap.remove(stackEditorProvider.getFunction()); } - /* (non-Javadoc) - * @see ghidra.framework.plugintool.Plugin#canCloseDomainObject(DomainObject) - */ protected boolean canCloseDomainObject(DomainObject dObj) { if (!(dObj instanceof Program)) { return true; @@ -153,9 +137,6 @@ public class StackEditorManager implements EditorListener { return checkEditors((Program) dObj); } - /* (non-Javadoc) - * @see ghidra.framework.plugintool.Plugin#canClose() - */ protected boolean canClose() { return checkEditors(null); } @@ -167,14 +148,4 @@ public class StackEditorManager implements EditorListener { 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()); - } - } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorManagerPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorManagerPlugin.java index 0b4a6dc8cc..e45b7ca005 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorManagerPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorManagerPlugin.java @@ -4,9 +4,9 @@ * 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. @@ -18,7 +18,6 @@ package ghidra.app.plugin.core.stackeditor; import ghidra.app.CorePluginPackage; import ghidra.app.events.ProgramClosedPluginEvent; import ghidra.app.plugin.PluginCategoryNames; -import ghidra.app.plugin.core.compositeeditor.CompositeEditorProvider; import ghidra.app.services.DataTypeManagerService; import ghidra.framework.model.DomainObject; import ghidra.framework.options.*; @@ -129,10 +128,6 @@ public class StackEditorManagerPlugin extends Plugin return editorMgr.canCloseDomainObject(dObj); } - CompositeEditorProvider getProvider(Program pgm, String functionName) { - return editorMgr.getProvider(pgm, functionName); - } - public void optionsChanged(ToolOptions options, String optionName, Object oldValue, Object newValue) { setOptions(options); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java index 71607a065e..6f8f4ae1f2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java @@ -45,7 +45,7 @@ import ghidra.util.*; import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; -public class StackEditorModel extends CompositeEditorModel { +public class StackEditorModel extends CompositeEditorModel { private static final long serialVersionUID = 1L; 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 StackFrame originalStack; - private DataTypeManager dtm; private boolean stackChangedExternally; @@ -68,7 +67,6 @@ public class StackEditorModel extends CompositeEditorModel { columnWidths = new int[] { 40, 40, 100, 100, 150 }; columnOffsets = new int[headers.length]; adjustOffsets(); - dtm = provider.getProgram().getDataTypeManager(); Plugin plugin = provider.getPlugin(); if (plugin instanceof StackEditorOptionManager) { showHexNumbers = ((StackEditorOptionManager) plugin).showStackNumbersInHex(); @@ -99,19 +97,20 @@ public class StackEditorModel extends CompositeEditorModel { void load(Function function) { originalStack = function.getStackFrame(); + ProgramBasedDataTypeManager dtm = function.getProgram().getDataTypeManager(); StackFrameDataType stackFrameDataType = new StackFrameDataType(originalStack, dtm); stackFrameDataType.setCategoryPath(dtm.getRootCategory().getCategoryPath()); load(stackFrameDataType); } @Override - public void load(Composite dataType) { + public void load(StackFrameDataType dataType) { stackChangedExternally(false); super.load(dataType); } @Override - protected void createViewCompositeFromOriginalComposite(Composite original) { + protected void createViewCompositeFromOriginalComposite(StackFrameDataType original) { if (viewDTM != null) { viewDTM.close(); @@ -119,10 +118,10 @@ public class StackEditorModel extends CompositeEditorModel { } // 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 - viewComposite = (Composite) original.copy(viewDTM); + // NOTE: StackFrameDataType cannot be resolved but all of its element datatypes must be + viewComposite = original.copy(viewDTM); } @Override @@ -130,16 +129,12 @@ public class StackEditorModel extends CompositeEditorModel { throw new UnsupportedOperationException("undo/redo not supported"); } - StackFrameDataType getViewComposite() { - return (StackFrameDataType) viewComposite; - } - @Override public boolean updateAndCheckChangeState() { if (originalIsChanging) { return false; } - StackFrameDataType sfdt = (StackFrameDataType) viewComposite; + StackFrameDataType sfdt = viewComposite; int editReturnAddressOffset = sfdt.getReturnAddressOffset(); int editLocalSize = sfdt.getLocalSize(); int editParamOffset = sfdt.getParameterOffset(); @@ -215,7 +210,7 @@ public class StackEditorModel extends CompositeEditorModel { return DataTypeInstance.getDataTypeInstance(dt, (dtLen > 0) ? dtLen : element.getLength(), usesAlignedLengthComponents()); case NAME: - String fieldName = getFieldNameAtRow(rowIndex, (StackFrameDataType) viewComposite); + String fieldName = getFieldNameAtRow(rowIndex, viewComposite); if (fieldName == null) { fieldName = ""; } @@ -265,7 +260,7 @@ public class StackEditorModel extends CompositeEditorModel { if (modelColumnIndex == OFFSET) { int svOffset = Integer.decode((String) aValue).intValue(); DataTypeComponent dtc = - ((StackFrameDataType) viewComposite).getComponentAt(svOffset); + (viewComposite).getComponentAt(svOffset); offsetSelection = new OffsetPairs(); offsetSelection.addPair(svOffset, dtc.getEndOffset()); } @@ -327,7 +322,7 @@ public class StackEditorModel extends CompositeEditorModel { public void validateComponentOffset(int index, String offset) throws UsrException { try { int newOffset = Integer.decode(offset).intValue(); - StackFrameDataType sfdt = (StackFrameDataType) viewComposite; + StackFrameDataType sfdt = viewComposite; if ((newOffset < sfdt.getMinOffset()) || (newOffset > sfdt.getMaxOffset())) { throw new UsrException(offset + " is not an offset in this stack frame."); } @@ -391,15 +386,13 @@ public class StackEditorModel extends CompositeEditorModel { if (offset == svOffset) { return; } - DataTypeComponent newElement = - ((StackFrameDataType) viewComposite).setOffset(rowIndex, svOffset); + DataTypeComponent newElement = viewComposite.setOffset(rowIndex, svOffset); setSelection(new int[] { newElement.getOrdinal() }); notifyCompositeChanged(); } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { - StackFrameDataType stackDt = (StackFrameDataType) viewComposite; if (getNumSelectedRows() > 1) { return false; } @@ -412,11 +405,11 @@ public class StackEditorModel extends CompositeEditorModel { if (columnIndex < 0 || columnIndex >= getColumnCount()) { return false; } - DataTypeComponent dtc = stackDt.getComponent(rowIndex); + DataTypeComponent dtc = viewComposite.getComponent(rowIndex); if (dtc == null) { return false; } - boolean notDefined = (stackDt.getDefinedComponentAtOrdinal(rowIndex) == null); + boolean notDefined = (viewComposite.getDefinedComponentAtOrdinal(rowIndex) == null); return !(notDefined && (columnIndex == OFFSET)); } @@ -424,11 +417,11 @@ public class StackEditorModel extends CompositeEditorModel { if (ordinal < 0 || ordinal >= viewComposite.getNumComponents()) { return false; } - return (((StackFrameDataType) viewComposite).getDefinedComponentAtOrdinal(ordinal) != null); + return viewComposite.getDefinedComponentAtOrdinal(ordinal) != null; } boolean hasVariableAtOffset(int offset) { - return (((StackFrameDataType) viewComposite).getDefinedComponentAtOffset(offset) != null); + return viewComposite.getDefinedComponentAtOffset(offset) != null; } StackFrame getOriginalStack() { @@ -436,7 +429,7 @@ public class StackEditorModel extends CompositeEditorModel { } StackFrameDataType getEditorStack() { - return (StackFrameDataType) viewComposite; + return viewComposite; } @Override @@ -461,8 +454,7 @@ public class StackEditorModel extends CompositeEditorModel { endOffset = getComponent(range.getEnd().getIndex().intValue()).getOffset(); } else { - StackFrameDataType stf = (StackFrameDataType) viewComposite; - endOffset = stf.getPositiveLength() + stf.getParameterOffset(); + endOffset = viewComposite.getPositiveLength() + viewComposite.getParameterOffset(); } offsets.addPair(startOffset, endOffset); } @@ -475,8 +467,8 @@ public class StackEditorModel extends CompositeEditorModel { private void setRelOffsetSelection(OffsetPairs offsets) { FieldSelection newSelection = new FieldSelection(); int num = offsets.getNumPairs(); - int min = ((StackFrameDataType) viewComposite).getMinOffset(); - int max = ((StackFrameDataType) viewComposite).getMaxOffset(); + int min = viewComposite.getMinOffset(); + int max = viewComposite.getMaxOffset(); for (int i = 0; i < num; i++) { XYPair pair = offsets.getPair(i); 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 y = (pair.y > max) ? max + 1 : pair.y; - DataTypeComponent startDtc = ((StackFrameDataType) viewComposite).getComponentAt(x); - DataTypeComponent endDtc = ((StackFrameDataType) viewComposite).getComponentAt(y - 1); + DataTypeComponent startDtc = viewComposite.getComponentAt(x); + DataTypeComponent endDtc = viewComposite.getComponentAt(y - 1); if (startDtc == null || endDtc == null) { return; } @@ -499,7 +491,7 @@ public class StackEditorModel extends CompositeEditorModel { } } else { - endIndex = ((StackFrameDataType) viewComposite).getNumComponents(); + endIndex = viewComposite.getNumComponents(); } newSelection.addRange(startIndex, endIndex); } @@ -547,7 +539,7 @@ public class StackEditorModel extends CompositeEditorModel { throw new UsrException( "Local size cannot exceed 0x" + Integer.toHexString(MAX_LOCAL_SIZE) + "."); } - ((StackFrameDataType) viewComposite).setLocalSize(size); + viewComposite.setLocalSize(size); notifyCompositeChanged(); } @@ -559,28 +551,28 @@ public class StackEditorModel extends CompositeEditorModel { throw new UsrException( "Parameter size cannot exceed 0x" + Integer.toHexString(MAX_PARAM_SIZE) + "."); } - ((StackFrameDataType) viewComposite).setParameterSize(size); + viewComposite.setParameterSize(size); notifyCompositeChanged(); } int getFrameSize() { - return ((StackFrameDataType) viewComposite).getFrameSize(); + return viewComposite.getFrameSize(); } int getLocalSize() { - return ((StackFrameDataType) viewComposite).getLocalSize(); + return viewComposite.getLocalSize(); } int getParameterSize() { - return ((StackFrameDataType) viewComposite).getParameterSize(); + return viewComposite.getParameterSize(); } int getParameterOffset() { - return ((StackFrameDataType) viewComposite).getParameterOffset(); + return viewComposite.getParameterOffset(); } int getReturnAddressOffset() { - return ((StackFrameDataType) viewComposite).getReturnAddressOffset(); + return viewComposite.getReturnAddressOffset(); } @Override @@ -591,7 +583,7 @@ public class StackEditorModel extends CompositeEditorModel { @Override public int getMaxReplaceLength(int currentIndex) { int offset = viewComposite.getComponent(currentIndex).getOffset(); - return ((StackFrameDataType) viewComposite).getMaxLength(offset); + return viewComposite.getMaxLength(offset); } @Override @@ -653,7 +645,7 @@ public class StackEditorModel extends CompositeEditorModel { // return false; // } // } - int maxBytes = ((StackFrameDataType) viewComposite).getMaxLength(offset); + int maxBytes = viewComposite.getMaxLength(offset); if (newLength > maxBytes) { return false; } @@ -674,7 +666,7 @@ public class StackEditorModel extends CompositeEditorModel { if (index < 0 || index >= viewComposite.getNumComponents()) { return false; } - return (((StackFrameDataType) viewComposite).getDefinedComponentAtOrdinal(index) != null); + return viewComposite.getDefinedComponentAtOrdinal(index) != null; } @Override @@ -730,7 +722,7 @@ public class StackEditorModel extends CompositeEditorModel { return false; } int offset = getComponent(currentIndex).getOffset(); - int maxBytes = ((StackFrameDataType) viewComposite).getMaxLength(offset); + int maxBytes = viewComposite.getMaxLength(offset); if (dataType.getLength() > maxBytes) { return false; } @@ -738,8 +730,7 @@ public class StackEditorModel extends CompositeEditorModel { } private void adjustComponents(DataType dataType) { - StackFrameDataType stackDt = (StackFrameDataType) viewComposite; - DataTypeComponent[] comps = stackDt.getDefinedComponents(); + DataTypeComponent[] comps = viewComposite.getDefinedComponents(); String msg = ""; for (DataTypeComponent component : comps) { DataType compDt = component.getDataType(); @@ -749,7 +740,8 @@ public class StackEditorModel extends CompositeEditorModel { len = component.getLength(); } try { - stackDt.replace(component.getOrdinal(), compDt, len, component.getFieldName(), + viewComposite.replace(component.getOrdinal(), compDt, len, + component.getFieldName(), component.getComment()); } catch (IllegalArgumentException e) { @@ -765,8 +757,7 @@ public class StackEditorModel extends CompositeEditorModel { } private void replaceComponents(DataType oldDataType, DataType newDataType) { - StackFrameDataType stackDt = (StackFrameDataType) viewComposite; - DataTypeComponent[] comps = stackDt.getDefinedComponents(); + DataTypeComponent[] comps = viewComposite.getDefinedComponents(); String msg = ""; for (DataTypeComponent component : comps) { DataType compDt = component.getDataType(); @@ -776,7 +767,7 @@ public class StackEditorModel extends CompositeEditorModel { len = component.getLength(); } try { - stackDt.replace(component.getOrdinal(), newDataType, len, + viewComposite.replace(component.getOrdinal(), newDataType, len, component.getFieldName(), component.getComment()); } catch (IllegalArgumentException e) { @@ -795,7 +786,7 @@ public class StackEditorModel extends CompositeEditorModel { public void setComponentDataTypeInstance(int index, DataType dt, int length) throws UsrException { checkIsAllowableDataType(dt); - ((StackFrameDataType) viewComposite).setDataType(index, dt, length); + viewComposite.setDataType(index, dt, length); } @Override @@ -815,7 +806,7 @@ public class StackEditorModel extends CompositeEditorModel { // prevent user names that are default values, unless the value is the original name String nameInEditor = (String) getValueAt(rowIndex, NAME); - StackFrameDataType stackFrameDataType = ((StackFrameDataType) viewComposite); + StackFrameDataType stackFrameDataType = viewComposite; if (stackFrameDataType.isDefaultName(newName) && !isOriginalFieldName(newName, rowIndex)) { if (Objects.equals(nameInEditor, newName)) { return false; // same as current name in the table; do nothing @@ -841,7 +832,7 @@ public class StackEditorModel extends CompositeEditorModel { @Override public boolean setComponentComment(int currentIndex, String comment) { - if (((StackFrameDataType) viewComposite).setComment(currentIndex, comment)) { + if (viewComposite.setComment(currentIndex, comment)) { updateAndCheckChangeState(); fireTableRowsUpdated(currentIndex, currentIndex); componentDataChanged(); @@ -973,7 +964,7 @@ public class StackEditorModel extends CompositeEditorModel { for (Variable sv : newVars) { Variable newSv = null; try { - DataType dt = dtm.resolve(sv.getDataType(), null); + DataType dt = originalDTM.resolve(sv.getDataType(), null); 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 if (var != null && var.getStackOffset() == sv.getStackOffset() && @@ -1017,7 +1008,7 @@ public class StackEditorModel extends CompositeEditorModel { newSv.setComment(comment); } } - load(new StackFrameDataType(original, viewDTM)); + load(new StackFrameDataType(original, originalDTM)); clearStatus(); return true; } @@ -1135,8 +1126,7 @@ public class StackEditorModel extends CompositeEditorModel { setStatus("Can only create arrays on a defined stack variable.", true); return 0; } - DataTypeComponent dtc = - ((StackFrameDataType) viewComposite).getDefinedComponentAtOrdinal(index); + DataTypeComponent dtc = viewComposite.getDefinedComponentAtOrdinal(index); if (dtc == null) { setStatus("Can only create arrays on a defined stack variable.", true); return 0; @@ -1179,12 +1169,7 @@ public class StackEditorModel extends CompositeEditorModel { } } if (reload) { - - StackFrame stack = function.getStackFrame(); - StackFrameDataType newSfdt = - new StackFrameDataType(stack, function.getProgram().getDataTypeManager()); - - load(newSfdt); // reload the stack model based on current stack frame + load(function); } else { refresh(); @@ -1193,19 +1178,26 @@ public class StackEditorModel extends CompositeEditorModel { @Override public void dataTypeChanged(DataTypeManager dataTypeManager, DataTypePath path) { - if (isLoaded()) { - DataType dataType = dataTypeManager.getDataType(path); - OffsetPairs offsetSelection = getRelOffsetSelection(); - adjustComponents(dataType); - fireTableDataChanged(); - componentDataChanged(); - setRelOffsetSelection(offsetSelection); + if (dataTypeManager != originalDTM) { + throw new AssertException("Listener only supports original DTM"); } + if (!isLoaded()) { + return; + } + DataType dataType = dataTypeManager.getDataType(path); + OffsetPairs offsetSelection = getRelOffsetSelection(); + adjustComponents(dataType); + fireTableDataChanged(); + componentDataChanged(); + setRelOffsetSelection(offsetSelection); } @Override public void dataTypeMoved(DataTypeManager dataTypeManager, DataTypePath oldPath, DataTypePath newPath) { + if (dataTypeManager != originalDTM) { + throw new AssertException("Listener only supports original DTM"); + } if (!isLoaded()) { return; } @@ -1219,61 +1211,63 @@ public class StackEditorModel extends CompositeEditorModel { @Override public void dataTypeRemoved(DataTypeManager dataTypeManager, DataTypePath path) { - if (isLoaded()) { - OffsetPairs offsetSelection = getRelOffsetSelection(); - DataType dataType = dataTypeManager.getDataType(path); - replaceComponents(dataType, DataType.DEFAULT); - fireTableDataChanged(); - componentDataChanged(); - setRelOffsetSelection(offsetSelection); + if (dataTypeManager != originalDTM) { + throw new AssertException("Listener only supports original DTM"); } + if (!isLoaded()) { + return; + } + OffsetPairs offsetSelection = getRelOffsetSelection(); + DataType dataType = dataTypeManager.getDataType(path); + replaceComponents(dataType, DataType.DEFAULT); + fireTableDataChanged(); + componentDataChanged(); + setRelOffsetSelection(offsetSelection); } @Override public void dataTypeRenamed(DataTypeManager dataTypeManager, DataTypePath oldPath, DataTypePath newPath) { - if (isLoaded()) { - DataTypeManager originalDataTypeManager = getOriginalDataTypeManager(); - 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 (dataTypeManager != originalDTM) { + throw new AssertException("Listener only supports original DTM"); } + 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 public void dataTypeReplaced(DataTypeManager dataTypeManager, DataTypePath oldPath, DataTypePath newPath, DataType newDataType) { - if (isLoaded()) { - DataType oldDataType = viewDTM.getDataType(oldPath); - OffsetPairs offsetSelection = getRelOffsetSelection(); - replaceComponents(oldDataType, newDataType); - fireTableDataChanged(); - componentDataChanged(); - setRelOffsetSelection(offsetSelection); + if (dataTypeManager != originalDTM) { + throw new AssertException("Listener only supports original DTM"); } + 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 protected StackFrameDataType getOriginalComposite() { - return (StackFrameDataType) originalComposite; + return originalComposite; } @Override @@ -1305,8 +1299,7 @@ public class StackEditorModel extends CompositeEditorModel { } private void refreshComponents() { - StackFrameDataType stackDt = (StackFrameDataType) viewComposite; - DataTypeComponent[] comps = stackDt.getDefinedComponents(); + DataTypeComponent[] comps = viewComposite.getDefinedComponents(); for (int i = comps.length - 1; i >= 0; i--) { DataTypeComponent component = comps[i]; DataType compDt = component.getDataType(); @@ -1326,7 +1319,7 @@ public class StackEditorModel extends CompositeEditorModel { @Override protected void clearComponents(int[] rows) { for (int i = rows.length - 1; i >= 0; i--) { - ((StackFrameDataType) viewComposite).clearComponent(rows[i]); + viewComposite.clearComponent(rows[i]); } notifyCompositeChanged(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorPanel.java index b575d8615f..b85c0c5549 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorPanel.java @@ -28,7 +28,7 @@ import ghidra.util.exception.UsrException; /** * Panel for editing a function stack. */ -public class StackEditorPanel extends CompositeEditorPanel { +public class StackEditorPanel extends CompositeEditorPanel { private JTextField frameSizeField; private JTextField localSizeField; @@ -42,7 +42,7 @@ public class StackEditorPanel extends CompositeEditorPanel { } private StackEditorModel getStackModel() { - return (StackEditorModel) model; + return model; } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorProvider.java index 9ee2973bfd..d097032cab 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorProvider.java @@ -37,7 +37,9 @@ import ghidra.util.Msg; /** * Editor for a Function Stack. */ -public class StackEditorProvider extends CompositeEditorProvider implements DomainObjectListener { +public class StackEditorProvider + extends CompositeEditorProvider + implements DomainObjectListener { private Program program; private Function function; @@ -136,7 +138,7 @@ public class StackEditorProvider extends CompositeEditorProvider implements Doma } @Override - protected CompositeEditorModel getModel() { + protected StackEditorModel getModel() { return stackModel; } @@ -147,7 +149,7 @@ public class StackEditorProvider extends CompositeEditorProvider implements Doma private void refreshName() { StackFrameDataType origDt = stackModel.getOriginalComposite(); - StackFrameDataType viewDt = stackModel.getViewComposite(); + StackFrameDataType viewDt = stackModel.getEditorStack(); String oldName = origDt.getName(); String newName = function.getName(); if (oldName.equals(newName)) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackFrameDataType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackFrameDataType.java index 556472f61e..4608884402 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackFrameDataType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackFrameDataType.java @@ -4,9 +4,9 @@ * 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. @@ -34,7 +34,6 @@ import ghidra.util.exception.InvalidInputException; */ public class StackFrameDataType extends BiDirectionDataType { - private static final long serialVersionUID = 1L; static String DUMMY_FUNCTION_NAME = "StackWithoutFunction"; private static final String UNKNOWN_PREFIX = "unknown_"; StackFrame stack; @@ -44,8 +43,10 @@ public class StackFrameDataType extends BiDirectionDataType { /** * 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) { super( @@ -57,12 +58,14 @@ public class StackFrameDataType extends BiDirectionDataType { /** * 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) { - super(stackDt.getCategoryPath(), stackDt.getName(), stackDt.getNegativeLength(), - stackDt.getPositiveLength(), stackDt.splitOffset, dtm); + super(stackDt.getName(), stackDt.getNegativeLength(), stackDt.getPositiveLength(), + stackDt.splitOffset, dtm); setDescription(stackDt.getDescription()); this.function = stackDt.function; this.growsNegative = stackDt.growsNegative; @@ -156,7 +159,7 @@ public class StackFrameDataType extends BiDirectionDataType { } @Override - public DataType copy(DataTypeManager dtm) { + public StackFrameDataType copy(DataTypeManager dtm) { return new StackFrameDataType(this, dtm); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackPieceDataType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackPieceDataType.java index 0580f540a1..304e6a8d1c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackPieceDataType.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackPieceDataType.java @@ -4,9 +4,9 @@ * 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. @@ -105,18 +105,22 @@ public class StackPieceDataType extends DataTypeImpl { @Override public void dataTypeSizeChanged(DataType dt) { + // ignore } @Override public void dataTypeDeleted(DataType dt) { + // ignore } @Override public void dataTypeReplaced(DataType oldDt, DataType newDt) { + // ignore } @Override public void dataTypeNameChanged(DataType dt, String oldName) { + // ignore } @Override diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/AbstractEditorTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/AbstractEditorTest.java index f9ca443082..59563ba79e 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/AbstractEditorTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/AbstractEditorTest.java @@ -55,8 +55,8 @@ import utilities.util.reflection.ReflectionUtilities; public abstract class AbstractEditorTest extends AbstractGhidraHeadedIntegrationTest { protected String languageName; protected String compilerSpecID; - protected CompositeEditorProvider provider; - protected CompositeEditorModel model; + protected CompositeEditorProvider provider; + protected CompositeEditorModel model; protected TestEnv env; protected ProgramBuilder builder; 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); this.provider = newProvider; runSwing(() -> removeTableCellEditorsFocusLostListener()); @@ -393,12 +393,12 @@ public abstract class AbstractEditorTest extends AbstractGhidraHeadedIntegration return (dtc != null) ? dtc.getComment() : null; } - protected CompositeEditorPanel getPanel() { - return (CompositeEditorPanel) provider.getComponent(); + protected CompositeEditorPanel getPanel() { + return provider.getComponent(); } protected JTable getTable() { - return ((CompositeEditorPanel) provider.getComponent()).table; + return provider.getComponent().table; } protected Window getWindow() { @@ -789,37 +789,72 @@ public abstract class AbstractEditorTest extends AbstractGhidraHeadedIntegration } 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() { - 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) { - assertEquals(PackingType.EXPLICIT, ((CompEditorModel) model).getPackingType()); - assertEquals(pack, ((CompEditorModel) model).getExplicitPackingValue()); + if (model instanceof CompEditorModel compModel) { + assertEquals(PackingType.EXPLICIT, compModel.getPackingType()); + assertEquals(pack, compModel.getExplicitPackingValue()); + } + else { + fail("Model does not support packing concept"); + } } 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() { - 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) { - assertEquals(AlignmentType.EXPLICIT, ((CompEditorModel) model).getAlignmentType()); - assertEquals(alignment, ((CompEditorModel) model).getExplicitMinimumAlignment()); + if (model instanceof CompEditorModel compModel) { + assertEquals(AlignmentType.EXPLICIT, compModel.getAlignmentType()); + assertEquals(alignment, compModel.getExplicitMinimumAlignment()); + } + else { + fail("Model does not support alignment concept"); + } } 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) { - assertEquals(value, ((CompEditorModel) model).getLength()); + assertEquals(value, model.getLength()); } protected void setOptions(String optionName, boolean b) { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorAlignmentTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorAlignmentTest.java index 40f71402dc..36b7a07067 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorAlignmentTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorAlignmentTest.java @@ -195,7 +195,7 @@ public class StructureEditorAlignmentTest extends AbstractStructureEditorTest { public void testByValueAlignedStructure() throws Exception { init(emptyStructure, pgmRootCat, false); - CompEditorPanel editorPanel = (CompEditorPanel) getPanel(); + StructureEditorPanel editorPanel = (StructureEditorPanel) getPanel(); DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1); addDataType(new ByteDataType()); @@ -268,7 +268,7 @@ public class StructureEditorAlignmentTest extends AbstractStructureEditorTest { emptyStructure.add(arrayDt); init(emptyStructure, pgmRootCat, false); - CompEditorPanel editorPanel = (CompEditorPanel) getPanel(); + StructureEditorPanel editorPanel = (StructureEditorPanel) getPanel(); JRadioButton explicitAlignButton = (JRadioButton) getInstanceField("explicitAlignButton", editorPanel); @@ -301,7 +301,7 @@ public class StructureEditorAlignmentTest extends AbstractStructureEditorTest { emptyStructure.pack(pack); init(emptyStructure, pgmRootCat, false); - CompEditorPanel editorPanel = (CompEditorPanel) getPanel(); + StructureEditorPanel editorPanel = (StructureEditorPanel) getPanel(); DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1); addDataType(new ByteDataType()); @@ -433,7 +433,7 @@ public class StructureEditorAlignmentTest extends AbstractStructureEditorTest { init(emptyStructure, pgmRootCat, false); - CompEditorPanel editorPanel = (CompEditorPanel) getPanel(); + StructureEditorPanel editorPanel = (StructureEditorPanel) getPanel(); JRadioButton byValueButton = (JRadioButton) findComponentByName(getPanel(), "Explicit Alignment"); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorArchiveTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorArchiveTest.java index 6b55f9cc3c..4fbc669d46 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorArchiveTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorArchiveTest.java @@ -4,9 +4,9 @@ * 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. @@ -71,8 +71,8 @@ public class StructureEditorArchiveTest extends AbstractStructureEditorTest { createStruct = getAction(plugin, "Structure"); performAction(createStruct, plugin.getProvider(), true); waitForSwing(); - CompEditorPanel editorPanel = - findComponent(tool.getToolFrame(), CompEditorPanel.class, true); + StructureEditorPanel editorPanel = + findComponent(tool.getToolFrame(), StructureEditorPanel.class, true); model = editorPanel.model; installProvider(model.getProvider()); archiveDTM = model.getOriginalDataTypeManager(); @@ -82,7 +82,7 @@ public class StructureEditorArchiveTest extends AbstractStructureEditorTest { waitForSwing(); // 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); pressButtonByText(dialog.getContentPane(), "No"); waitForSwing(); @@ -112,8 +112,7 @@ public class StructureEditorArchiveTest extends AbstractStructureEditorTest { DataTypeTestUtils.performAction(action, dtTree, false); - GhidraFileChooser chooser = - waitForDialogComponent(tool.getToolFrame(), GhidraFileChooser.class, 10000); + GhidraFileChooser chooser = waitForDialogComponent(GhidraFileChooser.class); assertNotNull("Never found chooser!", chooser); selectFileInChooser(chooser, archiveFile); @@ -162,8 +161,8 @@ public class StructureEditorArchiveTest extends AbstractStructureEditorTest { createStruct = getAction(plugin, "Structure"); performAction(createStruct, plugin.getProvider(), true); waitForSwing(); - CompEditorPanel editorPanel = - findComponent(tool.getToolFrame(), CompEditorPanel.class, true); + StructureEditorPanel editorPanel = + findComponent(tool.getToolFrame(), StructureEditorPanel.class, true); model = editorPanel.model; installProvider(model.getProvider()); @@ -199,7 +198,7 @@ public class StructureEditorArchiveTest extends AbstractStructureEditorTest { selectNode(child); performAction(closeArchive, plugin.getProvider(), false); - OptionDialog dialog = waitForDialogComponent(tool.getToolFrame(), OptionDialog.class, 2000); + OptionDialog dialog = waitForDialogComponent(OptionDialog.class); JButton button = findButtonByText(dialog, "No"); pressButton(button); } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorFlexAlignmentTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorFlexAlignmentTest.java index 3687e1d410..8ddf7e2fc1 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorFlexAlignmentTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorFlexAlignmentTest.java @@ -21,9 +21,7 @@ import javax.swing.*; import org.junit.Test; -import docking.widgets.OptionDialog; import ghidra.program.database.DatabaseObject; -import ghidra.program.database.data.StructureDBTest; import ghidra.program.model.data.*; public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTest { @@ -57,7 +55,7 @@ public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTes addDataType(ByteDataType.dataType); addDataType(FloatDataType.dataType); - addFlexDataType((Structure) structureModel.viewComposite, DWordDataType.dataType, null, + addFlexDataType(structureModel.viewComposite, DWordDataType.dataType, null, null); assertEquals(3, structureModel.getNumComponents()); @@ -76,7 +74,7 @@ public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTes addDataType(ByteDataType.dataType); addDataType(CharDataType.dataType); - addFlexDataType((Structure) structureModel.viewComposite, DWordDataType.dataType, null, + addFlexDataType(structureModel.viewComposite, DWordDataType.dataType, null, null); waitForSwing(); @@ -110,7 +108,7 @@ public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTes addDataType(ByteDataType.dataType); addDataType(CharDataType.dataType); - addFlexDataType((Structure) structureModel.viewComposite, DWordDataType.dataType, null, + addFlexDataType(structureModel.viewComposite, DWordDataType.dataType, null, null); waitForSwing(); @@ -138,11 +136,11 @@ public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTes public void testByValueAlignedStructure() throws Exception { init(emptyStructure, pgmRootCat, false); - CompEditorPanel editorPanel = (CompEditorPanel) getPanel(); + StructureEditorPanel editorPanel = (StructureEditorPanel) getPanel(); addDataType(ByteDataType.dataType); addDataType(CharDataType.dataType); - addFlexDataType((Structure) structureModel.viewComposite, DWordDataType.dataType, null, + addFlexDataType(structureModel.viewComposite, DWordDataType.dataType, null, null); waitForSwing(); @@ -209,7 +207,7 @@ public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTes addFlexDataType(emptyStructure, DWordDataType.dataType, null, null); init(emptyStructure, pgmRootCat, false); - CompEditorPanel editorPanel = (CompEditorPanel) getPanel(); + StructureEditorPanel editorPanel = (StructureEditorPanel) getPanel(); JRadioButton explicitAlignButton = (JRadioButton) getInstanceField("explicitAlignButton", editorPanel); @@ -243,11 +241,11 @@ public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTes emptyStructure.setExplicitPackingValue(value); init(emptyStructure, pgmRootCat, false); - CompEditorPanel editorPanel = (CompEditorPanel) getPanel(); + StructureEditorPanel editorPanel = (StructureEditorPanel) getPanel(); addDataType(ByteDataType.dataType); addDataType(CharDataType.dataType); - addFlexDataType((Structure) structureModel.viewComposite, DWordDataType.dataType, null, + addFlexDataType(structureModel.viewComposite, DWordDataType.dataType, null, null); JRadioButton byValuePackingButton = diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorLockedActions3Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorLockedActions3Test.java index 80f50cd41f..e04f620760 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorLockedActions3Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorLockedActions3Test.java @@ -353,7 +353,7 @@ public class StructureEditorLockedActions3Test extends AbstractStructureEditorTe @Test public void testShowNumbersInHex() { init(complexStructure, pgmTestCat); - CompEditorPanel panel = (CompEditorPanel) provider.getComponent(); + StructureEditorPanel panel = (StructureEditorPanel) provider.getComponent(); assertEquals("", model.getStatus()); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorLockedDnDTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorLockedDnDTest.java index 1d2d2ac68e..3372ead0dd 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorLockedDnDTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorLockedDnDTest.java @@ -159,8 +159,7 @@ public class StructureEditorLockedDnDTest extends AbstractStructureEditorTest { assertNotNull(dt4); insertAtPoint(dt4, 0, 0); - JDialog dialog = - waitForJDialog(env.getTool().getToolFrame(), "Enter Number", DEFAULT_WINDOW_TIMEOUT); + JDialog dialog = waitForJDialog("Enter Number"); assertNotNull(dialog); JTextField textField = findComponent(dialog, JTextField.class); triggerText(textField, "3"); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorUnlockedActions5Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorUnlockedActions5Test.java index 744406e0e0..ec51927f73 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorUnlockedActions5Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorUnlockedActions5Test.java @@ -100,7 +100,7 @@ public class StructureEditorUnlockedActions5Test extends AbstractStructureEditor assertTrue(model.isValidName()); - CompEditorPanel panel = (CompEditorPanel) getPanel(); + StructureEditorPanel panel = (StructureEditorPanel) getPanel(); assertFalse(panel.hasInvalidEntry()); assertFalse(panel.hasUncomittedEntry()); @@ -143,7 +143,7 @@ public class StructureEditorUnlockedActions5Test extends AbstractStructureEditor assertTrue(model.isValidName()); - CompEditorPanel panel = (CompEditorPanel) getPanel(); + StructureEditorPanel panel = (StructureEditorPanel) getPanel(); assertFalse(panel.hasInvalidEntry()); assertFalse(panel.hasUncomittedEntry()); @@ -657,7 +657,7 @@ public class StructureEditorUnlockedActions5Test extends AbstractStructureEditor public void testUndoRename() throws Exception { init(complexStructure, pgmTestCat); - CompEditorPanel panel = (CompEditorPanel) getPanel(); + StructureEditorPanel panel = (StructureEditorPanel) getPanel(); JTextField nameField = panel.nameTextField; setText(nameField, "myStruct"); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorUnlockedDnD2Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorUnlockedDnD2Test.java index 4d04963d57..a5939f7453 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorUnlockedDnD2Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorUnlockedDnD2Test.java @@ -4,9 +4,9 @@ * 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. @@ -74,7 +74,7 @@ public class StructureEditorUnlockedDnD2Test extends AbstractStructureEditorTest assertNotNull(dt4); addAtPoint(dt4, 3, 0); - dialog = env.waitForDialogComponent(NumberInputDialog.class, 1000); + dialog = waitForDialogComponent(NumberInputDialog.class); assertNotNull(dialog); okInput(dialog, 25); dialog = null; diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorUnlockedDnD3Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorUnlockedDnD3Test.java index 3ef3e9db65..b2cdd135de 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorUnlockedDnD3Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorUnlockedDnD3Test.java @@ -4,9 +4,9 @@ * 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. @@ -70,7 +70,7 @@ public class StructureEditorUnlockedDnD3Test extends AbstractStructureEditorTest assertNotNull(dt4); insertAtPoint(dt4, 0, 0); - dialog = env.waitForDialogComponent(NumberInputDialog.class, 1000); + dialog = waitForDialogComponent(NumberInputDialog.class); assertNotNull(dialog); okInput(dialog, 25); dialog = null; diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorUnlockedEnablementTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorUnlockedEnablementTest.java index d3604b207b..3798e13522 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorUnlockedEnablementTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/StructureEditorUnlockedEnablementTest.java @@ -254,7 +254,7 @@ public class StructureEditorUnlockedEnablementTest extends AbstractStructureEdit init(complexStructure, pgmBbCat); structureModel.viewDTM.withTransaction("Add Bitfield", - () -> ((Structure) structureModel.viewComposite).insertBitField(2, 1, 4, + () -> structureModel.viewComposite.insertBitField(2, 1, 4, CharDataType.dataType, 2, "bf1", null)); setSelection(new int[] { 2 }); @@ -296,7 +296,7 @@ public class StructureEditorUnlockedEnablementTest extends AbstractStructureEdit init(complexStructure, pgmBbCat); structureModel.viewDTM.withTransaction("Add Bitfield", - () -> ((Structure) structureModel.viewComposite).insertBitField(2, 1, 4, + () -> structureModel.viewComposite.insertBitField(2, 1, 4, CharDataType.dataType, 2, "bf1", null)); setSelection(new int[] { 2 }); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/UnionEditorActions1Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/UnionEditorActions1Test.java index 7a97caee0f..4c9153216b 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/UnionEditorActions1Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/compositeeditor/UnionEditorActions1Test.java @@ -810,7 +810,7 @@ public class UnionEditorActions1Test extends AbstractUnionEditorTest { public void testApplyWithInvalidName() throws Exception { init(complexUnion, pgmTestCat, false); - CompEditorPanel panel = (CompEditorPanel) getPanel(); + UnionEditorPanel panel = (UnionEditorPanel) getPanel(); JTextField nameField = panel.nameTextField; assertTrue(model.isValidName()); @@ -875,7 +875,7 @@ public class UnionEditorActions1Test extends AbstractUnionEditorTest { public void testShowNumbersInHex() { init(complexUnion, pgmTestCat, false); assertEquals("", model.getStatus()); - CompEditorPanel panel = (CompEditorPanel) provider.getComponent(); + UnionEditorPanel panel = (UnionEditorPanel) provider.getComponent(); assertEquals(false, model.isShowingNumbersInHex()); assertEquals("45", model.getValueAt(11, model.getLengthColumn())); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/AbstractStackEditorProviderTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/AbstractStackEditorProviderTest.java index 46bc685210..2e5b4e6b22 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/AbstractStackEditorProviderTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/AbstractStackEditorProviderTest.java @@ -4,9 +4,9 @@ * 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. @@ -15,7 +15,7 @@ */ package ghidra.app.plugin.core.stackeditor; -import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.*; import java.awt.Window; @@ -79,7 +79,7 @@ public abstract class AbstractStackEditorProviderTest extends AbstractStackEdito } 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); pressButtonByText(dialog, "Overwrite"); @@ -88,7 +88,7 @@ public abstract class AbstractStackEditorProviderTest extends AbstractStackEdito } 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); pressButtonByText(dialog, "Cancel"); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/AbstractStackEditorTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/AbstractStackEditorTest.java index 6adf7951e9..3eca112ff2 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/AbstractStackEditorTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/AbstractStackEditorTest.java @@ -4,9 +4,9 @@ * 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. @@ -362,10 +362,10 @@ public abstract class AbstractStackEditorTest extends AbstractEditorTest { waitForBusyTool(tool); Function f = program.getFunctionManager().getFunctionAt(addr(address)); - String funcName = f.getName(); - assertTrue(isProviderShown(tool.getToolFrame(), "Stack Editor", - StackEditorProvider.getProviderSubTitle(f))); - installProvider(stackEditorMgr.getProvider(program, funcName)); + stackEditorMgr.edit(f); + CompositeEditorProvider p = getComponentProvider(CompositeEditorProvider.class); + assertNotNull(p); + installProvider(p); model = ((StackEditorProvider) provider).getModel(); stackModel = (StackEditorModel) model; diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/StackEditorProvider1Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/StackEditorProvider1Test.java index f743505a68..5481593a77 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/StackEditorProvider1Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/StackEditorProvider1Test.java @@ -25,6 +25,7 @@ import javax.swing.SwingUtilities; import org.junit.Test; import docking.action.DockingActionIf; +import ghidra.app.plugin.core.compositeeditor.CompositeEditorProvider; import ghidra.app.util.datatype.EmptyCompositeException; import ghidra.framework.options.Options; import ghidra.program.model.data.*; @@ -173,9 +174,10 @@ public class StackEditorProvider1Test extends AbstractStackEditorProviderTest { Function f = program.getFunctionManager().getFunctionAt(addr("0x200")); assertStackEditorShowing(f); + CompositeEditorProvider p = getComponentProvider(CompositeEditorProvider.class); + assertNotNull(p); + installProvider(p); - installProvider(stackEditorMgr.getProvider(program, "FUN_00000200")); - assertNotNull(provider); model = ((StackEditorProvider) provider).getModel(); assertNotNull(model); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/framework/plugintool/mgr/BackgroundCommandTaskTest.java b/Ghidra/Features/Base/src/test/java/ghidra/framework/plugintool/mgr/BackgroundCommandTaskTest.java index 9ebb30d6f3..20ad649b13 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/framework/plugintool/mgr/BackgroundCommandTaskTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/framework/plugintool/mgr/BackgroundCommandTaskTest.java @@ -4,9 +4,9 @@ * 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. @@ -123,10 +123,10 @@ public class BackgroundCommandTaskTest extends AbstractGenericTest { } @Override - public void endTransaction(int transactionID, boolean commit) { - + public boolean endTransaction(int transactionID, boolean commit) { assertEquals(ID, transactionID); transactionCommited = commit; + return transactionCommited; } boolean wasCommitted() { diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/VTSessionDB.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/VTSessionDB.java index e5ba8e142c..23af40fd72 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/VTSessionDB.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/VTSessionDB.java @@ -4,9 +4,9 @@ * 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. @@ -809,12 +809,13 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession { } @Override - public void endTransaction(int transactionID, boolean commit) { + public boolean endTransaction(int transactionID, boolean commit) { TransactionInfo transaction = getCurrentTransactionInfo(); - super.endTransaction(transactionID, commit); + boolean committed = super.endTransaction(transactionID, commit); if (changeSetsModified && transaction.getStatus() == Status.COMMITTED) { changeSetsModified = false; } + return committed; } @Override diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/util/EmptyVTSession.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/util/EmptyVTSession.java index 8956970089..3be5f7003a 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/util/EmptyVTSession.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/util/EmptyVTSession.java @@ -4,9 +4,9 @@ * 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. @@ -165,9 +165,8 @@ public class EmptyVTSession implements VTSession { } @Override - public void endTransaction(int transactionID, boolean commit) { - // do nothing - + public boolean endTransaction(int transactionID, boolean commit) { + throw new UnsupportedOperationException(); } @Override diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/DomainObjectAdapterDB.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/DomainObjectAdapterDB.java index 43d9617d05..6a76c0d7c2 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/DomainObjectAdapterDB.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/DomainObjectAdapterDB.java @@ -23,6 +23,7 @@ import java.util.function.Function; import db.*; import db.util.ErrorHandler; import ghidra.framework.model.*; +import ghidra.framework.model.TransactionInfo.Status; import ghidra.framework.options.Options; import ghidra.framework.options.SubOptions; import ghidra.framework.store.LockException; @@ -358,8 +359,9 @@ public abstract class DomainObjectAdapterDB extends DomainObjectAdapter implemen } @Override - public void endTransaction(int transactionID, boolean commit) throws IllegalStateException { - transactionMgr.endTransaction(this, transactionID, commit, true); + public boolean endTransaction(int transactionID, boolean commit) throws IllegalStateException { + TransactionInfo txInfo = transactionMgr.endTransaction(this, transactionID, commit, true); + return txInfo.getStatus() == Status.COMMITTED; } /** diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainObject.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainObject.java index 72c2e8ed2d..fabda97fda 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainObject.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/DomainObject.java @@ -4,9 +4,9 @@ * 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. @@ -500,11 +500,21 @@ public interface DomainObject { /** * Terminate the specified transaction for this domain object. + *

+ * 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. + *

+ * 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 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. + * @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 @@ -546,12 +556,12 @@ public interface DomainObject { 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(); /** - * Returns true if there is a later state to "redo" to. + * {@return true if there is a later state to "redo" to.} */ boolean canRedo(); diff --git a/Ghidra/Framework/Project/src/test/java/ghidra/framework/task/GenericDomainObjectDB.java b/Ghidra/Framework/Project/src/test/java/ghidra/framework/task/GenericDomainObjectDB.java index 314a314eab..c2f3b0ee86 100644 --- a/Ghidra/Framework/Project/src/test/java/ghidra/framework/task/GenericDomainObjectDB.java +++ b/Ghidra/Framework/Project/src/test/java/ghidra/framework/task/GenericDomainObjectDB.java @@ -4,9 +4,9 @@ * 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. @@ -48,9 +48,10 @@ public class GenericDomainObjectDB extends DomainObjectAdapterDB { } @Override - public void endTransaction(int transactionID, boolean commit) { - super.endTransaction(transactionID, commit); + public boolean endTransaction(int transactionID, boolean commit) { + boolean committed = super.endTransaction(transactionID, commit); transactionsList.add(currentTransaction); currentTransaction = null; + return committed; } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProjectDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProjectDataTypeManager.java index 687e49e5bc..d17330f2c7 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProjectDataTypeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProjectDataTypeManager.java @@ -4,9 +4,9 @@ * 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. @@ -212,8 +212,8 @@ public class ProjectDataTypeManager extends StandAloneDataTypeManager } @Override - public void endTransaction(int transactionID, boolean commit) { - dataTypeArchive.endTransaction(transactionID, commit); + public boolean endTransaction(int transactionID, boolean commit) { + return dataTypeArchive.endTransaction(transactionID, commit); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramDataTypeManager.java index 9d662f5f67..631f166336 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramDataTypeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramDataTypeManager.java @@ -4,9 +4,9 @@ * 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. @@ -296,9 +296,8 @@ public class ProgramDataTypeManager extends ProgramBasedDataTypeManagerDB implem } @Override - public void endTransaction(int transactionID, boolean commit) { - program.endTransaction(transactionID, commit); - + public boolean endTransaction(int transactionID, boolean commit) { + return program.endTransaction(transactionID, commit); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BuiltInDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BuiltInDataTypeManager.java index 1defcd080e..6d0e6c0806 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BuiltInDataTypeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BuiltInDataTypeManager.java @@ -4,9 +4,9 @@ * 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. @@ -92,11 +92,11 @@ public final class BuiltInDataTypeManager extends StandAloneDataTypeManager { } @Override - public synchronized void endTransaction(int transactionID, boolean commit) { + public synchronized boolean endTransaction(int transactionID, boolean commit) { if (manager != null) { throw new UnsupportedOperationException(); } - super.endTransaction(transactionID, commit); + return super.endTransaction(transactionID, commit); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java index 395ece69da..07268f19b1 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java @@ -4,9 +4,9 @@ * 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. @@ -18,6 +18,7 @@ package ghidra.program.model.data; import java.util.*; import db.Transaction; +import ghidra.framework.model.DomainObject; import ghidra.program.database.SpecExtension; import ghidra.program.database.map.AddressMap; import ghidra.program.model.lang.*; @@ -380,11 +381,27 @@ public interface DataTypeManager { public int startTransaction(String description); /** - * Ends the current transaction + * Ends the current transaction. + *

+ * 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. + *

+ * 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. + *

+ * 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 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 diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StandAloneDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StandAloneDataTypeManager.java index 2dcc1c8981..1326596935 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StandAloneDataTypeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StandAloneDataTypeManager.java @@ -873,15 +873,15 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos } /** - * Get the number of active transactions - * @return number of active transactions + * Get the number of active datatype manager transactions + * @return number of active datatype manager transactions */ protected int getTransactionCount() { return transactionCount; } @Override - public void endTransaction(int transactionID, boolean commit) { + public boolean endTransaction(int transactionID, boolean commit) { boolean restored = false; synchronized (this) { if (transaction == null) { @@ -917,6 +917,7 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos invalidateCache(); notifyRestored(); } + return transaction == null && !restored; } public void undo() { diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/StubProgram.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/StubProgram.java index 0930afb095..82b6581e90 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/StubProgram.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/StubProgram.java @@ -4,9 +4,9 @@ * 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. @@ -60,7 +60,7 @@ public class StubProgram implements Program { } @Override - public void endTransaction(int transactionID, boolean commit) { + public boolean endTransaction(int transactionID, boolean commit) { throw new UnsupportedOperationException(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDoubleDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDoubleDataTypeManager.java index e6dedcd54c..78d03a9fe0 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDoubleDataTypeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDoubleDataTypeManager.java @@ -4,9 +4,9 @@ * 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. @@ -236,7 +236,7 @@ public class TestDoubleDataTypeManager implements DataTypeManager { } @Override - public void endTransaction(int transactionID, boolean commit) { + public boolean endTransaction(int transactionID, boolean commit) { throw new UnsupportedOperationException(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDummyDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDummyDataTypeManager.java index b68306cc03..87feb6bce5 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDummyDataTypeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/data/TestDummyDataTypeManager.java @@ -4,9 +4,9 @@ * 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. @@ -243,9 +243,9 @@ public class TestDummyDataTypeManager implements DataTypeManager { } @Override - public void endTransaction(int transactionID, boolean commit) { + public boolean endTransaction(int transactionID, boolean commit) { // stub - + return false; } @Override