mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-24 05:10:16 +00:00
Merge remote-tracking branch 'origin/GP-4740_ghidra1_CompositeEditorUndoRedo--SQUASHED'
This commit is contained in:
commit
47146d25f2
@ -87,6 +87,15 @@
|
||||
<LI>Immediately below the structure information area is a status line where status messages
|
||||
will appear.</LI>
|
||||
</UL>
|
||||
|
||||
<P><IMG src="help/shared/note.png" alt=""> All actions will be disabled while information
|
||||
entries are being modified and have not yet been comitted (e.g., Name, Description, Size, etc.).
|
||||
Such edits must either be comitted or reverted
|
||||
before other actions may be performed. An entry's background will changed to reflect the
|
||||
validity of an uncomitted value. A valid entry will be comitted by hitting the <Enter>
|
||||
key or changing focus. While in this edit state the entry may be reverted by hitting the
|
||||
<Escape> key.</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H2><A name="Structure_Editor_Apply_Editor_Changes"></A>Applying Changes</H2>
|
||||
@ -100,8 +109,46 @@
|
||||
applied and it is assigned to data in the program, all data items with the structure or union
|
||||
as the data type now have the new data type. In other words, the size or composition of those
|
||||
data items in the program will have changed due to the apply.</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H2><A name="Structure_Editor_Undo_Editor_Change"></A>Undo Change</H2>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>Select the Undo Change icon <IMG src="icon.undo" alt=""> in the toolbar to revert
|
||||
the previous change within the editor. The editor state maintains a stack of changes
|
||||
made within the editor. The last change which may be reverted is described by the button's
|
||||
tooltip. If this action is used and a change is reverted it may be re-applied by using the
|
||||
<A href="#Structure_Editor_Redo_Editor_Change">Redo Change</A> action. When changes are
|
||||
<A href="#Structure_Editor_Apply_Editor_Changes">applied</A>
|
||||
back to the original program or archive the undo/redo stack is cleared.<BR>
|
||||
</P>
|
||||
|
||||
<P><IMG src="help/shared/note.png" alt=""> Any change made to the editor's origininating
|
||||
datatype manager (i.e., datatype or categories) which impact any datatype directly, or
|
||||
indirectly, referenced by the edited composite at anytime during the edit session will
|
||||
cause the undo/redo stack to be cleared.</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H2><A name="Structure_Editor_Redo_Editor_Change"></A>Redo Change</H2>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>Select the Redo Change icon <IMG src="icon.redo" alt=""> in the toolbar to re-apply
|
||||
a previous change which was just <A href="#Structure_Editor_Undo_Editor_Change">reverted</A>.
|
||||
The last reverted change which may be re-applied is described by the button's
|
||||
tooltip. If this action is used and a change is re-applied it may again be reverted by using the
|
||||
<A href="#Structure_Editor_Undo_Editor_Change">Undo Change</A> action. When changes are
|
||||
<A href="#Structure_Editor_Apply_Editor_Changes">applied</A>
|
||||
back to the original program or archive the undo/redo stack is cleared.<BR>
|
||||
</P>
|
||||
|
||||
<P><IMG src="help/shared/note.png" alt=""> Any change made to the editor's origininating
|
||||
datatype manager (i.e., datatype or categories) which impact any datatype directly, or
|
||||
indirectly, referenced by the edited composite at anytime during the edit session will
|
||||
cause the undo/redo stack to be cleared.</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H2><A name="Show_In_Data_Type_Manager"></A><A name="Structure_Editor_Show_In_Data_Type_Manager">Show In Data Type Manager</H2>
|
||||
|
||||
|
@ -32,7 +32,6 @@ public class AddBitFieldAction extends CompositeEditorTableAction {
|
||||
if (!(model instanceof CompEditorModel)) {
|
||||
throw new AssertException("unsupported use");
|
||||
}
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -42,7 +41,10 @@ public class AddBitFieldAction extends CompositeEditorTableAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
if (hasIncompleteFieldEntry()) {
|
||||
return false;
|
||||
}
|
||||
boolean enabled = true;
|
||||
CompEditorModel editorModel = (CompEditorModel) model;
|
||||
// Unions do not support non-packed manipulation of bitfields
|
||||
@ -50,7 +52,7 @@ public class AddBitFieldAction extends CompositeEditorTableAction {
|
||||
editorModel.isPackingEnabled() || editorModel.getNumSelectedRows() != 1) {
|
||||
enabled = false;
|
||||
}
|
||||
setEnabled(enabled);
|
||||
return enabled;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
@ -28,7 +28,7 @@ import ghidra.program.model.data.InvalidDataTypeException;
|
||||
public class ApplyAction extends CompositeEditorTableAction {
|
||||
|
||||
public final static String ACTION_NAME = "Apply Editor Changes";
|
||||
private final static String GROUP_NAME = BASIC_ACTION_GROUP;
|
||||
private final static String GROUP_NAME = MAIN_ACTION_GROUP;
|
||||
private final static Icon ICON = new GIcon("icon.plugin.composite.editor.apply");
|
||||
private final static String[] POPUP_PATH = new String[] { "Apply Edits" };
|
||||
|
||||
@ -36,28 +36,29 @@ public class ApplyAction extends CompositeEditorTableAction {
|
||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||
|
||||
setDescription("Apply editor changes");
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!model.isValidName()) {
|
||||
model.setStatus("Name is not valid.", true);
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
provider.editorPanel.comitEntryChanges();
|
||||
|
||||
try {
|
||||
model.apply();
|
||||
}
|
||||
catch (EmptyCompositeException | InvalidDataTypeException e) {
|
||||
model.setStatus(e.getMessage(), true);
|
||||
}
|
||||
requestTableFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
boolean hasChanges = model.hasChanges();
|
||||
boolean validName = model.isValidName();
|
||||
setEnabled(hasChanges && validName);
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
if (hasIncompleteFieldEntry()) {
|
||||
return false;
|
||||
}
|
||||
return model.hasChanges() && model.isValidName();
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
@ -42,11 +42,13 @@ public class ArrayAction extends CompositeEditorTableAction {
|
||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||
setDescription(DESCRIPTION);
|
||||
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
model.createArray();
|
||||
}
|
||||
@ -57,7 +59,8 @@ public class ArrayAction extends CompositeEditorTableAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
setEnabled(model.isArrayAllowed());
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return !hasIncompleteFieldEntry() && model.isArrayAllowed();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
@ -173,7 +173,8 @@ public class BitFieldEditorDialog extends DialogComponentProvider {
|
||||
return;
|
||||
}
|
||||
int ordinal = bitfieldDtc.getOrdinal();
|
||||
composite.delete(ordinal);
|
||||
composite.getDataTypeManager()
|
||||
.withTransaction("Delete Bitfield", () -> composite.delete(ordinal));
|
||||
bitFieldEditorPanel.componentDeleted(ordinal);
|
||||
if (listener != null) {
|
||||
listener.componentChanged(ordinal);
|
||||
@ -192,7 +193,6 @@ public class BitFieldEditorDialog extends DialogComponentProvider {
|
||||
|
||||
ToggleHexUseAction() {
|
||||
super("Show Byte Offsets in Hexadecimal", "BitFieldEditorDialog");
|
||||
setEnabled(true);
|
||||
setSelected(bitFieldEditorPanel.isShowOffsetsInHex());
|
||||
setPopupMenuData(new MenuData(new String[] { getName() }));
|
||||
setHelpLocation(new HelpLocation("DataTypeEditors", "Structure_Bitfield_Editor"));
|
||||
@ -225,8 +225,7 @@ public class BitFieldEditorDialog extends DialogComponentProvider {
|
||||
@Override
|
||||
protected JMenuItem doCreateMenuItem() {
|
||||
DockingCheckBoxMenuItem menuItem = new DockingCheckBoxMenuItem(isSelected);
|
||||
menuItem.setUI(
|
||||
(DockingCheckboxMenuItemUI) DockingCheckboxMenuItemUI.createUI(menuItem));
|
||||
menuItem.setUI(DockingCheckboxMenuItemUI.createUI(menuItem));
|
||||
return menuItem;
|
||||
}
|
||||
}
|
||||
|
@ -645,8 +645,14 @@ public class BitFieldEditorPanel extends JPanel {
|
||||
}
|
||||
deleteConflicts = (option == OptionDialog.OPTION_ONE);
|
||||
}
|
||||
placementComponent.applyBitField(baseDataType, fieldNameTextField.getText().trim(),
|
||||
fieldCommentTextField.getText().trim(), deleteConflicts, listener);
|
||||
|
||||
boolean doDeleteConflicts = deleteConflicts;
|
||||
this.composite.getDataTypeManager()
|
||||
.withTransaction("Apply Bitfield",
|
||||
() -> placementComponent.applyBitField(baseDataType,
|
||||
fieldNameTextField.getText().trim(), fieldCommentTextField.getText().trim(),
|
||||
doDeleteConflicts, listener));
|
||||
|
||||
enableControls(false);
|
||||
return true;
|
||||
}
|
||||
|
@ -460,7 +460,7 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable {
|
||||
repaint();
|
||||
}
|
||||
|
||||
void applyBitField(DataType baseDataType, String fieldName, String fieldComment,
|
||||
DataTypeComponent applyBitField(DataType baseDataType, String fieldName, String fieldComment,
|
||||
boolean deleteConflicts, CompositeChangeListener listener) {
|
||||
if (!editUseEnabled) {
|
||||
throw new IllegalStateException("component not constructed for edit use");
|
||||
@ -519,9 +519,11 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable {
|
||||
if (listener != null) {
|
||||
listener.componentChanged(dtc.getOrdinal());
|
||||
}
|
||||
return dtc;
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException | InvalidDataTypeException e) {
|
||||
Msg.error(this, "Unexpected bitfield apply error", e);
|
||||
Msg.showError(this, this, "Unexpected bitfield apply error", e);
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
editMode = EditMode.NONE;
|
||||
@ -1032,14 +1034,6 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable {
|
||||
rightChopBytes = rightChop;
|
||||
allocationBytes = allocationByteSize - leftChopBytes - rightChopBytes;
|
||||
|
||||
if (allocationBytes <= 0) {
|
||||
int junk = 0;
|
||||
// allocation shrunk - need to adjust window
|
||||
|
||||
// TODO: Need to adjust view port sizing when allocationByteSize changes
|
||||
|
||||
}
|
||||
|
||||
allocateBits();
|
||||
layoutBits();
|
||||
}
|
||||
|
@ -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.
|
||||
@ -38,11 +38,13 @@ public class ClearAction extends CompositeEditorTableAction {
|
||||
|
||||
setDescription("Clear the selected components");
|
||||
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
model.clearSelectedComponents();
|
||||
}
|
||||
@ -53,7 +55,8 @@ public class ClearAction extends CompositeEditorTableAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
setEnabled(model.isClearAllowed());
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return !hasIncompleteFieldEntry() && model.isClearAllowed();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
@ -19,6 +19,7 @@ import java.util.*;
|
||||
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.fieldpanel.support.*;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.InsufficientBytesException;
|
||||
@ -28,6 +29,8 @@ import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
|
||||
private volatile boolean consideringReplacedDataType = false;
|
||||
|
||||
/**
|
||||
* Creates a model for editing a composite data type.
|
||||
* @param provider the provider that is using this model for editing.
|
||||
@ -38,8 +41,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
|
||||
@Override
|
||||
public boolean hasChanges() {
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
if ((originalDTM != null) && !originalDTM.contains(originalComposite)) {
|
||||
if (originalDTM != null && !originalDTM.contains(originalComposite)) {
|
||||
return true;
|
||||
}
|
||||
return super.hasChanges();
|
||||
@ -56,20 +58,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
selectionChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current dataType name (Structure or Union) as a string.
|
||||
*/
|
||||
@Override
|
||||
protected String getTypeName() {
|
||||
if (viewComposite instanceof Structure) {
|
||||
return "Structure";
|
||||
}
|
||||
else if (viewComposite instanceof Union) {
|
||||
return "Union";
|
||||
}
|
||||
return super.getTypeName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the changes for the current edited composite back to the
|
||||
* original composite.
|
||||
@ -87,7 +75,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
|
||||
FieldSelection saveSelection = new FieldSelection(selection);
|
||||
Composite originalDt = getOriginalComposite();
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
if (originalDt == null || originalDTM == null) {
|
||||
throw new IllegalStateException(
|
||||
"Can't apply edits without a data type or data type manager.");
|
||||
@ -103,8 +90,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
if (renamed) {
|
||||
action += "/Rename";
|
||||
}
|
||||
String type = (originalDt instanceof Union) ? " Union " : " Structure ";
|
||||
int transactionID = originalDTM.startTransaction(action + type + getCompositeName());
|
||||
int transactionID = originalDTM.startTransaction(action + " " + getTypeName());
|
||||
try {
|
||||
if (originalDtExists) {
|
||||
// Update the original structure.
|
||||
@ -137,7 +123,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
}
|
||||
finally {
|
||||
provider.updateTitle();
|
||||
// selection = saveSelection;
|
||||
setSelection(saveSelection);
|
||||
originalDTM.endTransaction(transactionID, true);
|
||||
}
|
||||
@ -260,15 +245,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void setDataType(int rowIndex, DataType dt, int length) throws UsrException {
|
||||
if (rowIndex < getNumComponents()) {
|
||||
replace(rowIndex, dt, length);
|
||||
}
|
||||
else {
|
||||
insert(rowIndex, dt, length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeInstance validateComponentDataType(int rowIndex, String dtString)
|
||||
throws UsrException {
|
||||
@ -295,11 +271,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
return (getNumSelectedRows() > 0) && !isBlankLastLineSelected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCycleAllowed(CycleGroup cycleGroup) {
|
||||
return (getNumSelectedRows() == 1);
|
||||
}
|
||||
|
||||
public boolean isInsertAllowed(DataType dataType) {
|
||||
int rowIndex = getMinIndexSelected();
|
||||
if (rowIndex == -1) {
|
||||
@ -343,9 +314,11 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
}
|
||||
|
||||
private void doDelete(int componentOrdinal) {
|
||||
viewComposite.delete(componentOrdinal);
|
||||
if (componentOrdinal < row) {
|
||||
row--;
|
||||
viewDTM.withTransaction("Delete Component", () -> {
|
||||
viewComposite.delete(componentOrdinal);
|
||||
});
|
||||
if (componentOrdinal < currentEditRow) {
|
||||
currentEditRow--;
|
||||
}
|
||||
}
|
||||
|
||||
@ -368,13 +341,13 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
for (int i = n - 1; i >= 0; i--) {
|
||||
int rowIndex = rows[i];
|
||||
int componentOrdinal = convertRowToOrdinal(rowIndex);
|
||||
if (componentOrdinal < row) {
|
||||
row--;
|
||||
if (componentOrdinal < currentEditRow) {
|
||||
currentEditRow--;
|
||||
}
|
||||
rowSet.add(componentOrdinal);
|
||||
}
|
||||
|
||||
viewComposite.delete(rowSet);
|
||||
viewDTM.withTransaction("Delete Components", () -> viewComposite.delete(rowSet));
|
||||
|
||||
// Not sure if this is the right behavior. Assuming the deleted rows were selected,
|
||||
// restore the selection to be the first row that was deleted so that the UI leaves the
|
||||
@ -427,14 +400,14 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
monitor.checkCancelled();
|
||||
int componentOrdinal = convertRowToOrdinal(rowIndex);
|
||||
ordinals.add(componentOrdinal);
|
||||
if (componentOrdinal < row) {
|
||||
row--;
|
||||
if (componentOrdinal < currentEditRow) {
|
||||
currentEditRow--;
|
||||
}
|
||||
selection.removeRange(componentOrdinal, componentOrdinal + 1);
|
||||
adjustSelection(componentOrdinal + 1, -1);
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
viewComposite.delete(ordinals);
|
||||
viewDTM.withTransaction("Delete Components", () -> viewComposite.delete(ordinals));
|
||||
fixSelection();
|
||||
componentEdited();
|
||||
notifyCompositeChanged();
|
||||
@ -612,14 +585,18 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
*/
|
||||
@Override
|
||||
public DataTypeComponent add(int rowIndex, DataType dt) throws UsrException {
|
||||
dt = viewDTM.resolve(dt, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
try {
|
||||
DataTypeInstance dti = getDropDataType(rowIndex, dt);
|
||||
return add(rowIndex, dti.getDataType(), dti.getLength());
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
return null;
|
||||
}
|
||||
String descr = rowIndex < getNumComponents() ? "Replace Component" : "Add Component";
|
||||
return viewDTM.withTransaction(descr, () -> {
|
||||
DataType resolvedDt = viewDTM.resolve(dt, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
try {
|
||||
DataTypeInstance dti = getDropDataType(rowIndex, resolvedDt);
|
||||
return add(rowIndex, dti.getDataType(), dti.getLength()); // add or replace
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -629,27 +606,27 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
*
|
||||
* @param rowIndex the index of the row where the data type should be added.
|
||||
* @param dt the data type to add
|
||||
*
|
||||
* @return true if the component is added, false if it doesn't.
|
||||
* @param dtLength datatype instance length
|
||||
* @return the component is added, null if it doesn't.
|
||||
* @throws UsrException if add fails
|
||||
*/
|
||||
@Override
|
||||
public DataTypeComponent add(int rowIndex, DataType dt, int dtLength) throws UsrException {
|
||||
DataTypeComponent dtc = null;
|
||||
if (rowIndex < getNumComponents()) {
|
||||
FieldRange range = getSelectedRangeContaining(rowIndex);
|
||||
if ((range == null) ||
|
||||
(range.getStart().getIndex().intValue() == range.getEnd().getIndex().intValue() -
|
||||
1)) {
|
||||
dtc = replace(rowIndex, dt, dtLength);
|
||||
}
|
||||
else {
|
||||
dtc = replaceComponentRange(range.getStart().getIndex().intValue(),
|
||||
dtc = viewDTM.withTransaction("Replace Component", () -> {
|
||||
FieldRange range = getSelectedRangeContaining(rowIndex);
|
||||
if ((range == null) || (range.getStart()
|
||||
.getIndex()
|
||||
.intValue() == range.getEnd().getIndex().intValue() - 1)) {
|
||||
return replace(rowIndex, dt, dtLength);
|
||||
}
|
||||
return replaceComponentRange(range.getStart().getIndex().intValue(),
|
||||
range.getEnd().getIndex().intValue() - 1, dt, dtLength);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
dtc = insert(rowIndex, dt, dtLength);
|
||||
dtc = viewDTM.withTransaction("Add Component", () -> insert(rowIndex, dt, dtLength));
|
||||
}
|
||||
return dtc;
|
||||
}
|
||||
@ -669,29 +646,28 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
* @param rowIndex the index of row where the data type should be replaced.
|
||||
* @param dt the new data type
|
||||
*
|
||||
* @return true if the component is added, false if it doesn't.
|
||||
* @throws UsrException if add fails
|
||||
* @return component added, null or exception if it does not
|
||||
* @throws UsrException if add error occurs
|
||||
*/
|
||||
public DataTypeComponent replace(int rowIndex, DataType dt) throws UsrException {
|
||||
DataTypeInstance dti =
|
||||
DataTypeHelper.getFixedLength(this, rowIndex, dt, usesAlignedLengthComponents());
|
||||
if (dti == null) {
|
||||
return null; // User cancelled from size dialog.
|
||||
}
|
||||
DataTypeComponent dtc = null;
|
||||
if (rowIndex < getNumComponents()) {
|
||||
FieldRange range = getSelectedRangeContaining(rowIndex);
|
||||
if ((range == null) ||
|
||||
(range.getStart().getIndex().intValue() == range.getEnd().getIndex().intValue() -
|
||||
1)) {
|
||||
dtc = replace(rowIndex, dti.getDataType(), dti.getLength());
|
||||
return viewDTM.withTransaction("Replace Component", () -> {
|
||||
DataTypeInstance dti =
|
||||
DataTypeHelper.getFixedLength(this, rowIndex, dt, usesAlignedLengthComponents());
|
||||
if (dti == null) {
|
||||
return null; // User cancelled from size dialog.
|
||||
}
|
||||
else {
|
||||
dtc = replaceComponentRange(range.getStart().getIndex().intValue(),
|
||||
if (rowIndex < getNumComponents()) {
|
||||
FieldRange range = getSelectedRangeContaining(rowIndex);
|
||||
if ((range == null) || (range.getStart()
|
||||
.getIndex()
|
||||
.intValue() == range.getEnd().getIndex().intValue() - 1)) {
|
||||
return replace(rowIndex, dti.getDataType(), dti.getLength());
|
||||
}
|
||||
return replaceComponentRange(range.getStart().getIndex().intValue(),
|
||||
range.getEnd().getIndex().intValue() - 1, dti.getDataType(), dti.getLength());
|
||||
}
|
||||
}
|
||||
return dtc;
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -747,7 +723,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
// Get the current data type at the index.
|
||||
DataTypeComponent oldDtc = getComponent(rowIndex);
|
||||
if (oldDtc == null) {
|
||||
// TODO should this throw exception instead?
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -869,6 +844,8 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
|
||||
/**
|
||||
* Replaces the components of the original structure with those of the edited one.
|
||||
* Transaction must already be started on the {@link #getOriginalDataTypeManager()
|
||||
* original datatype manager}.
|
||||
*/
|
||||
protected abstract void replaceOriginalComponents();
|
||||
|
||||
@ -1006,9 +983,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
lastNumDuplicates = multiple;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void clearComponents(int[] rows) throws UsrException;
|
||||
|
||||
@Override
|
||||
protected void createArray(int numElements) throws InvalidDataTypeException, UsrException {
|
||||
if (selection.getNumRanges() != 1) {
|
||||
@ -1027,15 +1001,16 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
DataType dt = comp.getDataType();
|
||||
|
||||
ArrayDataType array = new ArrayDataType(dt, numElements, comp.getLength(), viewDTM);
|
||||
|
||||
if (getNumSelectedComponentRows() > 1) {
|
||||
replaceComponentRange(rowIndex,
|
||||
selection.getFieldRange(0).getEnd().getIndex().intValue() - 1, array,
|
||||
array.getLength());
|
||||
}
|
||||
else {
|
||||
replace(rowIndex, array, array.getLength()); // Can throw UsrException.
|
||||
}
|
||||
viewDTM.withTransaction("Create Array", () -> {
|
||||
if (getNumSelectedComponentRows() > 1) {
|
||||
replaceComponentRange(rowIndex,
|
||||
selection.getFieldRange(0).getEnd().getIndex().intValue() - 1, array,
|
||||
array.getLength());
|
||||
}
|
||||
else {
|
||||
replace(rowIndex, array, array.getLength()); // Can throw UsrException.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1126,7 +1101,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
* @return the number of Undefined bytes consumed.
|
||||
*/
|
||||
protected int consumeByComponent(int rowIndex) {
|
||||
// TODO FIXME
|
||||
int numComps = viewComposite.getNumComponents();
|
||||
if (rowIndex >= 0 && rowIndex < numComps) {
|
||||
DataTypeComponent comp = viewComposite.getComponent(rowIndex);
|
||||
@ -1151,72 +1125,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes the number of undefined bytes requested if they are available.
|
||||
*
|
||||
* @param rowIndex index of the row (component).
|
||||
* @param numDesired the number of Undefined bytes desired.
|
||||
* @return the number of components removed from the structure when the
|
||||
* bytes were consumed.
|
||||
* @throws java.util.NoSuchElementException if the index is invalid.
|
||||
* @throws InvalidDataTypeException if there aren't enough bytes.
|
||||
*/
|
||||
protected int consumeUndefinedBytes(int rowIndex, int numDesired)
|
||||
throws NoSuchElementException, InvalidDataTypeException {
|
||||
// TODO FIXME
|
||||
if (numDesired <= 0) {
|
||||
return 0;
|
||||
}
|
||||
int numRowComponents = getNumComponents();
|
||||
int numAvailable = getNumUndefinedBytesAt(rowIndex);
|
||||
int numIndicesRemoved = 0;
|
||||
if (numDesired > numAvailable) {
|
||||
throw new InvalidDataTypeException("Not enough undefined bytes."); // don't have enough undefined bytes there.
|
||||
}
|
||||
|
||||
int numBytesNeeded = numDesired;
|
||||
if (rowIndex >= numRowComponents) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
for (int i = rowIndex; i < numRowComponents; i++) {
|
||||
// Get the current data type at the index.
|
||||
DataTypeComponent comp = viewComposite.getComponent(rowIndex);
|
||||
DataType dt = comp.getDataType();
|
||||
int compLength = 0;
|
||||
// A single undefined byte.
|
||||
if (dt == DataType.DEFAULT) {
|
||||
compLength = comp.getLength();
|
||||
}
|
||||
else {
|
||||
throw new InvalidDataTypeException("Not enough undefined bytes."); // Ran into data type other than undefined byte.
|
||||
}
|
||||
if (compLength < numBytesNeeded) {
|
||||
// consume all of this undefined bytes data type.
|
||||
numBytesNeeded -= compLength;
|
||||
deleteComponent(rowIndex);
|
||||
numIndicesRemoved++;
|
||||
}
|
||||
else {
|
||||
// Determine number of bytes left over.
|
||||
int leftOverBytes = compLength - numBytesNeeded;
|
||||
deleteComponent(rowIndex);
|
||||
numIndicesRemoved++;
|
||||
if (leftOverBytes == 1) {
|
||||
insert(rowIndex, DataType.DEFAULT, 1, null, null);
|
||||
numIndicesRemoved--;
|
||||
}
|
||||
else if (leftOverBytes > 1) {
|
||||
DataType newDt = new ArrayDataType(DataType.DEFAULT, leftOverBytes, 1, viewDTM);
|
||||
insert(rowIndex, newDt, leftOverBytes, null, null);
|
||||
numIndicesRemoved--;
|
||||
}
|
||||
break; // We're done.
|
||||
}
|
||||
}
|
||||
return numIndicesRemoved;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
int numRows = 0;
|
||||
@ -1275,13 +1183,15 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
if (nameExistsElsewhere(name, rowIndex)) {
|
||||
throw new InvalidNameException("Name \"" + name + "\" already exists.");
|
||||
}
|
||||
try {
|
||||
getComponent(rowIndex).setFieldName(name); // setFieldName handles trimming
|
||||
return true;
|
||||
}
|
||||
catch (DuplicateNameException exc) {
|
||||
throw new InvalidNameException(exc.getMessage());
|
||||
}
|
||||
return viewDTM.withTransaction("Set Component Name", () -> {
|
||||
try {
|
||||
getComponent(rowIndex).setFieldName(name); // setFieldName handles trimming
|
||||
return true;
|
||||
}
|
||||
catch (DuplicateNameException exc) {
|
||||
throw new InvalidNameException(exc.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1297,7 +1207,9 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
return false;
|
||||
}
|
||||
|
||||
getComponent(rowIndex).setComment(newComment);
|
||||
viewDTM.withTransaction("Set Component Comment",
|
||||
() -> getComponent(rowIndex).setComment(comment));
|
||||
|
||||
fireTableCellUpdated(rowIndex, getCommentColumn());
|
||||
componentDataChanged();
|
||||
return true;
|
||||
@ -1324,17 +1236,237 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
(selection.getFieldRange(0).getEnd().getIndex().intValue() < getNumComponents()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restored(DataTypeManager dataTypeManager) {
|
||||
|
||||
if (originalDTM == null) {
|
||||
// editor unloaded
|
||||
return;
|
||||
}
|
||||
|
||||
if (!originalCompositeExists()) {
|
||||
|
||||
if (originalCompositeId != DataTypeManager.NULL_DATATYPE_ID && !hasChanges) {
|
||||
provider.dispose(); // Close editor
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: Removed types will remain if used directly by edited components.
|
||||
if (viewDTM.refreshDBTypesFromOriginal()) {
|
||||
setStatus("Dependency datatypes have changed or been removed");
|
||||
}
|
||||
|
||||
if (originalCompositeId != DataTypeManager.NULL_DATATYPE_ID) {
|
||||
provider.show();
|
||||
// The user has modified the structure so prompt for whether or
|
||||
// not to close the structure.
|
||||
String question = "The " + getOriginType() + " \"" + originalDTM.getName() +
|
||||
"\" has changed and \n" + "\"" + currentName +
|
||||
"\" no longer exists outside the editor.\n" + "Discard edits and close the " +
|
||||
getTypeName() + " editor?";
|
||||
String title = "Close " + getTypeName() + " Editor?";
|
||||
int response = OptionDialog.showYesNoDialogWithNoAsDefaultButton(
|
||||
provider.getComponent(), title, question);
|
||||
if (response == OptionDialog.YES_OPTION) {
|
||||
provider.dispose(); // Close editor
|
||||
return;
|
||||
}
|
||||
|
||||
reloadFromView();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
fireTableDataChanged();
|
||||
componentDataChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
Composite composite = getOriginalComposite();
|
||||
boolean reload = true;
|
||||
if (hasChanges || !viewComposite.isEquivalent(composite)) {
|
||||
hasChanges = true;
|
||||
provider.show();
|
||||
// The user has modified the structure so prompt for whether or
|
||||
// not to reload the structure.
|
||||
String question = "The " + getOriginType() + " \"" + originalDTM.getName() +
|
||||
"\" has been restored.\n" + "\"" + currentName +
|
||||
"\" may have changed outside the editor.\n" + "Discard edits and reload the " +
|
||||
getTypeName() + "?";
|
||||
String title = "Reload " + getTypeName() + " Editor?";
|
||||
int response = OptionDialog
|
||||
.showYesNoDialogWithNoAsDefaultButton(provider.getComponent(), title, question);
|
||||
if (response != OptionDialog.YES_OPTION) {
|
||||
reload = false;
|
||||
}
|
||||
}
|
||||
if (reload) {
|
||||
load(composite); // reload the structure
|
||||
setStatus("Editor reloaded");
|
||||
return;
|
||||
}
|
||||
|
||||
if (viewDTM.refreshDBTypesFromOriginal()) {
|
||||
setStatus("Dependency datatypes have changed or been removed");
|
||||
}
|
||||
fireTableDataChanged();
|
||||
componentDataChanged();
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Override CompositeViewerModel CategoryChangeListener methods
|
||||
//==================================================================================================
|
||||
|
||||
@Override
|
||||
public void dataTypeRemoved(DataTypeManager dtm, DataTypePath path) {
|
||||
|
||||
if (dtm != originalDTM) {
|
||||
return; // Different DTM than the one for this data type.
|
||||
}
|
||||
|
||||
DataType dataType = viewDTM.getDataType(path.getCategoryPath(), path.getDataTypeName());
|
||||
if (dataType == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!path.equals(originalDataTypePath)) {
|
||||
DataType dt = viewDTM.getDataType(path);
|
||||
if (dt != null) {
|
||||
if (hasSubDt(viewComposite, path)) {
|
||||
String msg = "Removed sub-component data type \"" + path;
|
||||
setStatus(msg, true);
|
||||
}
|
||||
viewDTM.withTransaction("Removed Dependency", () -> {
|
||||
viewDTM.clearUndoOnChange();
|
||||
viewDTM.remove(dt, TaskMonitor.DUMMY);
|
||||
});
|
||||
fireTableDataChanged();
|
||||
componentDataChanged();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (originalCompositeId == DataTypeManager.NULL_DATATYPE_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
consideringReplacedDataType = true;
|
||||
try {
|
||||
provider.show();
|
||||
// The user has modified the structure so prompt for whether or
|
||||
// not to close the structure.
|
||||
String question =
|
||||
"The " + getOriginType() + " \"" + originalDTM.getName() + "\" has changed and \n" +
|
||||
"\"" + getCompositeName() + "\" no longer exists outside the editor.\n" +
|
||||
"Discard edits and close the " + getTypeName() + " editor?";
|
||||
String title = "Close " + getTypeName() + " Editor?";
|
||||
int response = OptionDialog
|
||||
.showYesNoDialogWithNoAsDefaultButton(provider.getComponent(), title, question);
|
||||
if (response == OptionDialog.YES_OPTION) {
|
||||
provider.closeComponent(true); // Close editor
|
||||
return;
|
||||
}
|
||||
|
||||
reloadFromView();
|
||||
}
|
||||
finally {
|
||||
consideringReplacedDataType = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
|
||||
|
||||
if (dtm != originalDTM) {
|
||||
return; // Different DTM than the one for this data type.
|
||||
}
|
||||
|
||||
if (!isLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldPath.getDataTypeName().equals(newPath.getDataTypeName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
String newName = newPath.getDataTypeName();
|
||||
String oldName = oldPath.getDataTypeName();
|
||||
|
||||
// Does the old name match our original name.
|
||||
// Check originalCompositeId to ensure original type is managed
|
||||
if (originalCompositeId != DataTypeManager.NULL_DATATYPE_ID &&
|
||||
oldPath.equals(originalDataTypePath)) {
|
||||
originalDataTypePath = newPath;
|
||||
try {
|
||||
if (viewComposite.getName().equals(oldName)) {
|
||||
setName(newName);
|
||||
}
|
||||
}
|
||||
catch (InvalidNameException | DuplicateNameException e) {
|
||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for managed datatype changing
|
||||
DataType dt = viewDTM.getDataType(oldPath);
|
||||
if (dt == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
viewDTM.withTransaction("Renamed Dependency", () -> {
|
||||
viewDTM.clearUndoOnChange();
|
||||
try {
|
||||
dt.setName(newPath.getDataTypeName());
|
||||
}
|
||||
catch (InvalidNameException | DuplicateNameException e) {
|
||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
|
||||
fireTableDataChanged();
|
||||
componentDataChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeMoved(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
|
||||
|
||||
if (dtm != originalDTM) {
|
||||
return; // Different DTM than the one for this data type.
|
||||
}
|
||||
|
||||
DataType dt = viewDTM.getDataType(oldPath);
|
||||
if (dt == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
viewDTM.withTransaction("Moved " + oldPath, () -> {
|
||||
viewDTM.clearUndoOnChange();
|
||||
Category newDtCat = viewDTM.createCategory(newPath.getCategoryPath());
|
||||
newDtCat.moveDataType(dt, null);
|
||||
});
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new AssertException(e);
|
||||
}
|
||||
|
||||
if (originalDataTypePath.getDataTypeName().equals(newPath.getDataTypeName()) &&
|
||||
originalDataTypePath.getCategoryPath().equals(oldPath.getCategoryPath())) {
|
||||
originalDataTypePath = newPath;
|
||||
compositeInfoChanged();
|
||||
}
|
||||
else {
|
||||
fireTableDataChanged();
|
||||
componentDataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeChanged(DataTypeManager dtm, DataTypePath path) {
|
||||
try {
|
||||
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
if (originalDTM == null) {
|
||||
// editor unloaded
|
||||
if (!isLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1348,14 +1480,9 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
return; // Different DTM than the one for this data type.
|
||||
}
|
||||
|
||||
if (!isLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we don't currently have any modifications that need applying and
|
||||
// the structure in the editor just changed, then show the changed
|
||||
// structure.
|
||||
String oldName = path.getDataTypeName();
|
||||
if (path.equals(originalDataTypePath)) {
|
||||
if (consideringReplacedDataType) {
|
||||
return;
|
||||
@ -1369,10 +1496,12 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
}
|
||||
originalIsChanging = true;
|
||||
try {
|
||||
if (hadChanges) {
|
||||
String message = "<html>" + HTMLUtilities.escapeHTML(oldName) +
|
||||
" has changed outside the editor.<br>" + "Discard edits & reload the " +
|
||||
getTypeName() + "?";
|
||||
if (hasChanges) {
|
||||
provider.show();
|
||||
String message = "<html>" +
|
||||
HTMLUtilities.escapeHTML(originalDataTypePath.getDataTypeName()) +
|
||||
" has changed outside the editor.<br>" +
|
||||
"Discard edits and reload the " + getTypeName() + "?";
|
||||
String title = "Reload " + getTypeName() + " Editor?";
|
||||
int response = OptionDialog.showYesNoDialogWithNoAsDefaultButton(
|
||||
provider.getComponent(), title, message);
|
||||
@ -1395,28 +1524,32 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
}
|
||||
}
|
||||
else {
|
||||
DataType viewDt = viewDTM.getDataType(path);
|
||||
// NOTE: There is the risk of a cascade of change notifications resulting in multiple
|
||||
// undo transactions for the viewDTM. An editor save could generate quite a few with
|
||||
// potentially many types getting changed by one change.
|
||||
DataType changedDt = originalDTM.getDataType(path);
|
||||
if (!(changedDt instanceof DatabaseObject)) {
|
||||
// NOTE: viewDTM only maps view-to-original IDs for DataTypeDB
|
||||
return;
|
||||
}
|
||||
long originalId = originalDTM.getID(changedDt);
|
||||
DataType viewDt = viewDTM.findMyDataTypeFromOriginalID(originalId);
|
||||
if (viewDt == null) {
|
||||
return;
|
||||
}
|
||||
int origDtLen = viewDt.getLength();
|
||||
DataType changedDt = dtm.getDataType(path);
|
||||
if (changedDt != null) {
|
||||
if ((viewDt instanceof Composite) && (changedDt instanceof Composite)) {
|
||||
Composite comp = (Composite) changedDt;
|
||||
Composite origDt = getOriginalComposite();
|
||||
if ((origDt != null) && comp.isPartOf(origDt)) {
|
||||
removeDtFromComponents(comp);
|
||||
}
|
||||
|
||||
((Composite) viewDt)
|
||||
.setDescription(((Composite) changedDt).getDescription());
|
||||
}
|
||||
viewDt = viewDTM.resolve(changedDt, DataTypeConflictHandler.REPLACE_HANDLER);
|
||||
if (origDtLen != viewDt.getLength()) {
|
||||
viewComposite.dataTypeSizeChanged(viewDt);
|
||||
}
|
||||
try {
|
||||
viewDTM.withTransaction("Changed " + path, () -> {
|
||||
viewDTM.clearUndoOnChange();
|
||||
viewDTM.replaceDataType(viewDt, changedDt, true);
|
||||
});
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new AssertException(e);
|
||||
}
|
||||
|
||||
// Clear undo/redo stack to avoid inconsistency with originalDTM
|
||||
viewDTM.clearUndo();
|
||||
|
||||
fireTableDataChanged();
|
||||
componentDataChanged();
|
||||
}
|
||||
@ -1426,13 +1559,10 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
}
|
||||
}
|
||||
|
||||
private volatile boolean consideringReplacedDataType = false;
|
||||
|
||||
@Override
|
||||
public void dataTypeReplaced(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath,
|
||||
DataType newDataType) {
|
||||
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
if (dtm != originalDTM) {
|
||||
return; // Different DTM than the one for this data type.
|
||||
}
|
||||
@ -1441,64 +1571,64 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
return;
|
||||
}
|
||||
|
||||
String dtName = oldPath.getDataTypeName();
|
||||
DataTypePath dtPath = new DataTypePath(newDataType.getCategoryPath(), dtName);
|
||||
if (!dtPath.equals(originalDataTypePath)) {
|
||||
DataType dt = viewDTM.getDataType(dtPath);
|
||||
if (!oldPath.equals(originalDataTypePath)) {
|
||||
// Check for type which may be referenced by viewComposite
|
||||
DataType dt = viewDTM.getDataType(oldPath);
|
||||
if (dt != null) {
|
||||
if (hasSubDt(viewComposite, dtPath)) {
|
||||
String msg = "Replaced data type \"" + dtPath +
|
||||
if (hasSubDt(viewComposite, oldPath)) {
|
||||
String msg = "Replaced data type \"" + oldPath +
|
||||
"\", which is a sub-component of \"" + getOriginalDataTypeName() + "\".";
|
||||
setStatus(msg, true);
|
||||
}
|
||||
// NOTE: depending upon event sequence and handling a
|
||||
// re-load may have occurred and replacement may be unnecessary
|
||||
try {
|
||||
viewDTM.replaceDataType(dt, newDataType, true);
|
||||
viewDTM.withTransaction("Replaced Dependency", () -> {
|
||||
viewDTM.clearUndoOnChange();
|
||||
viewDTM.replaceDataType(dt, newDataType, true);
|
||||
});
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new AssertException(e);
|
||||
}
|
||||
|
||||
// Clear undo/redo stack to avoid inconsistency with originalDTM
|
||||
viewDTM.clearUndo();
|
||||
|
||||
fireTableDataChanged();
|
||||
componentDataChanged();
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (this.hadChanges) {
|
||||
if (originalDataTypePath.equals(oldPath)) {
|
||||
if (hadChanges) {
|
||||
consideringReplacedDataType = true;
|
||||
try {
|
||||
String message =
|
||||
"<html>" + HTMLUtilities.escapeHTML(oldPath.getPath()) +
|
||||
" has changed outside the editor.<br>" +
|
||||
"Discard edits & reload the " + getTypeName() + "?";
|
||||
String title = "Reload " + getTypeName() + " Editor?";
|
||||
int response = OptionDialog.showYesNoDialogWithNoAsDefaultButton(
|
||||
provider.getComponent(), title, message);
|
||||
if (response == OptionDialog.OPTION_ONE) {
|
||||
load(getOriginalComposite());
|
||||
}
|
||||
}
|
||||
finally {
|
||||
consideringReplacedDataType = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
load(getOriginalComposite());
|
||||
setStatus(viewComposite.getPathName() + " changed outside the editor.",
|
||||
false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
String msg = "\"" + oldPath.getPath() + "\" was replaced with " +
|
||||
newDataType.getPathName() + " in the data type manager.";
|
||||
setStatus(msg, true);
|
||||
|
||||
consideringReplacedDataType = true;
|
||||
try {
|
||||
provider.show();
|
||||
|
||||
if (hasChanges) {
|
||||
String message = "<html>" + HTMLUtilities.escapeHTML(oldPath.getPath()) +
|
||||
" has been replaced outside the editor.<br>" +
|
||||
"Discard edits and close?</html>";
|
||||
String title = "Close " + getTypeName() + " Editor?";
|
||||
int response = OptionDialog.showYesNoDialogWithNoAsDefaultButton(
|
||||
provider.getComponent(), title, message);
|
||||
if (response != OptionDialog.OPTION_ONE) {
|
||||
compositeInfoChanged();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
load((Composite) newDataType);
|
||||
String message = "<html>" + HTMLUtilities.escapeHTML(oldPath.getPath()) +
|
||||
" has been replaced outside the editor.</html>";
|
||||
Msg.showWarn(this, provider.getComponent(), "Closing " + getTypeName() + " Editor",
|
||||
message);
|
||||
}
|
||||
|
||||
// fast close, discard any changes
|
||||
provider.closeComponent(true);
|
||||
}
|
||||
finally {
|
||||
consideringReplacedDataType = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1635,20 +1765,20 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
}
|
||||
Composite oldComposite = getOriginalComposite();
|
||||
if (oldComposite == null) {
|
||||
hadChanges = false;
|
||||
return hadChanges;
|
||||
hasChanges = false;
|
||||
return hasChanges;
|
||||
}
|
||||
|
||||
PackingType packingType = getPackingType();
|
||||
AlignmentType alignmentType = getAlignmentType();
|
||||
|
||||
hadChanges = (packingType != oldComposite.getPackingType()) ||
|
||||
hasChanges = (packingType != oldComposite.getPackingType()) ||
|
||||
(alignmentType != oldComposite.getAlignmentType()) ||
|
||||
(packingType == PackingType.EXPLICIT &&
|
||||
getExplicitPackingValue() != oldComposite.getExplicitPackingValue()) ||
|
||||
(alignmentType == AlignmentType.EXPLICIT &&
|
||||
getExplicitMinimumAlignment() != oldComposite.getExplicitMinimumAlignment());
|
||||
return hadChanges;
|
||||
return hasChanges;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1664,26 +1794,28 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
}
|
||||
|
||||
public void setAlignmentType(AlignmentType alignmentType, int explicitValue) {
|
||||
AlignmentType currentAlignType = getAlignmentType();
|
||||
if (alignmentType == AlignmentType.DEFAULT) {
|
||||
if (currentAlignType == AlignmentType.DEFAULT) {
|
||||
return;
|
||||
viewDTM.withTransaction("Set Alignment", () -> {
|
||||
AlignmentType currentAlignType = getAlignmentType();
|
||||
if (alignmentType == AlignmentType.DEFAULT) {
|
||||
if (currentAlignType == AlignmentType.DEFAULT) {
|
||||
return;
|
||||
}
|
||||
viewComposite.setToDefaultAligned();
|
||||
}
|
||||
viewComposite.setToDefaultAligned();
|
||||
}
|
||||
else if (alignmentType == AlignmentType.MACHINE) {
|
||||
if (currentAlignType == AlignmentType.MACHINE) {
|
||||
return;
|
||||
else if (alignmentType == AlignmentType.MACHINE) {
|
||||
if (currentAlignType == AlignmentType.MACHINE) {
|
||||
return;
|
||||
}
|
||||
viewComposite.setToMachineAligned();
|
||||
}
|
||||
viewComposite.setToMachineAligned();
|
||||
}
|
||||
else {
|
||||
if (currentAlignType == AlignmentType.EXPLICIT &&
|
||||
explicitValue == viewComposite.getExplicitMinimumAlignment()) {
|
||||
return;
|
||||
else {
|
||||
if (currentAlignType == AlignmentType.EXPLICIT &&
|
||||
explicitValue == viewComposite.getExplicitMinimumAlignment()) {
|
||||
return;
|
||||
}
|
||||
viewComposite.setExplicitMinimumAlignment(explicitValue);
|
||||
}
|
||||
viewComposite.setExplicitMinimumAlignment(explicitValue);
|
||||
}
|
||||
});
|
||||
if (fixSelection()) {
|
||||
selectionChanged();
|
||||
}
|
||||
@ -1703,26 +1835,28 @@ public abstract class CompEditorModel extends CompositeEditorModel {
|
||||
}
|
||||
|
||||
public void setPackingType(PackingType packingType, int explicitValue) {
|
||||
PackingType currentPacktype = getPackingType();
|
||||
if (packingType == PackingType.DISABLED) {
|
||||
if (currentPacktype == PackingType.DISABLED) {
|
||||
return;
|
||||
viewDTM.withTransaction("Set Packing", () -> {
|
||||
PackingType currentPacktype = getPackingType();
|
||||
if (packingType == PackingType.DISABLED) {
|
||||
if (currentPacktype == PackingType.DISABLED) {
|
||||
return;
|
||||
}
|
||||
viewComposite.setPackingEnabled(false);
|
||||
}
|
||||
viewComposite.setPackingEnabled(false);
|
||||
}
|
||||
else if (packingType == PackingType.DEFAULT) {
|
||||
if (currentPacktype == PackingType.DEFAULT) {
|
||||
return;
|
||||
else if (packingType == PackingType.DEFAULT) {
|
||||
if (currentPacktype == PackingType.DEFAULT) {
|
||||
return;
|
||||
}
|
||||
viewComposite.setToDefaultPacking();
|
||||
}
|
||||
viewComposite.setToDefaultPacking();
|
||||
}
|
||||
else {
|
||||
if (currentPacktype == PackingType.EXPLICIT &&
|
||||
explicitValue == viewComposite.getExplicitPackingValue()) {
|
||||
return;
|
||||
else {
|
||||
if (currentPacktype == PackingType.EXPLICIT &&
|
||||
explicitValue == viewComposite.getExplicitPackingValue()) {
|
||||
return;
|
||||
}
|
||||
viewComposite.setExplicitPackingValue(explicitValue);
|
||||
}
|
||||
viewComposite.setExplicitPackingValue(explicitValue);
|
||||
}
|
||||
});
|
||||
if (fixSelection()) {
|
||||
selectionChanged();
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* 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.
|
||||
@ -19,51 +18,44 @@ package ghidra.app.plugin.core.compositeeditor;
|
||||
/**
|
||||
* Adapter for a composite editor model listener.
|
||||
*/
|
||||
public class CompositeEditorModelAdapter
|
||||
implements CompositeEditorModelListener {
|
||||
public class CompositeEditorModelAdapter implements CompositeEditorModelListener {
|
||||
|
||||
public CompositeEditorModelAdapter() {
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.app.plugin.compositeeditor.CompositeEditorModelListener#compositeEditStateChanged(int)
|
||||
*/
|
||||
@Override
|
||||
public void compositeEditStateChanged(int type) {
|
||||
// do nothing by default
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.app.plugin.compositeeditor.CompositeEditorModelListener#endFieldEditing()
|
||||
*/
|
||||
@Override
|
||||
public void endFieldEditing() {
|
||||
// do nothing by default
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.app.plugin.compositeeditor.CompositeViewerModelListener#componentDataChanged()
|
||||
*/
|
||||
@Override
|
||||
public void componentDataChanged() {
|
||||
// do nothing by default
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.app.plugin.compositeeditor.CompositeViewerModelListener#compositeInfoChanged()
|
||||
*/
|
||||
@Override
|
||||
public void compositeInfoChanged() {
|
||||
// do nothing by default
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.app.plugin.compositeeditor.CompositeViewerModelListener#statusChanged(java.lang.String, boolean)
|
||||
*/
|
||||
@Override
|
||||
public void statusChanged(String message, boolean beep) {
|
||||
// do nothing by default
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.app.plugin.compositeeditor.CompositeViewerModelListener#selectionChanged()
|
||||
*/
|
||||
@Override
|
||||
public void selectionChanged() {
|
||||
// do nothing by default
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showUndefinedStateChanged(boolean showUndefinedBytes) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
// do nothing by default
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,12 +30,13 @@ import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.table.*;
|
||||
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;
|
||||
import docking.widgets.DropDownSelectionTextField;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.fieldpanel.support.FieldRange;
|
||||
import docking.widgets.fieldpanel.support.FieldSelection;
|
||||
import docking.widgets.label.GDLabel;
|
||||
@ -50,8 +51,6 @@ import ghidra.framework.plugintool.Plugin;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Composite;
|
||||
import ghidra.program.model.listing.DataTypeArchive;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.data.DataTypeParser.AllowedDataTypes;
|
||||
import ghidra.util.exception.UsrException;
|
||||
@ -121,6 +120,12 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||
setFocusTraversalPolicyProvider(true);
|
||||
}
|
||||
|
||||
abstract protected boolean hasUncomittedEntry();
|
||||
|
||||
abstract protected boolean hasInvalidEntry();
|
||||
|
||||
abstract protected void comitEntryChanges();
|
||||
|
||||
/**
|
||||
* Returns a list of focus traversal components. This list will be used to navigate forward
|
||||
* and backward when the Tab and Shift-Tab keys are pressed. The components will be traversed
|
||||
@ -167,11 +172,10 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||
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 -> {
|
||||
model.notifyCompositeChanged();
|
||||
});
|
||||
provider.dtmService, modelRow, model.showHexNumbers,
|
||||
ordinal -> refreshTableAndSelection(editorModel, ordinal));
|
||||
Component c = provider.getComponent();
|
||||
DockingWindowManager.showDialog(c, dlg);
|
||||
return true;
|
||||
@ -180,6 +184,11 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||
return false;
|
||||
}
|
||||
|
||||
private void refreshTableAndSelection(CompEditorModel editorModel, int ordinal) {
|
||||
editorModel.notifyCompositeChanged();
|
||||
editorModel.setSelection(new int[] { ordinal, ordinal });
|
||||
}
|
||||
|
||||
private void setupTableCellEditor() {
|
||||
|
||||
table.addPropertyChangeListener("tableCellEditor", evt -> {
|
||||
@ -546,63 +555,6 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||
}
|
||||
}
|
||||
|
||||
protected void dataTypeManagerRestored() {
|
||||
DataTypeManager originalDTM = model.getOriginalDataTypeManager();
|
||||
if (originalDTM == null) {
|
||||
// editor unloaded
|
||||
return;
|
||||
}
|
||||
boolean reload = true;
|
||||
String objectType;
|
||||
if (originalDTM instanceof ProgramBasedDataTypeManager) {
|
||||
objectType = "Program";
|
||||
}
|
||||
else {
|
||||
objectType = "Archive";
|
||||
}
|
||||
String archiveName = originalDTM.getName();
|
||||
DataType dt = originalDTM.getDataType(model.getCompositeID());
|
||||
if (dt instanceof Composite) {
|
||||
Composite composite = (Composite) dt;
|
||||
String origDtPath = composite.getPathName();
|
||||
if (!origDtPath.equals(model.getOriginalDataTypePath().getPath())) {
|
||||
model.fixupOriginalPath(composite);
|
||||
}
|
||||
}
|
||||
Composite originalDt = model.getOriginalComposite();
|
||||
if (originalDt == null) {
|
||||
provider.show();
|
||||
String info = "The " + objectType + " \"" + archiveName + "\" has been restored.\n" +
|
||||
"\"" + model.getCompositeName() + "\" may no longer exist outside the editor.";
|
||||
Msg.showWarn(this, this, objectType + " Restored", info);
|
||||
return;
|
||||
}
|
||||
else if (originalDt.isDeleted()) {
|
||||
cancelCellEditing(); // Make sure a field isn't being edited.
|
||||
provider.dispose(); // Close the editor.
|
||||
return;
|
||||
}
|
||||
else if (model.hasChanges()) {
|
||||
provider.show();
|
||||
// The user has modified the structure so prompt for whether or
|
||||
// not to reload the structure.
|
||||
String question =
|
||||
"The " + objectType + " \"" + archiveName + "\" has been restored.\n" + "\"" +
|
||||
model.getCompositeName() + "\" may have changed outside the editor.\n" +
|
||||
"Discard edits & reload the " + model.getTypeName() + "?";
|
||||
String title = "Reload " + model.getTypeName() + " Editor?";
|
||||
int response = OptionDialog.showYesNoDialogWithNoAsDefaultButton(this, title, question);
|
||||
if (response != 1) {
|
||||
reload = false;
|
||||
}
|
||||
}
|
||||
if (reload) {
|
||||
cancelCellEditing(); // Make sure a field isn't being edited.
|
||||
model.load(originalDt); // reload the structure
|
||||
model.updateAndCheckChangeState();
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
if (isVisible()) {
|
||||
setVisible(false);
|
||||
@ -737,7 +689,7 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||
*/
|
||||
public void setStatus(String status) {
|
||||
|
||||
if (status == null) {
|
||||
if (StringUtils.isEmpty(status)) {
|
||||
// Setting the text to null causes the label's preferred height to drop to 0, causing
|
||||
// the UI to change size, depending on whether there was an existing status or not.
|
||||
// Using the empty string prevents the UI layout from changing as the status changes.
|
||||
@ -906,6 +858,7 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||
catch (UsrException e) {
|
||||
model.setStatus(e.getMessage(), true);
|
||||
}
|
||||
provider.contextChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -964,9 +917,11 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||
switch (type) {
|
||||
case COMPOSITE_LOADED:
|
||||
cancelCellEditing(); // Make sure a field isn't being edited.
|
||||
provider.updateTitle();
|
||||
break;
|
||||
case NO_COMPOSITE_LOADED:
|
||||
cancelCellEditing(); // Make sure a field isn't being edited.
|
||||
provider.updateTitle();
|
||||
break;
|
||||
case COMPOSITE_MODIFIED:
|
||||
case COMPOSITE_UNMODIFIED:
|
||||
@ -1335,7 +1290,7 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||
fireEditingCanceled(); // user picked the same datatype
|
||||
}
|
||||
else {
|
||||
dt = model.resolve(dataType);
|
||||
dt = dataType;
|
||||
fireEditingStopped();
|
||||
}
|
||||
}
|
||||
@ -1622,4 +1577,5 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -162,10 +162,14 @@ public abstract class CompositeEditorProvider extends ComponentProviderAdapter
|
||||
|
||||
@Override
|
||||
public void closeComponent() {
|
||||
closeComponent(false);
|
||||
}
|
||||
|
||||
void closeComponent(boolean force) {
|
||||
if (editorModel != null && editorModel.editingField) {
|
||||
editorModel.endFieldEditing();
|
||||
}
|
||||
if (saveChanges(true) != 0) {
|
||||
if (force || saveChanges(true) != 0) {
|
||||
super.closeComponent();
|
||||
dispose();
|
||||
}
|
||||
@ -262,10 +266,6 @@ public abstract class CompositeEditorProvider extends ComponentProviderAdapter
|
||||
return editorModel.hasChanges();
|
||||
}
|
||||
|
||||
public void dataTypeManagerRestored() {
|
||||
editorPanel.dataTypeManagerRestored();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
tool.showComponentProvider(this, true);
|
||||
|
@ -30,7 +30,15 @@ import ghidra.util.HelpLocation;
|
||||
* <p>
|
||||
* Note: Any new actions must be registered in the editor manager via the actions's name.
|
||||
*/
|
||||
abstract public class CompositeEditorTableAction extends DockingAction implements EditorAction {
|
||||
abstract public class CompositeEditorTableAction extends DockingAction
|
||||
implements CompositeEditorModelListener {
|
||||
|
||||
static final String MAIN_ACTION_GROUP = "0_MAIN_EDITOR_ACTION";
|
||||
static final String UNDOREDO_ACTION_GROUP = "1_UNDOREDO_EDITOR_ACTION";
|
||||
static final String BASIC_ACTION_GROUP = "2_BASIC_EDITOR_ACTION";
|
||||
static final String DATA_ACTION_GROUP = "3_DATA_EDITOR_ACTION";
|
||||
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;
|
||||
@ -86,46 +94,47 @@ abstract public class CompositeEditorTableAction extends DockingAction implement
|
||||
tool = null;
|
||||
}
|
||||
|
||||
protected boolean hasIncompleteFieldEntry() {
|
||||
return provider.editorPanel.hasInvalidEntry() || provider.editorPanel.hasUncomittedEntry();
|
||||
}
|
||||
|
||||
protected void requestTableFocus() {
|
||||
if (provider != null) {
|
||||
provider.requestTableFocus();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
abstract public void adjustEnablement();
|
||||
|
||||
public String getHelpName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectionChanged() {
|
||||
adjustEnablement();
|
||||
provider.contextChanged();
|
||||
}
|
||||
|
||||
public void editStateChanged(int i) {
|
||||
adjustEnablement();
|
||||
provider.contextChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compositeEditStateChanged(int type) {
|
||||
adjustEnablement();
|
||||
provider.contextChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endFieldEditing() {
|
||||
adjustEnablement();
|
||||
provider.contextChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentDataChanged() {
|
||||
adjustEnablement();
|
||||
provider.contextChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compositeInfoChanged() {
|
||||
adjustEnablement();
|
||||
provider.contextChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -135,7 +144,7 @@ abstract public class CompositeEditorTableAction extends DockingAction implement
|
||||
|
||||
@Override
|
||||
public void showUndefinedStateChanged(boolean showUndefinedBytes) {
|
||||
adjustEnablement();
|
||||
provider.contextChanged();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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,36 +16,109 @@
|
||||
package ghidra.app.plugin.core.compositeeditor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import db.util.ErrorHandler;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.ProgramArchitecture;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import utility.function.Callback;
|
||||
|
||||
public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager {
|
||||
/**
|
||||
* {@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
|
||||
* indirectly referenced datatypes. This manager also facilitates undo/redo support within
|
||||
* the editor.
|
||||
*/
|
||||
public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager
|
||||
implements ErrorHandler {
|
||||
|
||||
/**
|
||||
* The data type manager for original composite data type being edited.
|
||||
* This is where the edited datatype will be written back to.
|
||||
*/
|
||||
private final DataTypeManager originalDTM;
|
||||
private final Composite originalComposite;
|
||||
private final Composite viewComposite;
|
||||
private final int transactionID;
|
||||
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
|
||||
|
||||
// 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
|
||||
private Callback restoredCallback;
|
||||
private int transactionId = 0;
|
||||
|
||||
// Modification count used to signal optional clearing of undo/redo stack at the end of a
|
||||
// transaction should any database modifications occur.
|
||||
private long flattenModCount = -1;
|
||||
|
||||
// datatype IDs to be checked as orphaned.
|
||||
// NOTE: Orphan removal can only be done when this DTM actively manages the viewComposite
|
||||
private TreeSet<Long> orphanIds = new TreeSet<>();
|
||||
|
||||
/**
|
||||
* Creates a data type manager that the structure editor will use
|
||||
* internally for updating the structure being edited.
|
||||
* 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
|
||||
* not be supported.
|
||||
* @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. (cannot be null).
|
||||
* @param originalDTM the original data type manager.
|
||||
*/
|
||||
public CompositeViewerDataTypeManager(String rootName, Composite originalComposite) {
|
||||
super(rootName, originalComposite.getDataTypeManager().getDataOrganization());
|
||||
this.originalComposite = originalComposite;
|
||||
transactionID = super.startTransaction("");
|
||||
originalDTM = originalComposite.getDataTypeManager();
|
||||
public CompositeViewerDataTypeManager(String rootName, DataTypeManager originalDTM) {
|
||||
this(rootName, originalDTM, null, null);
|
||||
clearUndo();
|
||||
transactionId = startTransaction("Composite Edit");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a data type manager that the structure editor will use internally for managing a
|
||||
* 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 restoredCallback Callback will be invoked following any undo/redo.
|
||||
*/
|
||||
public CompositeViewerDataTypeManager(String rootName, Composite originalComposite,
|
||||
Callback restoredCallback) {
|
||||
this(rootName, originalComposite.getDataTypeManager(), originalComposite, restoredCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @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 restoredCallback Callback will be invoked following any undo/redo.
|
||||
*/
|
||||
private CompositeViewerDataTypeManager(String rootName, DataTypeManager originalDTM,
|
||||
Composite originalComposite, Callback restoredCallback) {
|
||||
super(rootName, originalDTM.getDataOrganization());
|
||||
this.originalDTM = originalDTM;
|
||||
this.originalComposite = originalComposite;
|
||||
this.restoredCallback = restoredCallback;
|
||||
|
||||
int txId = startTransaction("Setup for Edit");
|
||||
try {
|
||||
initializeArchitecture();
|
||||
dataTypeIDMap = new IDMapDB(dbHandle, this);
|
||||
viewComposite = resolveViewComposite();
|
||||
}
|
||||
finally {
|
||||
endTransaction(txId, true);
|
||||
}
|
||||
clearUndo();
|
||||
}
|
||||
|
||||
private Composite resolveViewComposite() {
|
||||
return originalComposite != null ? (Composite) super.resolve(originalComposite, null)
|
||||
: null;
|
||||
}
|
||||
|
||||
private void initializeArchitecture() {
|
||||
ProgramArchitecture arch = originalDTM.getProgramArchitecture();
|
||||
if (arch != null) {
|
||||
try {
|
||||
@ -58,8 +131,48 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager {
|
||||
errHandler.dbError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewComposite = (Composite) super.resolve(originalComposite, null);
|
||||
/**
|
||||
* Provides a means of detecting changes to the underlying database during a transaction.
|
||||
* @return current modification count
|
||||
*/
|
||||
public long getModCount() {
|
||||
return dbHandle.getModCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void clearUndo() {
|
||||
// Exposes method for test use
|
||||
super.clearUndo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
dataTypeIDMap.invalidate();
|
||||
super.undo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void redo() {
|
||||
dataTypeIDMap.invalidate();
|
||||
super.redo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the view composite if requested during instantiation.
|
||||
* @return view composite or null if not resolved during instantiation.
|
||||
*/
|
||||
public Composite getResolvedViewComposite() {
|
||||
return viewComposite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if undo/redo is allowed.
|
||||
* @return true if undo/redo is allowed with use of individual transactions, else false
|
||||
*/
|
||||
public boolean isUndoRedoAllowed() {
|
||||
return restoredCallback != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -68,8 +181,10 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
super.endTransaction(transactionID, true);
|
||||
public synchronized void close() {
|
||||
if (transactionId != 0) {
|
||||
super.endTransaction(transactionId, true);
|
||||
}
|
||||
super.close();
|
||||
}
|
||||
|
||||
@ -100,36 +215,203 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager {
|
||||
// DataTypeManager instance.
|
||||
return viewComposite;
|
||||
}
|
||||
return super.resolve(dataType, handler);
|
||||
}
|
||||
|
||||
//
|
||||
// Transaction support has been disabled since a single open transaction is maintained
|
||||
// until this DTM is closed.
|
||||
//
|
||||
|
||||
@SuppressWarnings("sync-override")
|
||||
@Override
|
||||
public int startTransaction(String description) {
|
||||
// ignore - not yet supported
|
||||
return 0;
|
||||
DataType resolvedDt = super.resolve(dataType, handler);
|
||||
if ((dataType instanceof DatabaseObject) && originalDTM.contains(dataType)) {
|
||||
long originalId = originalDTM.getID(dataType);
|
||||
long myId = getID(resolvedDt);
|
||||
dataTypeIDMap.put(myId, originalId);
|
||||
}
|
||||
return resolvedDt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endTransaction(int txId, boolean commit) {
|
||||
// ignore - not yet supported
|
||||
public DataType replaceDataType(DataType existingViewDt, DataType replacementDt,
|
||||
boolean updateCategoryPath) throws DataTypeDependencyException {
|
||||
|
||||
long viewDtId = getID(existingViewDt);
|
||||
|
||||
if (existingViewDt instanceof DatabaseObject) {
|
||||
dataTypeIDMap.remove(viewDtId);
|
||||
}
|
||||
|
||||
DataType newResolvedDt =
|
||||
super.replaceDataType(existingViewDt, replacementDt, updateCategoryPath);
|
||||
|
||||
if (newResolvedDt instanceof DatabaseObject &&
|
||||
replacementDt.getDataTypeManager() == originalDTM) {
|
||||
long originalId = originalDTM.getID(replacementDt);
|
||||
long myId = getID(newResolvedDt);
|
||||
dataTypeIDMap.put(myId, originalId);
|
||||
}
|
||||
|
||||
return newResolvedDt;
|
||||
}
|
||||
|
||||
@SuppressWarnings("sync-override")
|
||||
@Override
|
||||
public boolean canUndo() {
|
||||
return false;
|
||||
public boolean remove(DataType existingViewDt, TaskMonitor monitor) {
|
||||
|
||||
long viewDtId = getID(existingViewDt);
|
||||
|
||||
if (existingViewDt instanceof DatabaseObject) {
|
||||
dataTypeIDMap.remove(viewDtId);
|
||||
}
|
||||
|
||||
return super.remove(existingViewDt, monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh all datatypes which originate from the originalDTM.
|
||||
* This methods is intended for use following an undo/redo of the originalDTM only
|
||||
* and will purge the ID mappings for any datatypes which no longer exist or become
|
||||
* orphaned.
|
||||
* @return true if a dependency change is detected, else false
|
||||
*/
|
||||
public boolean refreshDBTypesFromOriginal() {
|
||||
synchronized (orphanIds) {
|
||||
return withTransaction("DataTypes Restored", () -> {
|
||||
boolean changed = false;
|
||||
clearUndoOnChange();
|
||||
Iterator<DataType> allDataTypes = getAllDataTypes();
|
||||
while (allDataTypes.hasNext()) {
|
||||
DataType dt = allDataTypes.next();
|
||||
if (dt == viewComposite || !(dt instanceof DatabaseObject)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// subject all DB types to orphan check
|
||||
long myId = getID(dt);
|
||||
if (viewComposite != null) {
|
||||
orphanIds.add(myId);
|
||||
}
|
||||
|
||||
Long originalId = dataTypeIDMap.getOriginalIDFromViewID(myId);
|
||||
if (originalId == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DataType originalDt = originalDTM.getDataType(originalId);
|
||||
if (originalDt == null) {
|
||||
changed = true;
|
||||
remove(dt, TaskMonitor.DUMMY);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!originalDt.isEquivalent(dt)) {
|
||||
changed = true;
|
||||
try {
|
||||
originalDt = replaceDataType(dt, originalDt, true);
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new AssertException(e); // should not occur
|
||||
}
|
||||
}
|
||||
|
||||
CategoryPath path = dt.getCategoryPath();
|
||||
if (!originalDt.getCategoryPath().equals(path)) {
|
||||
Category newDtCat = createCategory(path);
|
||||
try {
|
||||
newDtCat.moveDataType(dt, null);
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new AssertException(e); // should not occur
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
checkOrphansForRemoval(true);
|
||||
return changed;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("sync-override")
|
||||
@Override
|
||||
public boolean canRedo() {
|
||||
return false;
|
||||
public void notifyRestored() {
|
||||
super.notifyRestored();
|
||||
if (restoredCallback != null) {
|
||||
restoredCallback.call();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void endTransaction(int transactionID, boolean commit) {
|
||||
|
||||
if (viewComposite != null && getTransactionCount() == 1) {
|
||||
// Perform orphan removal only at the end of the outer-most transaction
|
||||
synchronized (orphanIds) {
|
||||
checkOrphansForRemoval(false);
|
||||
}
|
||||
}
|
||||
|
||||
super.endTransaction(transactionID, commit);
|
||||
|
||||
if (!isTransactionActive() && flattenModCount != -1) {
|
||||
if (flattenModCount != dbHandle.getModCount()) {
|
||||
// Mod count differs from flagged mod count - clean undo/redo
|
||||
clearUndo();
|
||||
}
|
||||
flattenModCount = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkOrphansForRemoval(boolean cleanupIdMaps) {
|
||||
while (!orphanIds.isEmpty()) {
|
||||
long id = orphanIds.removeFirst();
|
||||
if (!hasParent(id)) {
|
||||
DataType dt = getDataType(id);
|
||||
if (dt instanceof DatabaseObject) {
|
||||
|
||||
if (dt == viewComposite) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check all children of the datatype which may become orphaned
|
||||
orphanIds.addAll(getChildIds(id));
|
||||
|
||||
// Remove orphan DB datatype
|
||||
remove(dt, TaskMonitor.DUMMY);
|
||||
|
||||
if (cleanupIdMaps) {
|
||||
dataTypeIDMap.remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag the next transaction end to check for subsequent database modifications
|
||||
* and clear undo/redo stack if changes are detected. This call is ignored if
|
||||
* there is already a pending check.
|
||||
*/
|
||||
public synchronized void clearUndoOnChange() {
|
||||
if (flattenModCount == -1) {
|
||||
flattenModCount = dbHandle.getModCount();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeParentChildRecord(long parentID, long childID) {
|
||||
// assume lock is in use
|
||||
super.removeParentChildRecord(parentID, childID);
|
||||
|
||||
if (viewComposite != null) {
|
||||
synchronized (orphanIds) {
|
||||
if (!hasParent(childID)) {
|
||||
// assumes if parent is removed it will not be re-added durig same transaction
|
||||
orphanIds.add(childID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DataType findOriginalDataTypeFromMyID(long myId) {
|
||||
Long originalId = dataTypeIDMap.getOriginalIDFromViewID(myId);
|
||||
return originalId != null ? originalDTM.getDataType(originalId) : null;
|
||||
}
|
||||
|
||||
public DataType findMyDataTypeFromOriginalID(long originalId) {
|
||||
Long myId = dataTypeIDMap.getViewIDFromOriginalID(originalId);
|
||||
return myId != null ? getDataType(myId) : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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,9 +24,9 @@ import javax.swing.table.TableColumn;
|
||||
|
||||
import docking.widgets.fieldpanel.support.FieldRange;
|
||||
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;
|
||||
@ -43,9 +43,10 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
protected Composite originalComposite;
|
||||
protected DataTypePath originalDataTypePath;
|
||||
protected long originalCompositeId;
|
||||
protected DataTypeManager originalDTM;
|
||||
|
||||
protected Composite viewComposite;
|
||||
protected DataTypeManager viewDTM;
|
||||
protected CompositeViewerDataTypeManager viewDTM;
|
||||
|
||||
private List<CompositeViewerModelListener> modelListeners = new ArrayList<>();
|
||||
|
||||
@ -75,9 +76,9 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
/** Width of left margin in pixels for the component area. */
|
||||
protected int leftMargin = 10;
|
||||
/** the current row for a field edit */
|
||||
protected int row = -1;
|
||||
protected int currentEditRow = -1;
|
||||
/** the current column for a field edit */
|
||||
protected int column = -1;
|
||||
protected int currentEditColumn = -1;
|
||||
protected CompositeEditorProvider provider;
|
||||
protected boolean showHexNumbers = false;
|
||||
|
||||
@ -134,7 +135,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
/**
|
||||
* Terminates listening for category change events within the model.
|
||||
*/
|
||||
void dispose() {
|
||||
protected void dispose() {
|
||||
// Unregister the listeners.
|
||||
// No longer want to listen for changes to previous category.
|
||||
unload();
|
||||
@ -164,7 +165,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
*
|
||||
* @param dataType the composite date type to be viewed.
|
||||
*/
|
||||
abstract void load(Composite dataType);
|
||||
protected abstract void load(Composite dataType);
|
||||
|
||||
/**
|
||||
* Unloads the currently loaded composite data type.
|
||||
@ -174,14 +175,13 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
* a new composite data type.
|
||||
*/
|
||||
void unload() {
|
||||
DataTypeManager originalDTM =
|
||||
(originalComposite != null) ? originalComposite.getDataTypeManager() : null;
|
||||
// Unregister the listeners.
|
||||
// No longer want to listen for changes to previous category.
|
||||
if (originalDTM != null) {
|
||||
originalDTM.removeDataTypeManagerListener(this);
|
||||
originalDTM = null;
|
||||
}
|
||||
originalDTM = null;
|
||||
originalComposite = null;
|
||||
originalCompositeId = DataTypeManager.NULL_DATATYPE_ID;
|
||||
viewComposite = null;
|
||||
@ -192,16 +192,34 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the data type against the indicated data type manager using the specified
|
||||
* conflictHandler. In general, a transaction should have already been initiated prior to
|
||||
* calling this method so that the true nature of the transaction may be established for
|
||||
* use with undo/redo (e.g., Set Datatype).
|
||||
*
|
||||
* @param dataType the data type to be resolved
|
||||
* @param resolveDtm the data type manager to resolve the data type against
|
||||
* @param conflictHandler the handler to be used for any conflicts encountered while resolving
|
||||
* @return the resolved data type
|
||||
*/
|
||||
protected final DataType resolveDataType(DataType dataType, DataTypeManager resolveDtm,
|
||||
DataTypeConflictHandler conflictHandler) {
|
||||
if (resolveDtm == null || dataType == DataType.DEFAULT) {
|
||||
return DataType.DEFAULT;
|
||||
}
|
||||
return resolveDtm.withTransaction("Resolve " + dataType.getPathName(), () -> {
|
||||
return resolveDtm.resolve(dataType, conflictHandler);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the indicated data type against the working copy in the viewer's data type manager.
|
||||
* @param dataType the data type
|
||||
* @return the working copy of the data type.
|
||||
*/
|
||||
DataType resolve(DataType dataType) {
|
||||
if (viewDTM == null) {
|
||||
return DataType.DEFAULT;
|
||||
}
|
||||
return viewDTM.resolve(dataType, null);
|
||||
public DataType resolve(DataType dataType) {
|
||||
return resolveDataType(dataType, viewDTM, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -209,7 +227,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
* @return the current row
|
||||
*/
|
||||
public int getRow() {
|
||||
return row;
|
||||
return currentEditRow;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -217,7 +235,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
* @param row the new row
|
||||
*/
|
||||
public void setRow(int row) {
|
||||
this.row = row;
|
||||
this.currentEditRow = row;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -225,7 +243,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
* @return the current column
|
||||
*/
|
||||
public int getColumn() {
|
||||
return column;
|
||||
return currentEditColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -239,7 +257,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
return;
|
||||
}
|
||||
|
||||
this.column = column;
|
||||
this.currentEditColumn = column;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -248,23 +266,43 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
* @param column the new column
|
||||
*/
|
||||
protected void setLocation(int row, int column) {
|
||||
this.row = row;
|
||||
this.column = column;
|
||||
this.currentEditRow = row;
|
||||
this.currentEditColumn = column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the original CompositeDataType that was used to construct this.
|
||||
* @return the original composite being viewed or null if it doesn't exist.
|
||||
* Returns the original Composite DataType that currently exists within the original
|
||||
* DataTypeManager, or if not found the instance originally loaded.
|
||||
* @return the original composite being viewed or null if nothing is currently loaded in
|
||||
* the model.
|
||||
*/
|
||||
protected Composite getOriginalComposite() {
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
if (originalDataTypePath != null && originalDTM != null) {
|
||||
DataType dt = originalDTM.getDataType(originalDataTypePath);
|
||||
if (dt instanceof Composite) {
|
||||
Composite existingOriginal = getExistingOriginalComposite();
|
||||
return existingOriginal != null ? existingOriginal : originalComposite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the original composite exists within the original datatype manager.
|
||||
* NOTE: If this method returns true, the current datatype which exists within the original
|
||||
* datatype manager will be returned by {@link #getOriginalComposite()}, although its name
|
||||
* may differ.
|
||||
* @return true if datatype found else false
|
||||
*/
|
||||
protected boolean originalCompositeExists() {
|
||||
return getExistingOriginalComposite() != null;
|
||||
}
|
||||
|
||||
private Composite 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 originalComposite;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -280,7 +318,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
* @return the manager
|
||||
*/
|
||||
protected DataTypeManager getOriginalDataTypeManager() {
|
||||
return (originalComposite != null) ? originalComposite.getDataTypeManager() : null;
|
||||
return originalDTM;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -288,7 +326,6 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
* @return the category
|
||||
*/
|
||||
public final Category getOriginalCategory() {
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
if (originalDataTypePath != null && originalDTM != null) {
|
||||
CategoryPath originalCategoryPath = originalDataTypePath.getCategoryPath();
|
||||
if (originalDTM.containsCategory(originalCategoryPath)) {
|
||||
@ -346,7 +383,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
* Return the data type name of the structure being viewed
|
||||
* @return the name
|
||||
*/
|
||||
public String getCompositeName() {
|
||||
protected String getCompositeName() {
|
||||
return (viewComposite != null) ? viewComposite.getDisplayName() : "";
|
||||
}
|
||||
|
||||
@ -587,12 +624,10 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current dataType name (Structure or Union) as a string.
|
||||
* @return the name
|
||||
* Returns the current dataType name (Structure, Union, etc.) as a string.
|
||||
* @return the type of composite being edited
|
||||
*/
|
||||
protected String getTypeName() {
|
||||
return "Composite Data Type";
|
||||
}
|
||||
public abstract String getTypeName();
|
||||
|
||||
/**
|
||||
* Returns the current status string.
|
||||
@ -635,26 +670,6 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
setStatus(status, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes up the original name and category because a program restoration may have changed the
|
||||
* original composite.
|
||||
* @param composite the restored copy of our original composite
|
||||
*/
|
||||
protected void fixupOriginalPath(Composite composite) {
|
||||
String newName = composite.getName();
|
||||
CategoryPath newCatPath = composite.getCategoryPath();
|
||||
CategoryPath oldCatPath = viewComposite.getCategoryPath();
|
||||
DataTypePath newDtPath = new DataTypePath(newCatPath, composite.getName());
|
||||
DataTypePath oldDtPath = new DataTypePath(oldCatPath, viewComposite.getName());
|
||||
|
||||
if (!oldCatPath.equals(newCatPath)) {
|
||||
dataTypeMoved(viewDTM, oldDtPath, newDtPath);
|
||||
}
|
||||
if (!originalDataTypePath.getDataTypeName().equals(newName)) {
|
||||
dataTypeRenamed(viewDTM, oldDtPath, newDtPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a CompositeViewerModelListener to be notified when model changes occur
|
||||
* @param listener the listener
|
||||
@ -713,7 +728,6 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
|
||||
@Override
|
||||
public void categoryRemoved(DataTypeManager dtm, CategoryPath path) {
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
if (dtm != originalDTM) {
|
||||
return; // Different DTM than the one for this data type.
|
||||
}
|
||||
@ -739,7 +753,6 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
|
||||
@Override
|
||||
public void categoryRenamed(DataTypeManager dtm, CategoryPath oldPath, CategoryPath newPath) {
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
if (dtm != originalDTM) {
|
||||
return; // Different DTM than the one for this data type.
|
||||
}
|
||||
@ -747,24 +760,27 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
return;
|
||||
}
|
||||
Category oldCat = viewDTM.getCategory(oldPath);
|
||||
try {
|
||||
oldCat.setName(newPath.getName());
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||
}
|
||||
catch (InvalidNameException e) {
|
||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||
}
|
||||
if (originalDataTypePath.isAncestor(oldPath)) {
|
||||
changeOriginalDataTypeCategory(oldPath, newPath);
|
||||
}
|
||||
viewDTM.withTransaction("Category Renamed", () -> {
|
||||
viewDTM.clearUndoOnChange();
|
||||
try {
|
||||
oldCat.setName(newPath.getName());
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||
}
|
||||
catch (InvalidNameException e) {
|
||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||
}
|
||||
if (originalDataTypePath.isAncestor(oldPath)) {
|
||||
changeOriginalDataTypeCategory(oldPath, newPath);
|
||||
}
|
||||
});
|
||||
|
||||
compositeInfoChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void categoryMoved(DataTypeManager dtm, CategoryPath oldPath, CategoryPath newPath) {
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
if (dtm != originalDTM) {
|
||||
return; // Different DTM than the one for this data type.
|
||||
}
|
||||
@ -776,14 +792,17 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
return;
|
||||
}
|
||||
CategoryPath parent = newPath.getParent();
|
||||
viewDTM.createCategory(parent);
|
||||
Category newCat = viewDTM.getCategory(parent);
|
||||
try {
|
||||
newCat.moveCategory(oldCat, TaskMonitor.DUMMY);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||
}
|
||||
viewDTM.withTransaction("Category Moved", () -> {
|
||||
viewDTM.clearUndoOnChange();
|
||||
viewDTM.createCategory(parent);
|
||||
Category newCat = viewDTM.getCategory(parent);
|
||||
try {
|
||||
newCat.moveCategory(oldCat, TaskMonitor.DUMMY);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
if (originalDataTypePath.isAncestor(oldPath)) {
|
||||
changeOriginalDataTypeCategory(oldPath, newPath);
|
||||
}
|
||||
@ -795,165 +814,6 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
// Adding a new data type doesn't affect this one?
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeRemoved(DataTypeManager dtm, DataTypePath path) {
|
||||
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
if (dtm != originalDTM) {
|
||||
return; // Different DTM than the one for this data type.
|
||||
}
|
||||
|
||||
DataType dataType = viewDTM.getDataType(path.getCategoryPath(), path.getDataTypeName());
|
||||
if (dataType == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
DataType baseDt = DataTypeHelper.getBaseType(dataType);
|
||||
DataTypePath dtPath = new DataTypePath(path.getCategoryPath(), baseDt.getName());
|
||||
if (!dtPath.equals(originalDataTypePath)) {
|
||||
DataType dt = viewDTM.getDataType(dtPath);
|
||||
if (dt != null) {
|
||||
if (hasSubDt(viewComposite, dtPath)) {
|
||||
String msg = "Removed sub-component data type \"" + dtPath;
|
||||
setStatus(msg, true);
|
||||
}
|
||||
viewDTM.remove(dt, TaskMonitor.DUMMY);
|
||||
// If a datatype we are using is removed, change it to undefined data types.
|
||||
fireTableDataChanged();
|
||||
componentDataChanged();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!dataType.equals(baseDt)) {
|
||||
return; // ignore typedefs, arrays, and pointers of the Datatype being edited.
|
||||
}
|
||||
String msg = "\"" + dtPath + "\" was removed from the data type manager.";
|
||||
setStatus(msg, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
|
||||
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
if (dtm != originalDTM) {
|
||||
return; // Different DTM than the one for this data type.
|
||||
}
|
||||
|
||||
DataType dt = viewDTM.getDataType(oldPath);
|
||||
if (dt == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
dt.setName(newPath.getDataTypeName());
|
||||
fireTableDataChanged();
|
||||
componentDataChanged();
|
||||
}
|
||||
catch (InvalidNameException | DuplicateNameException e) {
|
||||
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeMoved(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
|
||||
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
if (dtm != originalDTM) {
|
||||
return; // Different DTM than the one for this data type.
|
||||
}
|
||||
|
||||
DataType dt = viewDTM.getDataType(oldPath);
|
||||
if (dt == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Category newDtCat = viewDTM.createCategory(newPath.getCategoryPath());
|
||||
try {
|
||||
newDtCat.moveDataType(dt, null);
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new AssertException(e);
|
||||
}
|
||||
|
||||
if (originalDataTypePath.getDataTypeName().equals(newPath.getDataTypeName()) &&
|
||||
originalDataTypePath.getCategoryPath().equals(oldPath.getCategoryPath())) {
|
||||
originalDataTypePath = newPath;
|
||||
compositeInfoChanged();
|
||||
}
|
||||
else {
|
||||
fireTableDataChanged();
|
||||
componentDataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeChanged(DataTypeManager dtm, DataTypePath path) {
|
||||
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
if (dtm != originalDTM) {
|
||||
return; // Different DTM than the one for this data type.
|
||||
}
|
||||
|
||||
if (isLoaded()) {
|
||||
if (originalCompositeId != DataTypeManager.NULL_DATATYPE_ID &&
|
||||
path.equals(originalDataTypePath)) {
|
||||
compositeInfoChanged();
|
||||
}
|
||||
else {
|
||||
CategoryPath cat = path.getCategoryPath();
|
||||
viewDTM.createCategory(cat);
|
||||
DataType dt = viewDTM.getDataType(path);
|
||||
if (dt == null) {
|
||||
return;
|
||||
}
|
||||
if (originalDTM != viewDTM) {
|
||||
// update changed datatype
|
||||
DataType dataType = dtm.getDataType(path);
|
||||
viewDTM.resolve(dataType, DataTypeConflictHandler.REPLACE_HANDLER);
|
||||
}
|
||||
fireTableDataChanged();
|
||||
componentDataChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeReplaced(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath,
|
||||
DataType newDataType) {
|
||||
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
if (dtm != originalDTM) {
|
||||
return; // Different DTM than the one for this data type.
|
||||
}
|
||||
|
||||
if (!isLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!oldPath.equals(originalDataTypePath)) { // am I editing the replaced dataType?
|
||||
DataType dt = viewDTM.getDataType(oldPath);
|
||||
if (dt != null) {
|
||||
if (hasSubDt(viewComposite, oldPath)) {
|
||||
String msg = "Replaced sub-component data type \"" + oldPath.getPath();
|
||||
setStatus(msg, true);
|
||||
}
|
||||
try {
|
||||
|
||||
viewDTM.replaceDataType(dt, newDataType, true);
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new AssertException(e);
|
||||
}
|
||||
fireTableDataChanged();
|
||||
componentDataChanged();
|
||||
}
|
||||
}
|
||||
else {
|
||||
load((Composite) newDataType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void favoritesChanged(DataTypeManager dtm, DataTypePath path, boolean isFavorite) {
|
||||
// Don't care.
|
||||
@ -965,9 +825,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restored(DataTypeManager dataTypeManager) {
|
||||
provider.dataTypeManagerRestored();
|
||||
}
|
||||
public abstract void restored(DataTypeManager dataTypeManager);
|
||||
|
||||
//=================================================================================================
|
||||
// Helper methods for CategoryChangeListener methods.
|
||||
@ -1112,7 +970,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
* Returns true if the selection is a single row.
|
||||
* @return true if the selection is a single row
|
||||
*/
|
||||
public boolean isSingleRowSelection() {
|
||||
protected boolean isSingleRowSelection() {
|
||||
if (selection.getNumRanges() != 1) {
|
||||
return false;
|
||||
}
|
||||
@ -1124,7 +982,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
* Returns true if the list selection is contiguous and only contains component rows.
|
||||
* @return true if the list selection is contiguous and only contains component rows
|
||||
*/
|
||||
public boolean isContiguousComponentSelection() {
|
||||
protected boolean isContiguousComponentSelection() {
|
||||
return ((selection.getNumRanges() == 1) &&
|
||||
selection.getFieldRange(0).getStart().getIndex().intValue() < getNumComponents());
|
||||
}
|
||||
@ -1133,7 +991,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
* Get an array of the indices for all the selected rows.
|
||||
* @return the selected rows
|
||||
*/
|
||||
public int[] getSelectedRows() {
|
||||
protected int[] getSelectedRows() {
|
||||
ArrayList<Integer> list = new ArrayList<>();
|
||||
for (FieldRange range : this.selection) {
|
||||
int endIndex = range.getEnd().getIndex().intValue();
|
||||
@ -1149,7 +1007,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
* Get an array of the row indices for all the selected components.
|
||||
* @return the selected rows
|
||||
*/
|
||||
public int[] getSelectedComponentRows() {
|
||||
protected int[] getSelectedComponentRows() {
|
||||
ArrayList<Integer> list = new ArrayList<>();
|
||||
int numComponents = getNumComponents();
|
||||
for (FieldRange range : this.selection) {
|
||||
@ -1169,7 +1027,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
* @param rowIndex the row index
|
||||
* @return the range or null
|
||||
*/
|
||||
public FieldRange getSelectedRangeContaining(int rowIndex) {
|
||||
protected FieldRange getSelectedRangeContaining(int rowIndex) {
|
||||
FieldRange fieldRange = null;
|
||||
if (selection.containsEntirely(BigInteger.valueOf(rowIndex))) {
|
||||
// Get the size of the selection range we are in.
|
||||
@ -1203,7 +1061,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
*
|
||||
* @param rows the indices for the selected rows.
|
||||
*/
|
||||
public void setSelection(int[] rows) {
|
||||
protected void setSelection(int[] rows) {
|
||||
|
||||
if (updatingSelection) {
|
||||
return;
|
||||
@ -1229,7 +1087,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
* it gets adjusted to the empty last line when in unlocked mode.
|
||||
* @param selection the new selection
|
||||
*/
|
||||
public void setSelection(FieldSelection selection) {
|
||||
protected void setSelection(FieldSelection selection) {
|
||||
if (updatingSelection) {
|
||||
return;
|
||||
}
|
||||
@ -1292,7 +1150,7 @@ abstract class CompositeViewerModel extends AbstractTableModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to run the given task on the swing thread now if swing or later if not.
|
||||
* Convenience method to run the given task on the swing thread.
|
||||
* @param r the runnable
|
||||
*/
|
||||
protected void swing(Runnable r) {
|
||||
|
@ -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.
|
||||
@ -40,11 +40,13 @@ public class CreateInternalStructureAction extends CompositeEditorTableAction {
|
||||
public CreateInternalStructureAction(StructureEditorProvider provider) {
|
||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||
setDescription(DESCRIPTION);
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
int[] selectedComponentRows = model.getSelectedComponentRows();
|
||||
boolean hasComponentSelection = model.hasComponentSelection();
|
||||
boolean hasContiguousSelection = model.isContiguousComponentSelection();
|
||||
@ -82,8 +84,8 @@ public class CreateInternalStructureAction extends CompositeEditorTableAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
setEnabled(isCreateInternalStructureAllowed());
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return !hasIncompleteFieldEntry() && isCreateInternalStructureAllowed();
|
||||
}
|
||||
|
||||
private boolean isCreateInternalStructureAllowed() {
|
||||
|
@ -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.
|
||||
@ -57,13 +57,16 @@ public class CycleGroupAction extends CompositeEditorTableAction {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
model.cycleDataType(cycleGroup);
|
||||
requestTableFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
setEnabled(true);
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return !hasIncompleteFieldEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -56,19 +56,6 @@ public class DataTypeHelper {
|
||||
return new String(result, 0, resultIndex);
|
||||
}
|
||||
|
||||
public static DataType resolveDataType(DataType dt, DataTypeManager resolveDtm,
|
||||
DataTypeConflictHandler conflictHandler) {
|
||||
int txID = 0;
|
||||
try {
|
||||
txID = resolveDtm.startTransaction("Apply data type \"" + dt.getName() + "\"");
|
||||
dt = resolveDtm.resolve(dt, conflictHandler);
|
||||
}
|
||||
finally {
|
||||
resolveDtm.endTransaction(txID, (dt != null));
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a data type that was typed in the composite data type editor.
|
||||
* It creates a DataTypeInstance that consists of the data type and its size.
|
||||
|
@ -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.
|
||||
@ -41,11 +41,13 @@ public class DeleteAction extends CompositeEditorTableAction {
|
||||
|
||||
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
||||
setDescription("Delete the selected components");
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
TaskLauncher.launchModal(getName(), this::doDelete);
|
||||
requestTableFocus();
|
||||
}
|
||||
@ -63,7 +65,8 @@ public class DeleteAction extends CompositeEditorTableAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
setEnabled(model.isDeleteAllowed());
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return !hasIncompleteFieldEntry() && model.isDeleteAllowed();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
@ -41,15 +41,16 @@ public class DuplicateAction extends CompositeEditorTableAction {
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.ALT_DOWN_MASK);
|
||||
|
||||
public DuplicateAction(CompositeEditorProvider provider) {
|
||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null,
|
||||
ICON);
|
||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||
setDescription(DESCRIPTION);
|
||||
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
int[] indices = model.getSelectedComponentRows();
|
||||
if (indices.length != 1) {
|
||||
return;
|
||||
@ -69,7 +70,8 @@ public class DuplicateAction extends CompositeEditorTableAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
setEnabled(model.isDuplicateAllowed());
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return !hasIncompleteFieldEntry() && model.isDuplicateAllowed();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
@ -36,8 +36,7 @@ import ghidra.util.task.TaskMonitor;
|
||||
*/
|
||||
public class DuplicateMultipleAction extends CompositeEditorTableAction {
|
||||
|
||||
private final static Icon ICON =
|
||||
new GIcon("icon.plugin.composite.editor.duplicate.multiple");
|
||||
private final static Icon ICON = new GIcon("icon.plugin.composite.editor.duplicate.multiple");
|
||||
public final static String ACTION_NAME = "Duplicate Multiple of Component";
|
||||
private final static String GROUP_NAME = COMPONENT_ACTION_GROUP;
|
||||
private final static String DESCRIPTION = "Duplicate multiple of the selected component";
|
||||
@ -49,11 +48,13 @@ public class DuplicateMultipleAction extends CompositeEditorTableAction {
|
||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||
setDescription(DESCRIPTION);
|
||||
setKeyBindingData(new KeyBindingData(keyStroke));
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
int[] indices = model.getSelectedComponentRows();
|
||||
if (indices.length != 1) {
|
||||
return;
|
||||
@ -96,7 +97,8 @@ public class DuplicateMultipleAction extends CompositeEditorTableAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
setEnabled(model.isDuplicateAllowed());
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return !hasIncompleteFieldEntry() && model.isDuplicateAllowed();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,7 +31,6 @@ public class EditBitFieldAction extends CompositeEditorTableAction {
|
||||
if (!(model instanceof CompEditorModel)) {
|
||||
throw new AssertException("unsupported use");
|
||||
}
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -41,11 +40,9 @@ public class EditBitFieldAction extends CompositeEditorTableAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
// Unions do not support non-packed manipulation of bitfields
|
||||
boolean enabled = (provider instanceof StructureEditorProvider structProvider) &&
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return !hasIncompleteFieldEntry() &&
|
||||
(provider instanceof StructureEditorProvider structProvider) &&
|
||||
structProvider.getSelectedNonPackedBitFieldComponent() != null;
|
||||
setEnabled(enabled);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
@ -37,11 +37,13 @@ public class EditComponentAction extends CompositeEditorTableAction {
|
||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, MENU_PATH, null);
|
||||
this.dtmService = provider.dtmService;
|
||||
setDescription(DESCRIPTION);
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
int row = model.getRow();
|
||||
if (row >= model.getNumComponents()) {
|
||||
requestTableFocus();
|
||||
@ -79,8 +81,8 @@ public class EditComponentAction extends CompositeEditorTableAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
setEnabled(model.isEditComponentAllowed());
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return !hasIncompleteFieldEntry() && model.isEditComponentAllowed();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
@ -41,35 +41,32 @@ public class EditFieldAction extends CompositeEditorTableAction {
|
||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, MENU_PATH, null);
|
||||
setDescription(DESCRIPTION);
|
||||
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (model != null) {
|
||||
int row = model.getRow();
|
||||
int column = model.getColumn();
|
||||
if (model.isCellEditable(row, column)) {
|
||||
model.beginEditingField(row, column);
|
||||
return;
|
||||
}
|
||||
|
||||
// just go to the first editable cell, since the current one is not editable
|
||||
int firstEditableColumn = provider.getFirstEditableColumn(row);
|
||||
JTable table = provider.getTable();
|
||||
int modelColumn = table.convertColumnIndexToModel(firstEditableColumn);
|
||||
model.beginEditingField(row, modelColumn);
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
int row = model.getRow();
|
||||
int column = model.getColumn();
|
||||
if (model.isCellEditable(row, column)) {
|
||||
model.beginEditingField(row, column);
|
||||
return;
|
||||
}
|
||||
|
||||
// just go to the first editable cell, since the current one is not editable
|
||||
int firstEditableColumn = provider.getFirstEditableColumn(row);
|
||||
JTable table = provider.getTable();
|
||||
int modelColumn = table.convertColumnIndexToModel(firstEditableColumn);
|
||||
model.beginEditingField(row, modelColumn);
|
||||
requestTableFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
boolean shouldEnableEdit = false;
|
||||
if (model.isSingleRowSelection()) {
|
||||
shouldEnableEdit = model.isEditFieldAllowed();
|
||||
}
|
||||
setEnabled(shouldEnableEdit);
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return !hasIncompleteFieldEntry() && model.isSingleRowSelection() &&
|
||||
model.isEditFieldAllowed();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,366 +0,0 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.util.datatype.EmptyCompositeException;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.UsrException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public interface EditorModel {
|
||||
|
||||
// TODO: This model interface serves no real purpose and could be collapsed into the
|
||||
// abstract class CompositeEditorModel implementation.
|
||||
|
||||
/**
|
||||
* Called when the model is no longer needed.
|
||||
* This is where all cleanup code for the model should be placed.
|
||||
*/
|
||||
public void dispose();
|
||||
|
||||
/**
|
||||
* Returns the docking windows component provider associated with this edit model.
|
||||
* @return the component provider
|
||||
*/
|
||||
public CompositeEditorProvider getProvider();
|
||||
|
||||
/**
|
||||
* Adds a CompositeEditorModelListener to be notified when changes occur.
|
||||
* @param listener the listener to add.
|
||||
*/
|
||||
public void addCompositeEditorModelListener(CompositeEditorModelListener listener);
|
||||
|
||||
/**
|
||||
* Removes a CompositeEditorModelListener that was being notified when changes occur.
|
||||
* @param listener the listener to remove.
|
||||
*/
|
||||
public void removeCompositeEditorModelListener(CompositeEditorModelListener listener);
|
||||
|
||||
/**
|
||||
* Gets a data type within this editor that is equivalent to the indicated data type.
|
||||
* @param dt the data type to resolve
|
||||
* @return the equivalent data type within this editor.
|
||||
*/
|
||||
public DataType resolve(DataType dt);
|
||||
|
||||
/**
|
||||
* Returns whether or not addition of the specified component is allowed
|
||||
* based on the current selection. the addition could be an insert or replace as
|
||||
* determined by the state of the edit model.
|
||||
*
|
||||
* @param datatype the data type to be added.
|
||||
*/
|
||||
public boolean isAddAllowed(DataType datatype);
|
||||
|
||||
/**
|
||||
* Returns whether or not addition of the specified component is allowed
|
||||
* at the specified index. the addition could be an insert or replace as
|
||||
* determined by the state of the edit model.
|
||||
*
|
||||
* @param rowIndex row index of the component in the composite data type.
|
||||
* @param datatype the data type to be inserted.
|
||||
*/
|
||||
public boolean isAddAllowed(int rowIndex, DataType datatype);
|
||||
|
||||
/**
|
||||
* Returns whether or not the selection is allowed to be changed into an array.
|
||||
*/
|
||||
public boolean isArrayAllowed();
|
||||
|
||||
/**
|
||||
* Returns whether or not a bitfield is allowed at the current location.
|
||||
*/
|
||||
public boolean isBitFieldAllowed();
|
||||
|
||||
/**
|
||||
* Returns whether or not clearing the selected components is allowed.
|
||||
*/
|
||||
public boolean isClearAllowed();
|
||||
|
||||
/**
|
||||
* Returns whether or not the current selection can be cycled using the
|
||||
* indicated cycle group.
|
||||
* @param cycleGroup the cycle group
|
||||
* @return true, so that a message can be written to the user indicating
|
||||
* the criteria for cycling.
|
||||
*/
|
||||
public boolean isCycleAllowed(CycleGroup cycleGroup);
|
||||
|
||||
/**
|
||||
* Returns whether or not the selected components can be deleted.
|
||||
*/
|
||||
public boolean isDeleteAllowed();
|
||||
|
||||
/**
|
||||
* Returns whether or not the component at the selected index
|
||||
* is allowed to be duplicated.
|
||||
*/
|
||||
public boolean isDuplicateAllowed();
|
||||
|
||||
/**
|
||||
* Returns whether or not the base type of the component at the
|
||||
* selected index is editable. If the base type is a composite
|
||||
* then it is editable.
|
||||
* Also, if there isn't a selection then it isn't allowed.
|
||||
*/
|
||||
public boolean isEditComponentAllowed();
|
||||
|
||||
public boolean isEditFieldAllowed();
|
||||
|
||||
/**
|
||||
* Returns whether or not insertion of the specified data type is allowed
|
||||
* at the specified index.
|
||||
*
|
||||
* @param rowIndex row index of the component in the composite data type.
|
||||
* @param datatype the data type to be inserted.
|
||||
*/
|
||||
public boolean isInsertAllowed(int rowIndex, DataType datatype);
|
||||
|
||||
/**
|
||||
* Returns whether the selected component(s) can be moved down (to the next higher index).
|
||||
*/
|
||||
public boolean isMoveDownAllowed();
|
||||
|
||||
/**
|
||||
* Returns whether the selected component(s) can be moved up (to the next lower index).
|
||||
*/
|
||||
public boolean isMoveUpAllowed();
|
||||
|
||||
public boolean isReplaceAllowed(int rowIndex, DataType dataType);
|
||||
|
||||
/**
|
||||
* Returns whether the selected component can be unpackaged.
|
||||
* @return whether the selected component can be unpackaged.
|
||||
*/
|
||||
public boolean isUnpackageAllowed();
|
||||
|
||||
/**
|
||||
* Returns whether or not the editor has changes that haven't been applied.
|
||||
* Changes can also mean a new data type that hasn't yet been saved.
|
||||
* @return if there are changes
|
||||
*/
|
||||
public boolean hasChanges();
|
||||
|
||||
/**
|
||||
* Sets the name for the composite data type being edited.
|
||||
*
|
||||
* @param name the new name.
|
||||
*
|
||||
* @throws DuplicateNameException if the name already exists.
|
||||
* @throws InvalidNameException if the name is invalid
|
||||
*/
|
||||
public void setName(String name) throws DuplicateNameException, InvalidNameException;
|
||||
|
||||
/**
|
||||
* Sets the description for the composite data type being edited.
|
||||
*
|
||||
* @param desc the new description.
|
||||
*/
|
||||
public void setDescription(String desc);
|
||||
|
||||
/**
|
||||
* Sets the data type for the component at the indicated rowIndex.
|
||||
* @param rowIndex the row index of the component
|
||||
* @param dataTypeObject a String or a DataType
|
||||
* @return true if changed
|
||||
* @throws UsrException if the type cannot be used
|
||||
*/
|
||||
public boolean setComponentDataType(int rowIndex, Object dataTypeObject) throws UsrException;
|
||||
|
||||
/**
|
||||
* Sets the data type for the component at the indicated row index.
|
||||
* @param rowIndex the row index of the component
|
||||
* @param dt component datatype
|
||||
* @param length component length
|
||||
* @throws UsrException if invalid datatype or length specified
|
||||
*/
|
||||
public void setComponentDataTypeInstance(int rowIndex, DataType dt, int length)
|
||||
throws UsrException;
|
||||
|
||||
/**
|
||||
* Sets the data type for the component at the indicated index.
|
||||
* @param rowIndex the row index of the component
|
||||
* @param name the name
|
||||
* @return true if a change was made
|
||||
* @throws InvalidNameException if the name is invalid
|
||||
*/
|
||||
public boolean setComponentName(int rowIndex, String name) throws InvalidNameException;
|
||||
|
||||
/**
|
||||
* Sets the data type for the component at the indicated index.
|
||||
* @param rowIndex the row index of the component
|
||||
* @param comment the comment
|
||||
* @return true if a change was made
|
||||
*/
|
||||
public boolean setComponentComment(int rowIndex, String comment);
|
||||
|
||||
/**
|
||||
* Returns whether or not the editor is showing undefined bytes.
|
||||
* @return true if the editor is showing undefined bytes.
|
||||
*/
|
||||
public boolean isShowingUndefinedBytes();
|
||||
|
||||
public boolean beginEditingField(int modelRow, int modelColumn);
|
||||
|
||||
/**
|
||||
* Change the edit state to indicate no longer editing a field.
|
||||
* @return the edit state to indicate no longer editing a field.
|
||||
*/
|
||||
public boolean endEditingField();
|
||||
|
||||
/**
|
||||
* Returns whether the user is currently editing a field's value.
|
||||
* @return whether the user is currently editing a field's value.
|
||||
*/
|
||||
public boolean isEditingField();
|
||||
|
||||
public void endFieldEditing();
|
||||
|
||||
public DataTypeComponent add(DataType dataType) throws UsrException;
|
||||
|
||||
public DataTypeComponent add(int rowIndex, DataType dataType) throws UsrException;
|
||||
|
||||
public DataTypeComponent add(int rowIndex, DataType dt, int dtLength) throws UsrException;
|
||||
|
||||
/**
|
||||
* Apply the changes for the current edited composite back to the
|
||||
* original composite.
|
||||
*
|
||||
* @return true if apply succeeds
|
||||
* @throws EmptyCompositeException if the structure doesn't have any components.
|
||||
* @throws InvalidDataTypeException if this structure has a component that it is part of.
|
||||
*/
|
||||
public boolean apply() throws EmptyCompositeException, InvalidDataTypeException;
|
||||
|
||||
public void clearComponent(int rowIndex);
|
||||
|
||||
public void clearSelectedComponents() throws UsrException;
|
||||
|
||||
public void cycleDataType(CycleGroup cycleGroup);
|
||||
|
||||
public void createArray() throws UsrException;
|
||||
|
||||
/**
|
||||
* Delete the selected components.
|
||||
*
|
||||
* @throws UsrException if the data type isn't allowed to be deleted.
|
||||
*/
|
||||
public void deleteSelectedComponents() throws UsrException;
|
||||
|
||||
/**
|
||||
* Creates multiple duplicates of the indicated component.
|
||||
* The duplicates will be created at the index immediately after the
|
||||
* indicated component.
|
||||
* @param rowIndex the index of the row whose component is to be duplicated.
|
||||
* @param multiple the number of duplicates to create.
|
||||
* @param monitor the task monitor
|
||||
* @throws UsrException if component can't be duplicated the indicated number of times.
|
||||
*/
|
||||
public void duplicateMultiple(int rowIndex, int multiple, TaskMonitor monitor)
|
||||
throws UsrException;
|
||||
|
||||
public DataTypeComponent insert(DataType dataType) throws UsrException;
|
||||
|
||||
public DataTypeComponent insert(int rowIndex, DataType dataType) throws UsrException;
|
||||
|
||||
public DataTypeComponent insert(int rowIndex, DataType dt, int dtLength) throws UsrException;
|
||||
|
||||
/**
|
||||
* Moves a contiguous selection of components up by a single position. The component that was
|
||||
* immediately above (at the index immediately preceding the selection) the selection will be
|
||||
* moved below the selection (to what was the maximum selected component index).
|
||||
* @return true if selected components were moved up.
|
||||
* @throws UsrException if components can't be moved up.
|
||||
*/
|
||||
public boolean moveUp() throws UsrException;
|
||||
|
||||
/**
|
||||
* Moves a contiguous selection of components down by a single position. The component that was
|
||||
* immediately below (at the index immediately following the selection) the selection will be
|
||||
* moved above the selection (to what was the minimum selected component index).
|
||||
* @return true if selected components were moved down.
|
||||
* @throws UsrException if components can't be moved down.
|
||||
*/
|
||||
public boolean moveDown() throws UsrException;
|
||||
|
||||
public DataTypeComponent replace(int rowIndex, DataType dt, int dtLength) throws UsrException;
|
||||
|
||||
/**
|
||||
* Gets the maximum number of bytes available for a data type that is added at the indicated
|
||||
* index. This can vary based on whether or not it is in a selection.
|
||||
*
|
||||
* @param rowIndex index of the row in the editor's composite data type.
|
||||
* @return the length
|
||||
*/
|
||||
public int getMaxAddLength(int rowIndex);
|
||||
|
||||
/**
|
||||
* Determine the maximum number of duplicates that can be created for
|
||||
* the component at the indicated index. The duplicates would follow
|
||||
* the component. The number allowed depends on how many fit based on
|
||||
* the current lock/unlock state of the editor.
|
||||
* <br>Note: This method doesn't care whether there is a selection or not.
|
||||
*
|
||||
* @param rowIndex the index of the row for the component to be duplicated.
|
||||
* @return the maximum number of duplicates.
|
||||
*/
|
||||
public int getMaxDuplicates(int rowIndex);
|
||||
|
||||
/**
|
||||
* Determine the maximum number of array elements that can be created for
|
||||
* the current selection. The array data type is assumed to become the
|
||||
* data type of the first component in the selection. The current selection
|
||||
* must be contiguous or 0 is returned.
|
||||
*
|
||||
* @return the number of array elements that fit in the current selection.
|
||||
*/
|
||||
public int getMaxElements();
|
||||
|
||||
/**
|
||||
* Gets the maximum number of bytes available for a new data type that
|
||||
* will replace the current data type at the indicated component index.
|
||||
* If there isn't a component with the indicated index, the max length
|
||||
* will be determined by the lock mode.
|
||||
*
|
||||
* @param rowIndex index of the row for the component to replace.
|
||||
* @return the maximum number of bytes that can be replaced.
|
||||
*/
|
||||
public int getMaxReplaceLength(int rowIndex);
|
||||
|
||||
/**
|
||||
* Return the last number of bytes the user entered when prompted for
|
||||
* a data type size.
|
||||
* @return the number of bytes
|
||||
*/
|
||||
public int getLastNumBytes();
|
||||
|
||||
/**
|
||||
* Return the last number of duplicates the user entered when prompted for
|
||||
* creating duplicates of a component.
|
||||
* @return the number of duplicates
|
||||
*/
|
||||
public int getLastNumDuplicates();
|
||||
|
||||
/**
|
||||
* Return the last number of elements the user entered when prompted for
|
||||
* creating an array.
|
||||
* @return the number of elements
|
||||
*/
|
||||
public int getLastNumElements();
|
||||
|
||||
}
|
@ -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.
|
||||
@ -45,7 +45,6 @@ public class FavoritesAction extends CompositeEditorTableAction {
|
||||
new MenuData(new String[] { "Favorite", dt.getDisplayName() }, null, GROUP_NAME));
|
||||
|
||||
getPopupMenuData().setParentMenuGroup(GROUP_NAME);
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
public DataType getDataType() {
|
||||
@ -54,6 +53,9 @@ public class FavoritesAction extends CompositeEditorTableAction {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
model.add(dataType);
|
||||
}
|
||||
@ -63,12 +65,6 @@ public class FavoritesAction extends CompositeEditorTableAction {
|
||||
requestTableFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
// we always want it enabled so the user gets a "doesn't fit" message.
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpName() {
|
||||
return "Favorite";
|
||||
@ -76,7 +72,7 @@ public class FavoritesAction extends CompositeEditorTableAction {
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return model.isAddAllowed(dataType);
|
||||
return !hasIncompleteFieldEntry() && model.isAddAllowed(dataType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -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,13 +34,14 @@ public class FindReferencesToStructureFieldAction extends CompositeEditorTableAc
|
||||
public FindReferencesToStructureFieldAction(CompositeEditorProvider provider) {
|
||||
super(provider, ACTION_NAME, BASIC_ACTION_GROUP, new String[] { ACTION_NAME }, null, null);
|
||||
setDescription(DESCRIPTION);
|
||||
adjustEnablement();
|
||||
setHelpLocation(new HelpLocation(HelpTopics.FIND_REFERENCES, "Data_Types"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
FindAppliedDataTypesService service = tool.getService(FindAppliedDataTypesService.class);
|
||||
if (service == null) {
|
||||
Msg.showError(this, null, "Missing Plugin",
|
||||
@ -67,24 +68,27 @@ public class FindReferencesToStructureFieldAction extends CompositeEditorTableAc
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
setEnabled(false);
|
||||
if (!hasIncompleteFieldEntry()) {
|
||||
return false;
|
||||
}
|
||||
if (model.getSelectedComponentRows().length != 1) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
Composite composite = model.getOriginalComposite();
|
||||
if (composite == null) {
|
||||
return; // not sure if this can happen
|
||||
return false; // not sure if this can happen
|
||||
}
|
||||
|
||||
String fieldName = getFieldName();
|
||||
if (fieldName == null) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
setEnabled(true);
|
||||
updateMenuName(fieldName);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateMenuName(String name) {
|
||||
|
@ -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.
|
||||
@ -38,19 +38,21 @@ public class HexNumbersAction extends CompositeEditorTableAction implements Togg
|
||||
public HexNumbersAction(CompositeEditorProvider provider) {
|
||||
super(provider, ACTION_NAME, GROUP_NAME, PATH, PATH, null);
|
||||
setDescription(DESCRIPTION);
|
||||
setEnabled(true);
|
||||
setSelected(model.isShowingNumbersInHex());
|
||||
setKeyBindingData(new KeyBindingData("Shift-H"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
model.displayNumbersInHex(!model.isShowingNumbersInHex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
// Always enabled.
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return !hasIncompleteFieldEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -70,7 +72,7 @@ public class HexNumbersAction extends CompositeEditorTableAction implements Togg
|
||||
@Override
|
||||
protected JMenuItem doCreateMenuItem() {
|
||||
DockingCheckBoxMenuItem menuItem = new DockingCheckBoxMenuItem(isSelected);
|
||||
menuItem.setUI((DockingCheckboxMenuItemUI) DockingCheckboxMenuItemUI.createUI(menuItem));
|
||||
menuItem.setUI(DockingCheckboxMenuItemUI.createUI(menuItem));
|
||||
return menuItem;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,145 @@
|
||||
/* ###
|
||||
* 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.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import db.*;
|
||||
import db.util.ErrorHandler;
|
||||
|
||||
/**
|
||||
* {@link IDMapDB} provides a bidirectional map for tracking view to/from original datatype ID
|
||||
* correspondence and faciliate recovery across undo/redo of the view's datatype manager.
|
||||
*/
|
||||
class IDMapDB {
|
||||
private final static String TABLE_NAME = "IDMap";
|
||||
|
||||
private final static Schema SCHEMA =
|
||||
new Schema(0, "ViewID", new Class[] { LongField.class }, new String[] { "OriginalID" });
|
||||
|
||||
private static final int ORIGINAL_ID_COL = 0;
|
||||
|
||||
private final ErrorHandler errorHandler;
|
||||
private final Table table;
|
||||
|
||||
private Map<Long, Long> viewToOriginalMap;
|
||||
private Map<Long, Long> originalToViewMap;
|
||||
|
||||
/**
|
||||
* Construct database-backed bidirectional datatype ID map
|
||||
* @param dbHandle database handle for {@link CompositeViewerDataTypeManager}
|
||||
* @param errorHandler error handler
|
||||
*/
|
||||
IDMapDB(DBHandle dbHandle, ErrorHandler errorHandler) {
|
||||
this.errorHandler = errorHandler;
|
||||
table = init(dbHandle, errorHandler);
|
||||
viewToOriginalMap = new HashMap<>();
|
||||
originalToViewMap = new HashMap<>();
|
||||
}
|
||||
|
||||
private static Table init(DBHandle dbHandle, ErrorHandler errorHandler) {
|
||||
try {
|
||||
return dbHandle.createTable(TABLE_NAME, SCHEMA);
|
||||
}
|
||||
catch (IOException e) {
|
||||
errorHandler.dbError(e); // will throw runtime exception
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void invalidate() {
|
||||
viewToOriginalMap = null;
|
||||
originalToViewMap = null;
|
||||
// delay reload until needed
|
||||
}
|
||||
|
||||
void clearAll() throws IOException {
|
||||
table.deleteAll();
|
||||
viewToOriginalMap = new HashMap<>();
|
||||
originalToViewMap = new HashMap<>();
|
||||
}
|
||||
|
||||
private void reloadIfNeeded() {
|
||||
if (viewToOriginalMap != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
viewToOriginalMap = new HashMap<>();
|
||||
originalToViewMap = new HashMap<>();
|
||||
try {
|
||||
RecordIterator it = table.iterator();
|
||||
while (it.hasNext()) {
|
||||
DBRecord rec = it.next();
|
||||
long viewId = rec.getKey();
|
||||
long originalId = rec.getLongValue(ORIGINAL_ID_COL);
|
||||
viewToOriginalMap.put(viewId, originalId);
|
||||
originalToViewMap.put(originalId, viewId);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
errorHandler.dbError(e);
|
||||
}
|
||||
}
|
||||
|
||||
Long getOriginalIDFromViewID(long viewId) {
|
||||
reloadIfNeeded();
|
||||
return viewToOriginalMap.get(viewId);
|
||||
}
|
||||
|
||||
Long getViewIDFromOriginalID(long originalId) {
|
||||
reloadIfNeeded();
|
||||
return originalToViewMap.get(originalId);
|
||||
}
|
||||
|
||||
void put(long viewId, long originalId) {
|
||||
try {
|
||||
DBRecord rec = SCHEMA.createRecord(viewId);
|
||||
rec.setLongValue(ORIGINAL_ID_COL, originalId);
|
||||
table.putRecord(rec);
|
||||
|
||||
if (viewToOriginalMap != null) {
|
||||
viewToOriginalMap.put(viewId, originalId);
|
||||
originalToViewMap.put(originalId, viewId);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
errorHandler.dbError(e);
|
||||
}
|
||||
}
|
||||
|
||||
Long remove(long viewId) {
|
||||
Long originalId = null;
|
||||
try {
|
||||
DBRecord rec = table.getRecord(viewId);
|
||||
if (rec != null) {
|
||||
originalId = rec.getLongValue(ORIGINAL_ID_COL);
|
||||
table.deleteRecord(viewId);
|
||||
|
||||
if (viewToOriginalMap != null) {
|
||||
viewToOriginalMap.remove(viewId);
|
||||
originalToViewMap.remove(originalId);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
errorHandler.dbError(e);
|
||||
}
|
||||
return originalId;
|
||||
}
|
||||
|
||||
}
|
@ -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.
|
||||
@ -46,11 +46,13 @@ public class InsertUndefinedAction extends CompositeEditorTableAction {
|
||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||
setDescription(DESCRIPTION);
|
||||
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
boolean isContiguousSelection = model.getSelection().getNumRanges() == 1;
|
||||
if (isContiguousSelection) {
|
||||
@ -72,7 +74,10 @@ public class InsertUndefinedAction extends CompositeEditorTableAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
if (hasIncompleteFieldEntry()) {
|
||||
return false;
|
||||
}
|
||||
boolean enabled = false;
|
||||
if (model.viewComposite instanceof Structure) {
|
||||
boolean isContiguousSelection = model.getSelection().getNumRanges() == 1;
|
||||
@ -82,7 +87,7 @@ public class InsertUndefinedAction extends CompositeEditorTableAction {
|
||||
enabled = isContiguousSelection &&
|
||||
model.isInsertAllowed(model.getMinIndexSelected(), undefinedDt);
|
||||
}
|
||||
setEnabled(enabled);
|
||||
return enabled;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
@ -45,11 +45,13 @@ public class MoveDownAction extends CompositeEditorTableAction {
|
||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||
setDescription(DESCRIPTION);
|
||||
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
model.moveDown();
|
||||
}
|
||||
@ -60,7 +62,8 @@ public class MoveDownAction extends CompositeEditorTableAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
setEnabled(model.isMoveDownAllowed());
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return !hasIncompleteFieldEntry() && model.isMoveDownAllowed();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
@ -45,11 +45,13 @@ public class MoveUpAction extends CompositeEditorTableAction {
|
||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||
setDescription(DESCRIPTION);
|
||||
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
model.moveUp();
|
||||
}
|
||||
@ -60,8 +62,8 @@ public class MoveUpAction extends CompositeEditorTableAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
setEnabled(model.isMoveUpAllowed());
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return !hasIncompleteFieldEntry() && model.isMoveUpAllowed();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
@ -38,11 +38,13 @@ public class PointerAction extends CompositeEditorTableAction {
|
||||
super(provider, ACTION_NAME, GROUP_NAME, null, null, null);
|
||||
setDescription(DESCRIPTION);
|
||||
setKeyBindingData(new KeyBindingData(KeyEvent.VK_P, 0));
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
model.add(POINTER_DT);
|
||||
}
|
||||
@ -55,16 +57,8 @@ public class PointerAction extends CompositeEditorTableAction {
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
// Do nothing since we always want it enabled so the user gets a "doesn't fit" message.
|
||||
return model.getRowCount() > 0 && model.hasSelection() && model.isContiguousSelection();
|
||||
return !hasIncompleteFieldEntry() && model.getRowCount() > 0 && model.hasSelection() &&
|
||||
model.isContiguousSelection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
// Allow the user to get a "doesn't fit" message on contiguous selection.
|
||||
// Also allow message indicating you must have a selection.
|
||||
boolean hasSelection = model.hasSelection();
|
||||
boolean enable = model.getRowCount() > 0 &&
|
||||
(!hasSelection || (hasSelection && model.isContiguousSelection()));
|
||||
setEnabled(enable);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,62 @@
|
||||
/* ###
|
||||
* 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 javax.swing.Icon;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.KeyBindingData;
|
||||
import generic.theme.GIcon;
|
||||
|
||||
/**
|
||||
* {@link RedoChangeAction} facilitates an redo of recently undone/reverted composite editor changes.
|
||||
*/
|
||||
public class RedoChangeAction extends CompositeEditorTableAction {
|
||||
|
||||
public static String DESCRIPTION = "Redo Change";
|
||||
public final static String ACTION_NAME = "Redo Editor Change";
|
||||
private final static String GROUP_NAME = UNDOREDO_ACTION_GROUP;
|
||||
private final static Icon ICON = new GIcon("icon.redo");
|
||||
private final static String[] POPUP_PATH = new String[] { DESCRIPTION };
|
||||
|
||||
public RedoChangeAction(CompositeEditorProvider provider) {
|
||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||
setKeyBindingData(new KeyBindingData("ctrl shift Z"));
|
||||
setDescription("Redo editor change");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
CompositeViewerDataTypeManager viewDTM = model.getViewDataTypeManager();
|
||||
viewDTM.redo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
if (hasIncompleteFieldEntry()) {
|
||||
return false;
|
||||
}
|
||||
CompositeViewerDataTypeManager viewDTM = model.getViewDataTypeManager();
|
||||
boolean canRedo = viewDTM.canRedo();
|
||||
setEnabled(canRedo);
|
||||
String description = DESCRIPTION + (canRedo ? (": " + viewDTM.getRedoName()) : "");
|
||||
setDescription(description);
|
||||
return canRedo;
|
||||
}
|
||||
}
|
@ -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.
|
||||
@ -35,11 +35,13 @@ public class ShowComponentPathAction extends CompositeEditorTableAction {
|
||||
public ShowComponentPathAction(CompositeEditorProvider provider) {
|
||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, MENU_PATH, null);
|
||||
setDescription(DESCRIPTION);
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
String message = " ";
|
||||
int index = model.getMinIndexSelected();
|
||||
DataTypeComponent dtc = model.getComponent(index);
|
||||
@ -54,7 +56,7 @@ public class ShowComponentPathAction extends CompositeEditorTableAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
setEnabled(model.isSingleComponentRowSelection());
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return !hasIncompleteFieldEntry() && model.isSingleComponentRowSelection();
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
@ -36,14 +36,16 @@ public class ShowDataTypeInTreeAction extends CompositeEditorTableAction {
|
||||
private static final Icon ICON = new GIcon("icon.plugin.composite.editor.show.type");
|
||||
|
||||
public ShowDataTypeInTreeAction(CompositeEditorProvider provider) {
|
||||
super(provider, ACTION_NAME, TOOLBAR_GROUP, null /*popupPath*/,
|
||||
null /*menuPath*/, ICON);
|
||||
super(provider, ACTION_NAME, TOOLBAR_GROUP, null /*popupPath*/, null /*menuPath*/, ICON);
|
||||
|
||||
setToolBarData(new ToolBarData(ICON, TOOLBAR_GROUP));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
DataTypeManagerService dtmService = tool.getService(DataTypeManagerService.class);
|
||||
DataTypeManager dtm = provider.getDataTypeManager();
|
||||
DataTypePath path = provider.getDtPath();
|
||||
@ -52,10 +54,13 @@ public class ShowDataTypeInTreeAction extends CompositeEditorTableAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
if (hasIncompleteFieldEntry()) {
|
||||
return false;
|
||||
}
|
||||
DataTypeManager dtm = provider.getDataTypeManager();
|
||||
DataTypePath path = provider.getDtPath();
|
||||
DataType dt = dtm.getDataType(path);
|
||||
setEnabled(dt != null);
|
||||
return dt != null;
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
@ -62,6 +62,11 @@ class StructureEditorModel extends CompEditorModel {
|
||||
hiddenColumns = Collections.unmodifiableList(additionalColumns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "Structure";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<TableColumn> getHiddenColumns() {
|
||||
return hiddenColumns;
|
||||
@ -97,11 +102,6 @@ class StructureEditorModel extends CompEditorModel {
|
||||
return COMMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Composite dataType) {
|
||||
super.load(dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of component rows in the viewer. There may be a
|
||||
* blank row at the end for selecting. Therefore this number can be
|
||||
@ -213,37 +213,40 @@ class StructureEditorModel extends CompEditorModel {
|
||||
if (currentLength == size) {
|
||||
return;
|
||||
}
|
||||
Structure structure = (Structure) viewComposite;
|
||||
if (currentLength > size) {
|
||||
int numComponents = structure.getNumComponents();
|
||||
|
||||
DataTypeComponent dtc = structure.getComponentContaining(size);
|
||||
int ordinal = dtc.getOrdinal();
|
||||
viewDTM.withTransaction("Set Size", () -> {
|
||||
int length = currentLength;
|
||||
Structure structure = (Structure) viewComposite;
|
||||
if (length > size) {
|
||||
int numComponents = structure.getNumComponents();
|
||||
|
||||
// retain any zero-length components which have an offset equal the new size
|
||||
while (dtc.getOffset() == size && dtc.getLength() == 0 &&
|
||||
(ordinal + 1) < numComponents) {
|
||||
dtc = structure.getComponent(++ordinal);
|
||||
}
|
||||
DataTypeComponent dtc = structure.getComponentContaining(size);
|
||||
int ordinal = dtc.getOrdinal();
|
||||
|
||||
// remove trailing components outside of new size
|
||||
for (int index = numComponents - 1; index >= ordinal; index--) {
|
||||
structure.delete(index);
|
||||
int bitFieldResidualBytes = structure.getNumComponents() - index;
|
||||
for (int i = 0; i < bitFieldResidualBytes; i++) {
|
||||
// bitfield removal may cause injection of undefined bytes - remove them
|
||||
structure.delete(index);
|
||||
// retain any zero-length components which have an offset equal the new size
|
||||
while (dtc.getOffset() == size && dtc.getLength() == 0 &&
|
||||
(ordinal + 1) < numComponents) {
|
||||
dtc = structure.getComponent(++ordinal);
|
||||
}
|
||||
|
||||
// remove trailing components outside of new size
|
||||
for (int index = numComponents - 1; index >= ordinal; index--) {
|
||||
structure.delete(index);
|
||||
int bitFieldResidualBytes = structure.getNumComponents() - index;
|
||||
for (int i = 0; i < bitFieldResidualBytes; i++) {
|
||||
// bitfield removal may cause injection of undefined bytes - remove them
|
||||
structure.delete(index);
|
||||
}
|
||||
}
|
||||
// structure may shrink too much from component removal - may need to grow
|
||||
length = (viewComposite.isZeroLength()) ? 0 : viewComposite.getLength();
|
||||
}
|
||||
// structure may shrink too much from component removal - may need to grow
|
||||
currentLength = (viewComposite.isZeroLength()) ? 0 : viewComposite.getLength();
|
||||
}
|
||||
if (currentLength < size) {
|
||||
// Increasing structure length.
|
||||
structure.growStructure(size - currentLength);
|
||||
}
|
||||
updateAndCheckChangeState();
|
||||
fireTableDataChanged();
|
||||
if (length < size) {
|
||||
// Increasing structure length.
|
||||
structure.growStructure(size - length);
|
||||
}
|
||||
});
|
||||
notifyCompositeChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -286,38 +289,36 @@ class StructureEditorModel extends CompEditorModel {
|
||||
clearComponents(getSelectedComponentRows());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearComponent(int ordinal) {
|
||||
((Structure) viewComposite).clearComponent(ordinal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearComponents(int[] indices) {
|
||||
if (isEditingField()) {
|
||||
endFieldEditing();
|
||||
}
|
||||
|
||||
Arrays.sort(indices);
|
||||
|
||||
// work from back to front so our indices aren't affected by each component's clear.
|
||||
for (int i = indices.length - 1; i >= 0; i--) {
|
||||
DataTypeComponent comp = getComponent(indices[i]);
|
||||
if (comp == null) {
|
||||
continue; // must be on blank last line.
|
||||
}
|
||||
boolean isSelected = selection.containsEntirely(BigInteger.valueOf(indices[i]));
|
||||
int numBytes = comp.getLength();
|
||||
((Structure) viewComposite).clearComponent(indices[i]);
|
||||
viewDTM.withTransaction("Clear Components", () -> {
|
||||
for (int i = indices.length - 1; i >= 0; i--) {
|
||||
DataTypeComponent comp = getComponent(indices[i]);
|
||||
if (comp == null) {
|
||||
continue; // must be on blank last line.
|
||||
}
|
||||
boolean isSelected = selection.containsEntirely(BigInteger.valueOf(indices[i]));
|
||||
int numBytes = comp.getLength();
|
||||
((Structure) viewComposite).clearComponent(indices[i]);
|
||||
|
||||
// Adjust the selection due to the clear.
|
||||
adjustSelection(indices[i] + 1, numBytes - 1);
|
||||
if (isSelected && numBytes > 1) {
|
||||
selection.addRange(indices[i] + 1, indices[i] + numBytes);
|
||||
}
|
||||
// Adjust the selection due to the clear.
|
||||
adjustSelection(indices[i] + 1, numBytes - 1);
|
||||
if (isSelected && numBytes > 1) {
|
||||
selection.addRange(indices[i] + 1, indices[i] + numBytes);
|
||||
}
|
||||
|
||||
if (indices[i] > 0) {
|
||||
consumeByComponent(indices[i] - 1);
|
||||
if (indices[i] > 0) {
|
||||
consumeByComponent(indices[i] - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
componentEdited();
|
||||
}
|
||||
|
||||
@ -374,14 +375,16 @@ class StructureEditorModel extends CompEditorModel {
|
||||
int dtLen = dt.getLength();
|
||||
checkIsAllowableDataType(dt);
|
||||
|
||||
int startIndex = index + 1;
|
||||
if (isShowingUndefinedBytes() && (dt != DataType.DEFAULT)) {
|
||||
int endIndex = startIndex + (dtLen * multiple) - 1;
|
||||
if (startIndex < getNumComponents()) {
|
||||
deleteComponentRange(startIndex, endIndex, monitor);
|
||||
viewDTM.withTransaction("Duplicate Components", () -> {
|
||||
int startIndex = index + 1;
|
||||
if (isShowingUndefinedBytes() && (dt != DataType.DEFAULT)) {
|
||||
int endIndex = startIndex + (dtLen * multiple) - 1;
|
||||
if (startIndex < getNumComponents()) {
|
||||
deleteComponentRange(startIndex, endIndex, monitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
insertComponentMultiple(startIndex, dt, originalComp.getLength(), multiple, monitor);
|
||||
insertComponentMultiple(startIndex, dt, originalComp.getLength(), multiple, monitor);
|
||||
});
|
||||
|
||||
// Adjust the selection since we added some components. Select last component added.
|
||||
// Ensure that last added component is selected to allow for repeated duplication
|
||||
@ -407,24 +410,25 @@ class StructureEditorModel extends CompEditorModel {
|
||||
}
|
||||
int len = getLength();
|
||||
|
||||
DataTypeComponent comp = deleteComponentAndResidual(startIndex - 1);
|
||||
|
||||
try {
|
||||
if (!isPackingEnabled() && comp.isBitFieldComponent()) {
|
||||
// insert residual undefined bytes before inserting non-packed bitfield
|
||||
int lenChange = len - getLength();
|
||||
insert(endIndex, DataType.DEFAULT, 1, lenChange, TaskMonitor.DUMMY);
|
||||
return viewDTM.withTransaction("Shift Up", () -> {
|
||||
DataTypeComponent comp = deleteComponentAndResidual(startIndex - 1);
|
||||
try {
|
||||
if (!isPackingEnabled() && comp.isBitFieldComponent()) {
|
||||
// insert residual undefined bytes before inserting non-packed bitfield
|
||||
int lenChange = len - getLength();
|
||||
insert(endIndex, DataType.DEFAULT, 1, lenChange, TaskMonitor.DUMMY);
|
||||
}
|
||||
insert(endIndex, comp.getDataType(), comp.getLength(), comp.getFieldName(),
|
||||
comp.getComment());
|
||||
}
|
||||
insert(endIndex, comp.getDataType(), comp.getLength(), comp.getFieldName(),
|
||||
comp.getComment());
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// can't happen while using a dummy monitor
|
||||
}
|
||||
catch (InvalidDataTypeException e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
catch (CancelledException e) {
|
||||
// can't happen while using a dummy monitor
|
||||
}
|
||||
catch (InvalidDataTypeException e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -443,24 +447,25 @@ class StructureEditorModel extends CompEditorModel {
|
||||
}
|
||||
int len = getLength();
|
||||
|
||||
DataTypeComponent comp = deleteComponentAndResidual(endIndex + 1);
|
||||
|
||||
try {
|
||||
if (!isPackingEnabled() && comp.isBitFieldComponent()) {
|
||||
// insert residual undefined bytes before inserting non-packed bitfield
|
||||
int lenChange = len - getLength();
|
||||
insert(startIndex, DataType.DEFAULT, 1, lenChange, TaskMonitor.DUMMY);
|
||||
return viewDTM.withTransaction("Shift Down", () -> {
|
||||
DataTypeComponent comp = deleteComponentAndResidual(endIndex + 1);
|
||||
try {
|
||||
if (!isPackingEnabled() && comp.isBitFieldComponent()) {
|
||||
// insert residual undefined bytes before inserting non-packed bitfield
|
||||
int lenChange = len - getLength();
|
||||
insert(startIndex, DataType.DEFAULT, 1, lenChange, TaskMonitor.DUMMY);
|
||||
}
|
||||
insert(startIndex, comp.getDataType(), comp.getLength(), comp.getFieldName(),
|
||||
comp.getComment());
|
||||
}
|
||||
insert(startIndex, comp.getDataType(), comp.getLength(), comp.getFieldName(),
|
||||
comp.getComment());
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// can't happen while using a dummy monitor
|
||||
}
|
||||
catch (InvalidDataTypeException e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
catch (CancelledException e) {
|
||||
// can't happen while using a dummy monitor
|
||||
}
|
||||
catch (InvalidDataTypeException e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private DataTypeComponent deleteComponentAndResidual(int index) {
|
||||
@ -887,23 +892,27 @@ class StructureEditorModel extends CompEditorModel {
|
||||
String comment) throws InvalidDataTypeException {
|
||||
checkIsAllowableDataType(dataType);
|
||||
try {
|
||||
DataTypeComponent dtc;
|
||||
if (isPackingEnabled() || !(dataType instanceof BitFieldDataType)) {
|
||||
dtc = ((Structure) viewComposite).insert(rowIndex, dataType, length, name, comment);
|
||||
}
|
||||
else {
|
||||
BitFieldDataType bitfield = (BitFieldDataType) dataType;
|
||||
dtc = ((Structure) viewComposite).insertBitField(rowIndex, length,
|
||||
bitfield.getBitOffset(), bitfield.getBaseDataType(),
|
||||
bitfield.getDeclaredBitSize(), name, comment);
|
||||
}
|
||||
if (rowIndex <= row) {
|
||||
row++;
|
||||
}
|
||||
adjustSelection(rowIndex, 1);
|
||||
// Consume undefined bytes that may have been added, if needed.
|
||||
consumeByComponent(rowIndex - 1);
|
||||
return dtc;
|
||||
return viewDTM.withTransaction("Insert Component", () -> {
|
||||
DataTypeComponent dtc;
|
||||
if (isPackingEnabled() || !(dataType instanceof BitFieldDataType)) {
|
||||
dtc = ((Structure) viewComposite).insert(rowIndex, dataType, length, name,
|
||||
comment);
|
||||
}
|
||||
else {
|
||||
BitFieldDataType bitfield = (BitFieldDataType) dataType;
|
||||
dtc = ((Structure) viewComposite).insertBitField(rowIndex, length,
|
||||
bitfield.getBitOffset(), bitfield.getBaseDataType(),
|
||||
bitfield.getDeclaredBitSize(), name, comment);
|
||||
}
|
||||
if (rowIndex <= currentEditRow) {
|
||||
currentEditRow++;
|
||||
}
|
||||
adjustSelection(rowIndex, 1);
|
||||
// Consume undefined bytes that may have been added, if needed.
|
||||
consumeByComponent(rowIndex - 1);
|
||||
|
||||
return dtc;
|
||||
});
|
||||
}
|
||||
catch (IllegalArgumentException exc) {
|
||||
throw new InvalidDataTypeException(exc.getMessage());
|
||||
@ -918,20 +927,21 @@ class StructureEditorModel extends CompEditorModel {
|
||||
int componentOrdinal = convertRowToOrdinal(rowIndex);
|
||||
monitor.initialize(numCopies);
|
||||
try {
|
||||
viewDTM.withTransaction("Insert Multiple", () -> {
|
||||
for (int i = 0; i < numCopies; i++) {
|
||||
monitor.checkCancelled();
|
||||
monitor.setMessage("Inserting " + (i + 1) + " of " + numCopies);
|
||||
viewComposite.insert(componentOrdinal, dataType, length);
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numCopies; i++) {
|
||||
monitor.checkCancelled();
|
||||
monitor.setMessage("Inserting " + (i + 1) + " of " + numCopies);
|
||||
viewComposite.insert(componentOrdinal, dataType, length);
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
|
||||
if (rowIndex <= row) {
|
||||
row += numCopies;
|
||||
}
|
||||
adjustSelection(componentOrdinal, numCopies);
|
||||
// Consume undefined bytes that may have been added, if needed.
|
||||
consumeByComponent(componentOrdinal - numCopies);
|
||||
if (rowIndex <= currentEditRow) {
|
||||
currentEditRow += numCopies;
|
||||
}
|
||||
adjustSelection(componentOrdinal, numCopies);
|
||||
// Consume undefined bytes that may have been added, if needed.
|
||||
consumeByComponent(componentOrdinal - numCopies);
|
||||
});
|
||||
}
|
||||
catch (IllegalArgumentException exc) {
|
||||
throw new InvalidDataTypeException(exc.getMessage());
|
||||
@ -951,8 +961,10 @@ class StructureEditorModel extends CompEditorModel {
|
||||
// FreeForm editing mode (showing Undefined Bytes).
|
||||
if (isShowingUndefinedBytes() && !isAtEnd(rowIndex)) {
|
||||
int origLen = getComponent(rowIndex).getLength();
|
||||
dtc = ((Structure) viewComposite).replace(componentOrdinal, dataType, length, name,
|
||||
comment);
|
||||
dtc = viewDTM.withTransaction("Replace Component", () -> {
|
||||
return ((Structure) viewComposite).replace(componentOrdinal, dataType, length,
|
||||
name, comment);
|
||||
});
|
||||
diffLen = origLen - dtc.getLength();
|
||||
int nextRowIndex = rowIndex + 1;
|
||||
if (diffLen < 0) {
|
||||
@ -965,14 +977,16 @@ class StructureEditorModel extends CompEditorModel {
|
||||
selection.addRange(nextRowIndex, nextRowIndex + diffLen);
|
||||
}
|
||||
}
|
||||
if (rowIndex < row) {
|
||||
row += diffLen;
|
||||
if (rowIndex < currentEditRow) {
|
||||
currentEditRow += diffLen;
|
||||
}
|
||||
}
|
||||
else {
|
||||
((Structure) viewComposite).delete(componentOrdinal);
|
||||
dtc = ((Structure) viewComposite).insert(componentOrdinal, dataType, length, name,
|
||||
comment);
|
||||
dtc = viewDTM.withTransaction("Replace Component", () -> {
|
||||
((Structure) viewComposite).delete(componentOrdinal);
|
||||
return ((Structure) viewComposite).insert(componentOrdinal, dataType, length,
|
||||
name, comment);
|
||||
});
|
||||
}
|
||||
return dtc;
|
||||
}
|
||||
@ -1013,47 +1027,53 @@ class StructureEditorModel extends CompEditorModel {
|
||||
overlap.intersect(selection);
|
||||
boolean replacedSelected = (overlap.getNumRanges() > 0);
|
||||
|
||||
// Remove the selected components.
|
||||
deleteComponentRange(startRowIndex, endRowIndex, monitor);
|
||||
|
||||
int beginUndefs = startRowIndex + numComps;
|
||||
// Create the new components.
|
||||
insertMultiple(startRowIndex, datatype, length, numComps, monitor);
|
||||
int indexAfterMultiple = startRowIndex + numComps;
|
||||
if (replacedSelected) {
|
||||
selection.addRange(startRowIndex, indexAfterMultiple);
|
||||
fixSelection();
|
||||
}
|
||||
|
||||
DataTypeComponent comp = getComponent(startRowIndex);
|
||||
// Set the field name and comment the same as before
|
||||
int txId = viewDTM.startTransaction("Replace Multiple");
|
||||
try {
|
||||
comp.setFieldName(fieldName);
|
||||
}
|
||||
catch (DuplicateNameException exc) {
|
||||
Msg.showError(this, null, null, null);
|
||||
}
|
||||
comp.setComment(comment);
|
||||
// Remove the selected components.
|
||||
deleteComponentRange(startRowIndex, endRowIndex, monitor);
|
||||
|
||||
// Create any needed undefined data types.
|
||||
int remainingLength = numBytesInRange - (numComps * length);
|
||||
if (remainingLength > 0 && isShowingUndefinedBytes()) {
|
||||
int beginUndefs = startRowIndex + numComps;
|
||||
// Create the new components.
|
||||
insertMultiple(startRowIndex, datatype, length, numComps, monitor);
|
||||
int indexAfterMultiple = startRowIndex + numComps;
|
||||
if (replacedSelected) {
|
||||
selection.addRange(startRowIndex, indexAfterMultiple);
|
||||
fixSelection();
|
||||
}
|
||||
|
||||
DataTypeComponent comp = getComponent(startRowIndex);
|
||||
// Set the field name and comment the same as before
|
||||
try {
|
||||
insertComponentMultiple(beginUndefs, DataType.DEFAULT, DataType.DEFAULT.getLength(),
|
||||
remainingLength, monitor);
|
||||
if (replacedSelected) {
|
||||
selection.addRange(indexAfterMultiple, indexAfterMultiple + remainingLength);
|
||||
comp.setFieldName(fieldName);
|
||||
}
|
||||
catch (DuplicateNameException exc) {
|
||||
Msg.showError(this, null, null, null);
|
||||
}
|
||||
comp.setComment(comment);
|
||||
|
||||
// Create any needed undefined data types.
|
||||
int remainingLength = numBytesInRange - (numComps * length);
|
||||
if (remainingLength > 0 && isShowingUndefinedBytes()) {
|
||||
try {
|
||||
insertComponentMultiple(beginUndefs, DataType.DEFAULT,
|
||||
DataType.DEFAULT.getLength(), remainingLength, monitor);
|
||||
if (replacedSelected) {
|
||||
selection.addRange(indexAfterMultiple,
|
||||
indexAfterMultiple + remainingLength);
|
||||
}
|
||||
}
|
||||
catch (InvalidDataTypeException idte) {
|
||||
Msg.showError(this, null, "Structure Editor Error", idte.getMessage());
|
||||
}
|
||||
}
|
||||
catch (InvalidDataTypeException idte) {
|
||||
Msg.showError(this, null, "Structure Editor Error", idte.getMessage());
|
||||
else if (remainingLength < 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (remainingLength < 0) {
|
||||
return false;
|
||||
finally {
|
||||
viewDTM.endTransaction(txId, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1068,28 +1088,30 @@ class StructureEditorModel extends CompEditorModel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
void removeDtFromComponents(Composite comp) {
|
||||
DataType newDt = viewDTM.getDataType(comp.getDataTypePath());
|
||||
if (newDt == null) {
|
||||
return;
|
||||
}
|
||||
int num = getNumComponents();
|
||||
for (int i = num - 1; i >= 0; i--) {
|
||||
DataTypeComponent dtc = getComponent(i);
|
||||
DataType dt = dtc.getDataType();
|
||||
if (dt instanceof Composite) {
|
||||
Composite dtcComp = (Composite) dt;
|
||||
if (dtcComp.isPartOf(newDt)) {
|
||||
clearComponents(new int[] { i });
|
||||
String msg =
|
||||
"Components containing " + comp.getDisplayName() + " were cleared.";
|
||||
setStatus(msg, true);
|
||||
boolean clearedComponents = viewDTM.withTransaction("Remove Components", () -> {
|
||||
boolean cleared = false;
|
||||
int num = getNumComponents();
|
||||
for (int i = num - 1; i >= 0; i--) {
|
||||
DataTypeComponent dtc = getComponent(i);
|
||||
DataType dt = dtc.getDataType();
|
||||
if (dt instanceof Composite) {
|
||||
Composite dtcComp = (Composite) dt;
|
||||
if (dtcComp.isPartOf(newDt)) {
|
||||
clearComponents(new int[] { i });
|
||||
cleared = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cleared;
|
||||
});
|
||||
if (clearedComponents) {
|
||||
setStatus("Components containing " + comp.getDisplayName() + " were cleared.", true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1203,27 +1225,35 @@ class StructureEditorModel extends CompEditorModel {
|
||||
}
|
||||
|
||||
DataType addedDataType = createDataTypeInOriginalDTM(structureDataType);
|
||||
if (viewComposite.isPackingEnabled()) {
|
||||
deleteSelectedComponents();
|
||||
insert(minRow, addedDataType, addedDataType.getLength());
|
||||
|
||||
int txId = viewDTM.startTransaction("Replace w/Structure");
|
||||
try {
|
||||
if (viewComposite.isPackingEnabled()) {
|
||||
deleteSelectedComponents();
|
||||
insert(minRow, addedDataType, addedDataType.getLength());
|
||||
}
|
||||
else {
|
||||
int adjustmentBytes = 0;
|
||||
if (firstDtc != null && firstDtc.isBitFieldComponent() && minRow > 0) {
|
||||
DataTypeComponent dtc = getComponent(minRow - 1);
|
||||
if (dtc.getEndOffset() == firstDtc.getOffset()) {
|
||||
++adjustmentBytes;
|
||||
}
|
||||
}
|
||||
if (lastDtc != null && lastDtc.isBitFieldComponent() &&
|
||||
maxRow < getNumComponents()) {
|
||||
DataTypeComponent dtc = getComponent(maxRow);
|
||||
if (dtc.getOffset() == lastDtc.getEndOffset()) {
|
||||
++adjustmentBytes;
|
||||
}
|
||||
}
|
||||
clearSelectedComponents();
|
||||
insertMultiple(minRow, DataType.DEFAULT, 1, adjustmentBytes, monitor);
|
||||
replace(minRow, addedDataType, addedDataType.getLength());
|
||||
}
|
||||
}
|
||||
else {
|
||||
int adjustmentBytes = 0;
|
||||
if (firstDtc != null && firstDtc.isBitFieldComponent() && minRow > 0) {
|
||||
DataTypeComponent dtc = getComponent(minRow - 1);
|
||||
if (dtc.getEndOffset() == firstDtc.getOffset()) {
|
||||
++adjustmentBytes;
|
||||
}
|
||||
}
|
||||
if (lastDtc != null && lastDtc.isBitFieldComponent() && maxRow < getNumComponents()) {
|
||||
DataTypeComponent dtc = getComponent(maxRow);
|
||||
if (dtc.getOffset() == lastDtc.getEndOffset()) {
|
||||
++adjustmentBytes;
|
||||
}
|
||||
}
|
||||
clearSelectedComponents();
|
||||
insertMultiple(minRow, DataType.DEFAULT, 1, adjustmentBytes, monitor);
|
||||
replace(minRow, addedDataType, addedDataType.getLength());
|
||||
finally {
|
||||
viewDTM.endTransaction(txId, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1263,7 +1293,6 @@ class StructureEditorModel extends CompEditorModel {
|
||||
|
||||
private DataType createDataTypeInOriginalDTM(StructureDataType structureDataType) {
|
||||
boolean commit = false;
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
int transactionID =
|
||||
originalDTM.startTransaction("Create structure " + structureDataType.getName());
|
||||
try {
|
||||
@ -1300,81 +1329,83 @@ class StructureEditorModel extends CompEditorModel {
|
||||
endFieldEditing();
|
||||
}
|
||||
|
||||
Structure viewStruct = (Structure) viewComposite;
|
||||
viewDTM.withTransaction("Unpack Component", () -> {
|
||||
Structure viewStruct = (Structure) viewComposite;
|
||||
|
||||
// Get the field name and comment before removing.
|
||||
String fieldName = currentComp.getFieldName();
|
||||
String comment = currentComp.getComment();
|
||||
int numComps = 0;
|
||||
// This component is an array so unpackage it.
|
||||
if (currentDataType instanceof Array) {
|
||||
Array array = (Array) currentDataType;
|
||||
int elementLen = array.getElementLength();
|
||||
numComps = array.getNumElements();
|
||||
// Remove the array.
|
||||
delete(componentOrdinal);
|
||||
if (numComps > 0) {
|
||||
// Add the array's elements
|
||||
try {
|
||||
DataType dt = array.getDataType();
|
||||
insertMultiple(rowIndex, dt, elementLen, numComps, monitor);
|
||||
}
|
||||
catch (InvalidDataTypeException ie) {
|
||||
// Do nothing.
|
||||
}
|
||||
catch (OutOfMemoryError memExc) {
|
||||
throw memExc; // rethrow the exception.
|
||||
// Get the field name and comment before removing.
|
||||
String fieldName = currentComp.getFieldName();
|
||||
String comment = currentComp.getComment();
|
||||
int numComps = 0;
|
||||
// This component is an array so unpackage it.
|
||||
if (currentDataType instanceof Array) {
|
||||
Array array = (Array) currentDataType;
|
||||
int elementLen = array.getElementLength();
|
||||
numComps = array.getNumElements();
|
||||
// Remove the array.
|
||||
delete(componentOrdinal);
|
||||
if (numComps > 0) {
|
||||
// Add the array's elements
|
||||
try {
|
||||
DataType dt = array.getDataType();
|
||||
insertMultiple(rowIndex, dt, elementLen, numComps, monitor);
|
||||
}
|
||||
catch (InvalidDataTypeException ie) {
|
||||
// Do nothing.
|
||||
}
|
||||
catch (OutOfMemoryError memExc) {
|
||||
throw memExc; // rethrow the exception.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// This component is a structure so unpackage it.
|
||||
else if (currentDataType instanceof Structure) {
|
||||
Structure struct = (Structure) currentDataType;
|
||||
numComps = struct.getNumComponents();
|
||||
if (numComps > 0) {
|
||||
// Remove the structure.
|
||||
int currentOffset = currentComp.getOffset();
|
||||
deleteComponent(rowIndex);
|
||||
// This component is a structure so unpackage it.
|
||||
else if (currentDataType instanceof Structure) {
|
||||
Structure struct = (Structure) currentDataType;
|
||||
numComps = struct.getNumComponents();
|
||||
if (numComps > 0) {
|
||||
// Remove the structure.
|
||||
int currentOffset = currentComp.getOffset();
|
||||
deleteComponent(rowIndex);
|
||||
|
||||
// Add the structure's elements
|
||||
for (int i = 0; i < numComps; i++) {
|
||||
DataTypeComponent dtc = struct.getComponent(i);
|
||||
DataType dt = dtc.getDataType();
|
||||
int compLength = dtc.getLength();
|
||||
if (!isPackingEnabled()) {
|
||||
if (dtc.isBitFieldComponent()) {
|
||||
BitFieldDataType bitfield = (BitFieldDataType) dt;
|
||||
viewStruct.insertBitFieldAt(currentOffset + dtc.getOffset(), compLength,
|
||||
bitfield.getBitOffset(), bitfield.getBaseDataType(),
|
||||
bitfield.getDeclaredBitSize(), dtc.getFieldName(),
|
||||
dtc.getComment());
|
||||
// Add the structure's elements
|
||||
for (int i = 0; i < numComps; i++) {
|
||||
DataTypeComponent dtc = struct.getComponent(i);
|
||||
DataType dt = dtc.getDataType();
|
||||
int compLength = dtc.getLength();
|
||||
if (!isPackingEnabled()) {
|
||||
if (dtc.isBitFieldComponent()) {
|
||||
BitFieldDataType bitfield = (BitFieldDataType) dt;
|
||||
viewStruct.insertBitFieldAt(currentOffset + dtc.getOffset(),
|
||||
compLength, bitfield.getBitOffset(), bitfield.getBaseDataType(),
|
||||
bitfield.getDeclaredBitSize(), dtc.getFieldName(),
|
||||
dtc.getComment());
|
||||
}
|
||||
else {
|
||||
viewStruct.insertAtOffset(currentOffset + dtc.getOffset(), dt,
|
||||
compLength, dtc.getFieldName(), dtc.getComment());
|
||||
}
|
||||
}
|
||||
else {
|
||||
viewStruct.insertAtOffset(currentOffset + dtc.getOffset(), dt,
|
||||
compLength, dtc.getFieldName(), dtc.getComment());
|
||||
insert(rowIndex + i, dt, compLength, dtc.getFieldName(),
|
||||
dtc.getComment());
|
||||
}
|
||||
}
|
||||
else {
|
||||
insert(rowIndex + i, dt, compLength, dtc.getFieldName(), dtc.getComment());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
selection.clear();
|
||||
selection.addRange(rowIndex, rowIndex + numComps);
|
||||
selection.clear();
|
||||
selection.addRange(rowIndex, rowIndex + numComps);
|
||||
|
||||
DataTypeComponent comp = getComponent(rowIndex);
|
||||
// Set the field name and comment the same as before
|
||||
try {
|
||||
if (comp.getFieldName() == null) {
|
||||
comp.setFieldName(fieldName);
|
||||
DataTypeComponent comp = getComponent(rowIndex);
|
||||
// Set the field name and comment the same as before
|
||||
try {
|
||||
if (comp.getFieldName() == null) {
|
||||
comp.setFieldName(fieldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (DuplicateNameException exc) {
|
||||
Msg.showError(this, null, null, null);
|
||||
}
|
||||
comp.setComment(comment);
|
||||
|
||||
catch (DuplicateNameException exc) {
|
||||
Msg.showError(this, null, null, null);
|
||||
}
|
||||
comp.setComment(comment);
|
||||
});
|
||||
fixSelection();
|
||||
componentEdited();
|
||||
selectionChanged();
|
||||
|
@ -59,6 +59,8 @@ public class StructureEditorProvider extends CompositeEditorProvider {
|
||||
//@formatter:off
|
||||
return new CompositeEditorTableAction[] {
|
||||
new ApplyAction(this),
|
||||
new UndoChangeAction(this),
|
||||
new RedoChangeAction(this),
|
||||
// new ToggleLockAction(this),
|
||||
new InsertUndefinedAction(this),
|
||||
new MoveUpAction(this),
|
||||
@ -117,12 +119,11 @@ public class StructureEditorProvider extends CompositeEditorProvider {
|
||||
|
||||
int[] selectedRows = editorModel.getSelectedRows();
|
||||
|
||||
// TODO: Add w/ GP-4740 merge
|
||||
// if (editorPanel.hasInvalidEntry() || editorPanel.hasUncomittedEntry() ||
|
||||
// selectedRows.length != 1 || editorModel.viewComposite.isPackingEnabled()) {
|
||||
// Msg.error(this, "Unsupported add bitfield editor use");
|
||||
// return;
|
||||
// }
|
||||
if (editorPanel.hasInvalidEntry() || editorPanel.hasUncomittedEntry() ||
|
||||
selectedRows.length != 1 || editorModel.viewComposite.isPackingEnabled()) {
|
||||
Msg.error(this, "Unsupported add bitfield editor use");
|
||||
return;
|
||||
}
|
||||
|
||||
bitFieldEditor =
|
||||
new BitFieldEditorDialog(editorModel.viewComposite, dtmService, -(selectedRows[0] + 1),
|
||||
@ -164,5 +165,4 @@ public class StructureEditorProvider extends CompositeEditorProvider {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,63 @@
|
||||
/* ###
|
||||
* 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 javax.swing.Icon;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.KeyBindingData;
|
||||
import generic.theme.GIcon;
|
||||
|
||||
/**
|
||||
* {@link UndoChangeAction} facilitates an undo of recent composite editor changes.
|
||||
*/
|
||||
public class UndoChangeAction extends CompositeEditorTableAction {
|
||||
|
||||
public static String DESCRIPTION = "Undo Change";
|
||||
public final static String ACTION_NAME = "Undo Editor Change";
|
||||
private final static String GROUP_NAME = UNDOREDO_ACTION_GROUP;
|
||||
private final static Icon ICON = new GIcon("icon.undo");
|
||||
private final static String[] POPUP_PATH = new String[] { DESCRIPTION };
|
||||
|
||||
public UndoChangeAction(CompositeEditorProvider provider) {
|
||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||
setKeyBindingData(new KeyBindingData("ctrl Z"));
|
||||
setDescription(DESCRIPTION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
CompositeViewerDataTypeManager viewDTM = model.getViewDataTypeManager();
|
||||
viewDTM.undo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
if (hasIncompleteFieldEntry()) {
|
||||
return false;
|
||||
}
|
||||
CompositeViewerDataTypeManager viewDTM = model.getViewDataTypeManager();
|
||||
boolean canUndo = viewDTM.canUndo();
|
||||
setEnabled(canUndo);
|
||||
String description = DESCRIPTION + (canUndo ? (": " + viewDTM.getUndoName()) : "");
|
||||
setDescription(description);
|
||||
return canUndo;
|
||||
}
|
||||
|
||||
}
|
@ -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 java.math.BigInteger;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import javax.help.UnsupportedOperationException;
|
||||
|
||||
import docking.widgets.fieldpanel.support.FieldRange;
|
||||
import docking.widgets.fieldpanel.support.FieldSelection;
|
||||
@ -63,6 +64,11 @@ class UnionEditorModel extends CompEditorModel {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "Union";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOffsetColumn() {
|
||||
return -1;
|
||||
@ -171,11 +177,6 @@ class UnionEditorModel extends CompEditorModel {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearComponent(int rowIndex) {
|
||||
// clearing not supported
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the selected components
|
||||
*
|
||||
@ -345,8 +346,9 @@ class UnionEditorModel extends CompEditorModel {
|
||||
if (range != null) {
|
||||
// Determine the number of bytes.
|
||||
// Get the size of the range.
|
||||
for (int i =
|
||||
range.getStart().getIndex().intValue(); i < range.getEnd().getIndex().intValue(); i++) {
|
||||
for (int i = range.getStart().getIndex().intValue(); i < range.getEnd()
|
||||
.getIndex()
|
||||
.intValue(); i++) {
|
||||
DataTypeComponent comp = getComponent(i);
|
||||
numBytesInRange = Math.max(numBytesInRange, comp.getLength());
|
||||
}
|
||||
@ -378,10 +380,10 @@ class UnionEditorModel extends CompEditorModel {
|
||||
String comment) throws InvalidDataTypeException {
|
||||
checkIsAllowableDataType(dataType);
|
||||
try {
|
||||
DataTypeComponent dtc =
|
||||
((Union) viewComposite).insert(rowIndex, dataType, length, name, comment);
|
||||
if (rowIndex <= row) {
|
||||
row++;
|
||||
DataTypeComponent dtc = viewDTM.withTransaction("Add Component",
|
||||
() -> ((Union) viewComposite).insert(rowIndex, dataType, length, name, comment));
|
||||
if (rowIndex <= currentEditRow) {
|
||||
currentEditRow++;
|
||||
}
|
||||
adjustSelection(rowIndex, 1);
|
||||
notifyCompositeChanged();
|
||||
@ -395,12 +397,17 @@ class UnionEditorModel extends CompEditorModel {
|
||||
@Override
|
||||
public void insert(int rowIndex, DataType dataType, int length, int numCopies,
|
||||
TaskMonitor monitor) throws InvalidDataTypeException, CancelledException {
|
||||
|
||||
monitor.initialize(numCopies);
|
||||
for (int i = 0; i < numCopies; i++) {
|
||||
monitor.checkCancelled();
|
||||
insert(rowIndex + i, dataType, length, null, null);
|
||||
monitor.incrementProgress(1);
|
||||
int txId = viewDTM.startTransaction("Insert Multiple");
|
||||
try {
|
||||
monitor.initialize(numCopies);
|
||||
for (int i = 0; i < numCopies; i++) {
|
||||
monitor.checkCancelled();
|
||||
insert(rowIndex + i, dataType, length, null, null);
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
viewDTM.endTransaction(txId, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -410,9 +417,10 @@ class UnionEditorModel extends CompEditorModel {
|
||||
checkIsAllowableDataType(dataType);
|
||||
try {
|
||||
boolean isSelected = selection.containsEntirely(BigInteger.valueOf(rowIndex));
|
||||
((Union) viewComposite).delete(rowIndex);
|
||||
DataTypeComponent dtc =
|
||||
((Union) viewComposite).insert(rowIndex, dataType, length, name, comment);
|
||||
DataTypeComponent dtc = viewDTM.withTransaction("Replace Component", () -> {
|
||||
((Union) viewComposite).delete(rowIndex);
|
||||
return ((Union) viewComposite).insert(rowIndex, dataType, length, name, comment);
|
||||
});
|
||||
if (isSelected) {
|
||||
selection.addRange(rowIndex, rowIndex + 1);
|
||||
fixSelection();
|
||||
@ -456,12 +464,20 @@ class UnionEditorModel extends CompEditorModel {
|
||||
FieldSelection overlap = new FieldSelection();
|
||||
overlap.addRange(startRowIndex, endRowIndex + 1);
|
||||
overlap.intersect(selection);
|
||||
|
||||
// Union just replaces entire selection range with single instance of new component.
|
||||
deleteComponentRange(startRowIndex, endRowIndex, monitor);
|
||||
|
||||
boolean replacedSelected = (overlap.getNumRanges() > 0);
|
||||
insert(startRowIndex, datatype, length, null, null);
|
||||
|
||||
int txId = viewDTM.startTransaction("Insert Multiple");
|
||||
try {
|
||||
|
||||
// Union just replaces entire selection range with single instance of new component.
|
||||
deleteComponentRange(startRowIndex, endRowIndex, monitor);
|
||||
|
||||
insert(startRowIndex, datatype, length, null, null);
|
||||
}
|
||||
finally {
|
||||
viewDTM.endTransaction(txId, true);
|
||||
}
|
||||
|
||||
if (replacedSelected) {
|
||||
selection.addRange(startRowIndex, startRowIndex + 1);
|
||||
fixSelection();
|
||||
@ -475,30 +491,38 @@ class UnionEditorModel extends CompEditorModel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearComponents(int[] rows) throws UsrException {
|
||||
throw new UsrException("Can't clear components in a union.");
|
||||
protected void clearComponent(int rowIndex) {
|
||||
throw new UnsupportedOperationException("Can't clear components in a union.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearComponents(int[] rows) {
|
||||
throw new UnsupportedOperationException("Can't clear components in a union.");
|
||||
}
|
||||
|
||||
@Override
|
||||
void removeDtFromComponents(Composite comp) {
|
||||
DataType newDt = viewDTM.getDataType(comp.getDataTypePath());
|
||||
DataTypePath path = comp.getDataTypePath();
|
||||
DataType newDt = viewDTM.getDataType(path);
|
||||
if (newDt == null) {
|
||||
return;
|
||||
}
|
||||
int num = getNumComponents();
|
||||
for (int i = num - 1; i >= 0; i--) {
|
||||
DataTypeComponent dtc = getComponent(i);
|
||||
DataType dt = dtc.getDataType();
|
||||
if (dt instanceof Composite) {
|
||||
Composite dtcComp = (Composite) dt;
|
||||
if (dtcComp.isPartOf(newDt)) {
|
||||
deleteComponent(i);
|
||||
String msg =
|
||||
"Components containing " + comp.getDisplayName() + " were removed.";
|
||||
setStatus(msg, true);
|
||||
viewDTM.withTransaction("Remove use of " + path, () -> {
|
||||
int num = getNumComponents();
|
||||
for (int i = num - 1; i >= 0; i--) {
|
||||
DataTypeComponent dtc = getComponent(i);
|
||||
DataType dt = dtc.getDataType();
|
||||
if (dt instanceof Composite) {
|
||||
Composite dtcComp = (Composite) dt;
|
||||
if (dtcComp.isPartOf(newDt)) {
|
||||
deleteComponent(i);
|
||||
String msg =
|
||||
"Components containing " + comp.getDisplayName() + " were removed.";
|
||||
setStatus(msg, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -533,22 +557,6 @@ class UnionEditorModel extends CompEditorModel {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes the number of undefined bytes requested if they are available.
|
||||
*
|
||||
* @param rowIndex index of the row (component).
|
||||
* @param numDesired the number of Undefined bytes desired.
|
||||
* @return the number of components removed from the structure when the
|
||||
* bytes were consumed.
|
||||
* @throws java.util.NoSuchElementException if the index is invalid.
|
||||
* @throws InvalidDataTypeException if there aren't enough bytes.
|
||||
*/
|
||||
@Override
|
||||
protected int consumeUndefinedBytes(int rowIndex, int numDesired)
|
||||
throws NoSuchElementException, InvalidDataTypeException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowingUndefinedBytes() {
|
||||
return false;
|
||||
|
@ -28,8 +28,4 @@ public class UnionEditorPanel extends CompEditorPanel {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean choosePacking() {
|
||||
return true; // packing is not destructive to unions, so safe to use without prompting
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,8 @@ public class UnionEditorProvider extends CompositeEditorProvider {
|
||||
//@formatter:off
|
||||
return new CompositeEditorTableAction[] {
|
||||
new ApplyAction(this),
|
||||
new UndoChangeAction(this),
|
||||
new RedoChangeAction(this),
|
||||
new MoveUpAction(this),
|
||||
new MoveDownAction(this),
|
||||
new DuplicateAction(this),
|
||||
|
@ -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.
|
||||
@ -46,11 +46,13 @@ public class UnpackageAction extends CompositeEditorTableAction {
|
||||
super(provider, ACTION_NAME, GROUP_NAME, POPUP_PATH, null, ICON);
|
||||
setDescription(DESCRIPTION);
|
||||
setKeyBindingData(new KeyBindingData(KEY_STROKE));
|
||||
adjustEnablement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
if (!isEnabledForContext(context)) {
|
||||
return;
|
||||
}
|
||||
// If lots of components, verify the user really wants to unpackage.
|
||||
int currentRowIndex =
|
||||
model.getSelection().getFieldRange(0).getStart().getIndex().intValue();
|
||||
@ -60,7 +62,7 @@ public class UnpackageAction extends CompositeEditorTableAction {
|
||||
String title = "Continue with unpackage?";
|
||||
int response =
|
||||
OptionDialog.showYesNoDialog(model.getProvider().getComponent(), title, question);
|
||||
if (response != 1) { // User did not select yes.
|
||||
if (response != OptionDialog.YES_OPTION) { // User did not select yes.
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -85,7 +87,7 @@ public class UnpackageAction extends CompositeEditorTableAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustEnablement() {
|
||||
setEnabled(model.isUnpackageAllowed());
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return !hasIncompleteFieldEntry() && model.isUnpackageAllowed();
|
||||
}
|
||||
}
|
||||
|
@ -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,12 +165,6 @@ public class DataTypesProvider extends ComponentProviderAdapter {
|
||||
addLocalAction(new DeleteArchiveAction(plugin));
|
||||
addLocalAction(new RenameAction(plugin));
|
||||
addLocalAction(new EditAction(plugin));
|
||||
// NOTE: it make very little sense to blindly enable packing
|
||||
// addLocalAction(new PackDataTypeAction(plugin));
|
||||
// addLocalAction( new PackDataTypeAction( plugin ));
|
||||
// addLocalAction( new PackSizeDataTypeAction( plugin ));
|
||||
// addLocalAction(new PackAllDataTypesAction(plugin));
|
||||
// addLocalAction( new DefineDataTypeAlignmentAction( plugin ));
|
||||
addLocalAction(new CreateEnumFromSelectionAction(plugin));
|
||||
|
||||
// File group
|
||||
|
@ -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.
|
||||
@ -109,8 +109,7 @@ public class DeleteAction extends DockingAction {
|
||||
"Confirm Delete Operation",
|
||||
"Are you sure you want to delete selected\n" +
|
||||
"data types and/or categories?\n\n" +
|
||||
"Note: There is no undo for archives and\n" +
|
||||
"changes may trigger the removal of related\n" +
|
||||
"Note: Changes may trigger the removal of related\n" +
|
||||
"data types, components and defined data.)");
|
||||
//@formatter:on
|
||||
if (choice != OptionDialog.OPTION_ONE) {
|
||||
|
@ -1,101 +0,0 @@
|
||||
/* ###
|
||||
* 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.datamgr.actions;
|
||||
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.tree.GTree;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeTreeNode;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class Pack1DataTypeAction extends DockingAction {
|
||||
|
||||
private DataTypeManagerPlugin plugin;
|
||||
|
||||
public Pack1DataTypeAction(DataTypeManagerPlugin plugin) {
|
||||
super("Pack1 Data Type", plugin.getName());
|
||||
this.plugin = plugin;
|
||||
setPopupMenuData(new MenuData(new String[] { "Pack (1)" }, "Edit"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
Object contextObject = context.getContextObject();
|
||||
if (!(contextObject instanceof GTree)) {
|
||||
return false;
|
||||
}
|
||||
GTree gTree = (GTree) contextObject;
|
||||
TreePath[] selectionPaths = gTree.getSelectionPaths();
|
||||
if (selectionPaths.length != 1) {
|
||||
return false;
|
||||
}
|
||||
DataTypeTreeNode node = (DataTypeTreeNode) selectionPaths[0].getLastPathComponent();
|
||||
|
||||
if (!(node instanceof DataTypeNode)) {
|
||||
return false;
|
||||
}
|
||||
setEnabled(node.isModifiable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
GTree gTree = (GTree) context.getContextObject();
|
||||
TreePath[] selectionPaths = gTree.getSelectionPaths();
|
||||
if (selectionPaths.length != 1) {
|
||||
Msg.error(this, "Pack is only allowed on an individual data type.");
|
||||
return;
|
||||
}
|
||||
TreePath treePath = selectionPaths[0];
|
||||
final DataTypeNode dataTypeNode = (DataTypeNode) treePath.getLastPathComponent();
|
||||
DataType dataType = dataTypeNode.getDataType();
|
||||
DataTypeManager dataTypeManager = dataType.getDataTypeManager();
|
||||
if (dataTypeManager == null) {
|
||||
Msg.error(this,
|
||||
"Can't pack data type " + dataType.getName() + " without a data type manager.");
|
||||
return;
|
||||
}
|
||||
|
||||
int transactionID = -1;
|
||||
boolean commit = false;
|
||||
try {
|
||||
// start a transaction
|
||||
transactionID = dataTypeManager.startTransaction("Pack(1) " + dataType.getName());
|
||||
packDataType(dataType);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
// commit the changes
|
||||
dataTypeManager.endTransaction(transactionID, commit);
|
||||
}
|
||||
}
|
||||
|
||||
private void packDataType(DataType dataType) {
|
||||
if (!(dataType instanceof Composite)) {
|
||||
Msg.error(this,
|
||||
"Can't pack data type " + dataType.getName() + ". It's not a composite.");
|
||||
return;
|
||||
}
|
||||
((Composite) dataType).pack(1);
|
||||
}
|
||||
|
||||
}
|
@ -1,136 +0,0 @@
|
||||
/* ###
|
||||
* 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.datamgr.actions;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.tree.GTree;
|
||||
import docking.widgets.tree.GTreeNode;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.archive.Archive;
|
||||
import ghidra.app.plugin.core.datamgr.tree.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class PackAllDataTypesAction extends DockingAction {
|
||||
|
||||
private DataTypeManagerPlugin plugin;
|
||||
|
||||
public PackAllDataTypesAction(DataTypeManagerPlugin plugin) {
|
||||
super("Pack All Composites", plugin.getName());
|
||||
this.plugin = plugin;
|
||||
|
||||
setPopupMenuData(new MenuData(new String[] { "Pack All..." }, "Edit"));
|
||||
// setHelpLocation(new HelpLocation(plugin.getName(), getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
Object contextObject = context.getContextObject();
|
||||
if (!(contextObject instanceof GTree)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GTree gTree = (GTree) contextObject;
|
||||
TreePath[] selectionPaths = gTree.getSelectionPaths();
|
||||
if (selectionPaths == null || selectionPaths.length != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GTreeNode node = (GTreeNode) selectionPaths[0].getLastPathComponent();
|
||||
if ((node instanceof ProgramArchiveNode) || (node instanceof ProjectArchiveNode) ||
|
||||
(node instanceof FileArchiveNode)) {
|
||||
ArchiveNode archiveNode = (ArchiveNode) node;
|
||||
if (!archiveNode.isEnabled()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
GTree gTree = (GTree) context.getContextObject();
|
||||
TreePath[] selectionPaths = gTree.getSelectionPaths();
|
||||
GTreeNode node = (GTreeNode) selectionPaths[0].getLastPathComponent();
|
||||
if ((node instanceof ProgramArchiveNode) || (node instanceof ProjectArchiveNode) ||
|
||||
(node instanceof FileArchiveNode)) {
|
||||
ArchiveNode archiveNode = (ArchiveNode) node;
|
||||
Archive archive = archiveNode.getArchive();
|
||||
if (archive.isModifiable()) {
|
||||
DataTypeManager dataTypeManager = archive.getDataTypeManager();
|
||||
DataOrganization dataOrganization = dataTypeManager.getDataOrganization();
|
||||
|
||||
int result =
|
||||
OptionDialog.showOptionDialog(
|
||||
plugin.getTool().getToolFrame(),
|
||||
"Pack All Composites",
|
||||
"Are you sure you want to enable packing of all non-packed composites in " +
|
||||
dataTypeManager.getName() +
|
||||
"?\nAll structures and unions that are not currently packed will default packing enabled.\n" +
|
||||
"This could cause component offsets to change as well as size and alignment of these data types to change.\n" +
|
||||
"Do you want to continue?", "Continue", OptionDialog.WARNING_MESSAGE);
|
||||
if (result == OptionDialog.CANCEL_OPTION) {
|
||||
return;
|
||||
}
|
||||
packDataTypes(dataTypeManager, dataOrganization);
|
||||
}
|
||||
else {
|
||||
Msg.showWarn(this, gTree, "Modification Not Allowed",
|
||||
"The archive must be modifiable to pack data types.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void packDataTypes(DataTypeManager dataTypeManager, DataOrganization dataOrganization) {
|
||||
if (dataTypeManager == null) {
|
||||
Msg.error(this, "Can't pack data types without a data type manager.");
|
||||
return;
|
||||
}
|
||||
int transactionID = -1;
|
||||
boolean commit = false;
|
||||
try {
|
||||
// start a transaction
|
||||
transactionID =
|
||||
dataTypeManager.startTransaction("Pack Composite Types");
|
||||
packEachStructure(dataTypeManager, dataOrganization);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
// commit the changes
|
||||
dataTypeManager.endTransaction(transactionID, commit);
|
||||
}
|
||||
}
|
||||
|
||||
private void packEachStructure(DataTypeManager dataTypeManager,
|
||||
DataOrganization dataOrganization) {
|
||||
Iterator<? extends Composite> allComposites = dataTypeManager.getAllComposites();
|
||||
while (allComposites.hasNext()) {
|
||||
Composite composite = allComposites.next();
|
||||
if (!composite.isPackingEnabled()) {
|
||||
composite.setPackingEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
/* ###
|
||||
* 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.datamgr.actions;
|
||||
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.tree.GTree;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeTreeNode;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class PackDataTypeAction extends DockingAction {
|
||||
|
||||
public PackDataTypeAction(DataTypeManagerPlugin plugin) {
|
||||
super("Pack Data Type", plugin.getName());
|
||||
setPopupMenuData(new MenuData(new String[] { "Pack (default)" }, "Edit"));
|
||||
// setHelpLocation(new HelpLocation(plugin.getName(), getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAddToPopup(ActionContext context) {
|
||||
DataTypeNode node = getSelectedDataTypeNode(context);
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
DataType dataType = node.getDataType();
|
||||
if (dataType instanceof BuiltInDataType || dataType instanceof Pointer ||
|
||||
dataType instanceof MissingBuiltInDataType) {
|
||||
return false;
|
||||
}
|
||||
if (!node.isModifiable()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
DataTypeNode node = getSelectedDataTypeNode(context);
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
DataType dataType = node.getDataType();
|
||||
if (dataType instanceof Composite) {
|
||||
return !((Composite) dataType).isPackingEnabled();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private DataTypeNode getSelectedDataTypeNode(ActionContext context) {
|
||||
Object contextObject = context.getContextObject();
|
||||
if (!(contextObject instanceof GTree)) {
|
||||
return null;
|
||||
}
|
||||
GTree gTree = (GTree) contextObject;
|
||||
TreePath[] selectionPaths = gTree.getSelectionPaths();
|
||||
if (selectionPaths.length != 1) {
|
||||
return null;
|
||||
}
|
||||
DataTypeTreeNode node = (DataTypeTreeNode) selectionPaths[0].getLastPathComponent();
|
||||
|
||||
if (!(node instanceof DataTypeNode)) {
|
||||
return null;
|
||||
}
|
||||
return (DataTypeNode) node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
GTree gTree = (GTree) context.getContextObject();
|
||||
TreePath[] selectionPaths = gTree.getSelectionPaths();
|
||||
for (TreePath treePath : selectionPaths) {
|
||||
final DataTypeNode dataTypeNode = (DataTypeNode) treePath.getLastPathComponent();
|
||||
DataType dataType = dataTypeNode.getDataType();
|
||||
DataTypeManager dataTypeManager = dataType.getDataTypeManager();
|
||||
DataOrganization dataOrganization = dataTypeManager.getDataOrganization();
|
||||
alignDataType(dataType, dataOrganization);
|
||||
}
|
||||
}
|
||||
|
||||
private void alignDataType(DataType dataType, DataOrganization dataOrganization) {
|
||||
DataTypeManager dataTypeManager = dataType.getDataTypeManager();
|
||||
if (dataTypeManager == null) {
|
||||
Msg.error(this,
|
||||
"Can't align data type " + dataType.getName() + " without a data type manager.");
|
||||
return;
|
||||
}
|
||||
if (!(dataType instanceof Structure)) {
|
||||
Msg.error(this,
|
||||
"Can't align data type " + dataType.getName() + ". It's not a structure.");
|
||||
return;
|
||||
}
|
||||
int transactionID = -1;
|
||||
boolean commit = false;
|
||||
try {
|
||||
// start a transaction
|
||||
transactionID = dataTypeManager.startTransaction("Pack " + dataType.getName());
|
||||
((Structure) dataType).setPackingEnabled(true);
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
// commit the changes
|
||||
dataTypeManager.endTransaction(transactionID, commit);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
/* ###
|
||||
* 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.datamgr.actions;
|
||||
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.dialogs.NumberInputDialog;
|
||||
import docking.widgets.tree.GTree;
|
||||
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeNode;
|
||||
import ghidra.app.plugin.core.datamgr.tree.DataTypeTreeNode;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class PackSizeDataTypeAction extends DockingAction {
|
||||
|
||||
private DataTypeManagerPlugin plugin;
|
||||
|
||||
public PackSizeDataTypeAction(DataTypeManagerPlugin plugin) {
|
||||
super("Pack Size Data Type", plugin.getName());
|
||||
this.plugin = plugin;
|
||||
setPopupMenuData(new MenuData(new String[] { "Pack for Size..." }, "Edit"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
Object contextObject = context.getContextObject();
|
||||
if (!(contextObject instanceof GTree)) {
|
||||
return false;
|
||||
}
|
||||
GTree gTree = (GTree) contextObject;
|
||||
TreePath[] selectionPaths = gTree.getSelectionPaths();
|
||||
if (selectionPaths.length != 1) {
|
||||
return false;
|
||||
}
|
||||
DataTypeTreeNode node = (DataTypeTreeNode) selectionPaths[0].getLastPathComponent();
|
||||
|
||||
if (!(node instanceof DataTypeNode)) {
|
||||
return false;
|
||||
}
|
||||
setEnabled(node.isModifiable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
GTree gTree = (GTree) context.getContextObject();
|
||||
TreePath[] selectionPaths = gTree.getSelectionPaths();
|
||||
TreePath treePath = selectionPaths[0];
|
||||
final DataTypeNode dataTypeNode = (DataTypeNode) treePath.getLastPathComponent();
|
||||
DataType dataType = dataTypeNode.getDataType();
|
||||
DataTypeManager dataTypeManager = dataType.getDataTypeManager();
|
||||
if (dataTypeManager == null) {
|
||||
Msg.error(this,
|
||||
"Can't pack data type " + dataType.getName() + " without a data type manager.");
|
||||
return;
|
||||
}
|
||||
|
||||
NumberInputDialog numberInputDialog =
|
||||
new NumberInputDialog("explicit pack value", 0, 0, 16);
|
||||
if (!numberInputDialog.show()) {
|
||||
return;
|
||||
}
|
||||
int packSize = numberInputDialog.getValue();
|
||||
|
||||
int transactionID = -1;
|
||||
boolean commit = false;
|
||||
try {
|
||||
// start a transaction
|
||||
transactionID =
|
||||
dataTypeManager.startTransaction("Pack(" + packSize + ") " + dataType.getName());
|
||||
packDataType(dataType, packSize);
|
||||
commit = true;
|
||||
}
|
||||
catch (IllegalArgumentException iie) {
|
||||
Msg.showError(this, null, "Invalid Pack Value", iie.getMessage());
|
||||
}
|
||||
finally {
|
||||
// commit the changes
|
||||
dataTypeManager.endTransaction(transactionID, commit);
|
||||
}
|
||||
}
|
||||
|
||||
private void packDataType(DataType dataType, int packSize) throws IllegalArgumentException {
|
||||
if (!(dataType instanceof Composite)) {
|
||||
Msg.error(this,
|
||||
"Can't pack data type " + dataType.getName() + ". It's not a composite.");
|
||||
return;
|
||||
}
|
||||
((Composite) dataType).pack(packSize);
|
||||
}
|
||||
|
||||
}
|
@ -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.
|
||||
@ -32,10 +32,11 @@ import docking.widgets.fieldpanel.support.FieldSelection;
|
||||
* When edit actions occur and there is a selection, the listener's are notified
|
||||
* of the new selection via the listener's overrideSelection method.
|
||||
*/
|
||||
import ghidra.app.plugin.core.compositeeditor.CompositeEditorModel;
|
||||
import ghidra.app.plugin.core.compositeeditor.DataTypeHelper;
|
||||
import ghidra.app.plugin.core.compositeeditor.*;
|
||||
import ghidra.app.util.datatype.EmptyCompositeException;
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
@ -77,6 +78,11 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeName() {
|
||||
return "Stack";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean allowsZeroLengthComponents() {
|
||||
return false;
|
||||
@ -105,8 +111,23 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Composite createViewCompositeFromOriginalComposite(Composite original) {
|
||||
return (Composite) original.copy(original.getDataTypeManager());
|
||||
protected void createViewCompositeFromOriginalComposite(Composite original) {
|
||||
|
||||
if (viewDTM != null) {
|
||||
viewDTM.close();
|
||||
viewDTM = null;
|
||||
}
|
||||
|
||||
// Use temporary standalone view datatype manager which will not manage the viewComposite
|
||||
viewDTM = new CompositeViewerDataTypeManager(originalDTM.getName(), originalDTM);
|
||||
|
||||
// NOTE: StackFrameDataType cannot be resolved
|
||||
viewComposite = (Composite) original.copy(viewDTM);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void restoreEditor() {
|
||||
throw new UnsupportedOperationException("undo/redo not supported");
|
||||
}
|
||||
|
||||
StackFrameDataType getViewComposite() {
|
||||
@ -127,21 +148,10 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
int stackLocalSize = originalStack.getLocalSize();
|
||||
int stackParamOffset = originalStack.getParameterOffset();
|
||||
int stackParamSize = originalStack.getParameterSize();
|
||||
hadChanges = (editReturnAddressOffset != stackReturnAddressOffset) ||
|
||||
hasChanges = (editReturnAddressOffset != stackReturnAddressOffset) ||
|
||||
(editLocalSize != stackLocalSize) || (editParamOffset != stackParamOffset) ||
|
||||
(editParamSize != stackParamSize) || super.updateAndCheckChangeState();
|
||||
return hadChanges;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current dataType name (Structure or Union) as a string.
|
||||
*/
|
||||
@Override
|
||||
protected String getTypeName() {
|
||||
if (viewComposite instanceof StackFrameDataType) {
|
||||
return "Stack";
|
||||
}
|
||||
return super.getTypeName();
|
||||
return hasChanges;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -435,11 +445,6 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
return (StackFrameDataType) viewComposite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearComponent(int ordinal) {
|
||||
((StackFrameDataType) viewComposite).clearComponent(ordinal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearSelectedComponents() throws UsrException {
|
||||
OffsetPairs offsetSelection = getRelOffsetSelection();
|
||||
@ -683,11 +688,6 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
return (getNumSelectedRows() > 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCycleAllowed(CycleGroup cycleGroup) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeleteAllowed() {
|
||||
if (selection.getNumRanges() != 1) {
|
||||
@ -840,7 +840,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
|
||||
/** Gets the original field name within the parent data type for a given row in the editor */
|
||||
private boolean isOriginalFieldName(String testName, int rowIndex) {
|
||||
StackFrameDataType dataType = (StackFrameDataType) getOriginalComposite();
|
||||
StackFrameDataType dataType = getOriginalComposite();
|
||||
String fieldName = getFieldNameAtRow(rowIndex, dataType);
|
||||
return SystemUtilities.isEqual(fieldName, testName);
|
||||
}
|
||||
@ -858,7 +858,11 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
|
||||
@Override
|
||||
public DataTypeComponent add(DataType dataType) throws UsrException {
|
||||
return replace(dataType);
|
||||
int rowIndex = getMinIndexSelected();
|
||||
if (rowIndex < 0) {
|
||||
throw new UsrException("A component must be selected.");
|
||||
}
|
||||
return replace(rowIndex, dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1019,7 +1023,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
newSv.setComment(comment);
|
||||
}
|
||||
}
|
||||
load(new StackFrameDataType(original, dtm));
|
||||
load(new StackFrameDataType(original, viewDTM));
|
||||
clearStatus();
|
||||
return true;
|
||||
}
|
||||
@ -1106,10 +1110,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
return replace(rowIndex, dataType);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
public DataTypeComponent replace(int index, DataType dataType) throws UsrException {
|
||||
private DataTypeComponent replace(int index, DataType dataType) throws UsrException {
|
||||
try {
|
||||
DataTypeInstance dti = getDropDataType(index, dataType);
|
||||
return replace(index, dti.getDataType(), dti.getLength());
|
||||
@ -1121,17 +1122,12 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
|
||||
@Override
|
||||
public DataTypeComponent replace(int index, DataType dt, int dtLength) throws UsrException {
|
||||
|
||||
OffsetPairs offsetSelection = getRelOffsetSelection();
|
||||
int transID = startTransaction("Apply Data Type \"" + dt.getName() + "\"");
|
||||
try {
|
||||
fieldEdited(
|
||||
DataTypeInstance.getDataTypeInstance(dt, dtLength, usesAlignedLengthComponents()),
|
||||
index, getDataTypeColumn());
|
||||
setRelOffsetSelection(offsetSelection);
|
||||
}
|
||||
finally {
|
||||
endTransaction(transID);
|
||||
}
|
||||
fieldEdited(
|
||||
DataTypeInstance.getDataTypeInstance(dt, dtLength, usesAlignedLengthComponents()),
|
||||
index, getDataTypeColumn());
|
||||
setRelOffsetSelection(offsetSelection);
|
||||
return getComponent(index);
|
||||
}
|
||||
|
||||
@ -1159,6 +1155,48 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
return max / dtc.getDataType().getAlignedLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restored(DataTypeManager dataTypeManager) {
|
||||
|
||||
StackFrameDataType sfdt = getOriginalComposite();
|
||||
Function function = sfdt.getFunction();
|
||||
if (function.isDeleted()) {
|
||||
// Cancel Editor.
|
||||
provider.dispose();
|
||||
PluginTool tool = ((StackEditorProvider) provider).getPlugin().getTool();
|
||||
tool.setStatusInfo("Stack Editor was closed for " + provider.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
updateAndCheckChangeState();
|
||||
|
||||
boolean reload = true;
|
||||
if (hasChanges) {
|
||||
// The user has modified the structure so prompt for whether or
|
||||
// not to reload the structure.
|
||||
String question = "The program \"dtm.getName()\" has been restored.\n" + "\"" +
|
||||
currentName + "\" may have changed outside the editor.\n" +
|
||||
"Discard edits and reload the Stack Editor?";
|
||||
String title = "Reload Stack Editor?";
|
||||
int response = OptionDialog
|
||||
.showYesNoDialogWithNoAsDefaultButton(provider.getComponent(), title, question);
|
||||
if (response != 1) {
|
||||
reload = false;
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
else {
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeChanged(DataTypeManager dataTypeManager, DataTypePath path) {
|
||||
if (isLoaded()) {
|
||||
@ -1235,10 +1273,18 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stack frame model datatype being edited
|
||||
* @return stack frame model datatype
|
||||
*/
|
||||
@Override
|
||||
protected Composite getOriginalComposite() {
|
||||
// This is to allow the stack editor panel to have access.
|
||||
return originalComposite; // not contained within datatype manager
|
||||
protected StackFrameDataType getOriginalComposite() {
|
||||
return (StackFrameDataType) originalComposite;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean originalCompositeExists() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1247,12 +1293,6 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
return super.getOriginalDataTypeManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fixupOriginalPath(Composite composite) {
|
||||
// This is to allow the stack editor panel to have access.
|
||||
super.fixupOriginalPath(composite);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getCompositeID() {
|
||||
// This is to allow the stack editor panel to have access.
|
||||
@ -1276,10 +1316,25 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
for (int i = comps.length - 1; i >= 0; i--) {
|
||||
DataTypeComponent component = comps[i];
|
||||
DataType compDt = component.getDataType();
|
||||
if (compDt.isDeleted()) {
|
||||
clearComponent(component.getOrdinal());
|
||||
if (compDt instanceof DatabaseObject) {
|
||||
// NOTE: viewDTM only maps view-to-original IDs for DataTypeDB
|
||||
long myId = viewDTM.getID(compDt);
|
||||
if (viewDTM.findOriginalDataTypeFromMyID(myId) == null) {
|
||||
// Datatype not found
|
||||
clearComponent(component.getOrdinal());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewDTM.refreshDBTypesFromOriginal();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clearComponents(int[] rows) {
|
||||
for (int i = rows.length - 1; i >= 0; i--) {
|
||||
((StackFrameDataType) viewComposite).clearComponent(rows[i]);
|
||||
}
|
||||
notifyCompositeChanged();
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
@ -1289,24 +1344,6 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
//**************************************************************************
|
||||
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
||||
|
||||
@Override
|
||||
public DataType resolve(DataType dt) {
|
||||
if (dt instanceof StackPieceDataType) {
|
||||
return dt;
|
||||
}
|
||||
return DataTypeHelper.resolveDataType(dt, viewDTM, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method overrides the CompositeEditorModel to wrap the resolve of the data type
|
||||
* in a transaction.
|
||||
*/
|
||||
@Override
|
||||
public DataType resolveDataType(DataType dt, DataTypeManager resolveDtm,
|
||||
DataTypeConflictHandler conflictHandler) {
|
||||
return DataTypeHelper.resolveDataType(dt, resolveDtm, conflictHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeInstance validateComponentDataType(int index, String dtString)
|
||||
throws CancelledException, UsrException {
|
||||
@ -1323,7 +1360,6 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
}
|
||||
}
|
||||
|
||||
DataTypeManager originalDTM = getOriginalDataTypeManager();
|
||||
DataType newDt = DataTypeHelper.parseDataType(index, dtString, this, originalDTM,
|
||||
provider.getDtmService());
|
||||
|
||||
@ -1337,7 +1373,7 @@ public class StackEditorModel extends CompositeEditorModel {
|
||||
int newLength = newDt.getLength();
|
||||
|
||||
checkIsAllowableDataType(newDt);
|
||||
newDt = DataTypeHelper.resolveDataType(newDt, viewDTM, null);
|
||||
newDt = resolveDataType(newDt, viewDTM, null);
|
||||
int maxLength = getMaxReplaceLength(index);
|
||||
if (newLength <= 0) {
|
||||
throw new UsrException("Can't currently add this data type--not enough space.");
|
||||
|
@ -21,12 +21,8 @@ import java.util.List;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.widgets.OptionDialog;
|
||||
import ghidra.app.plugin.core.compositeeditor.CompositeEditorPanel;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.data.Composite;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.exception.UsrException;
|
||||
|
||||
/**
|
||||
@ -45,6 +41,27 @@ public class StackEditorPanel extends CompositeEditorPanel {
|
||||
super(model, provider);
|
||||
}
|
||||
|
||||
private StackEditorModel getStackModel() {
|
||||
return (StackEditorModel) model;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasUncomittedEntry() {
|
||||
// Stack editor has not yet been modified to use GFormattedTextField
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasInvalidEntry() {
|
||||
// Stack editor has not yet been modified to use GFormattedTextField
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void comitEntryChanges() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
int getFrameSize() {
|
||||
return Integer.decode(frameSizeField.getText()).intValue();
|
||||
}
|
||||
@ -149,7 +166,7 @@ public class StackEditorPanel extends CompositeEditorPanel {
|
||||
}
|
||||
else {
|
||||
try {
|
||||
((StackEditorModel) model).setLocalSize(localSize);
|
||||
getStackModel().setLocalSize(localSize);
|
||||
}
|
||||
catch (UsrException ue) {
|
||||
model.setStatus("Invalid local size \"" + valueStr + "\". " + ue.getMessage(),
|
||||
@ -193,7 +210,7 @@ public class StackEditorPanel extends CompositeEditorPanel {
|
||||
value = Integer.decode(valueStr);
|
||||
int paramSize = value.intValue();
|
||||
try {
|
||||
((StackEditorModel) model).setParameterSize(paramSize);
|
||||
getStackModel().setParameterSize(paramSize);
|
||||
}
|
||||
catch (UsrException ue) {
|
||||
model.setStatus("Invalid parameter size \"" + valueStr + "\". " + ue.getMessage(),
|
||||
@ -220,9 +237,6 @@ public class StackEditorPanel extends CompositeEditorPanel {
|
||||
returnAddrOffsetField.setEnabled(false);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.app.plugin.compositeeditor.CompositeModelDataListener#compositeInfoChanged()
|
||||
*/
|
||||
@Override
|
||||
public void compositeInfoChanged() {
|
||||
adjustStackInfo();
|
||||
@ -233,11 +247,8 @@ public class StackEditorPanel extends CompositeEditorPanel {
|
||||
: Integer.toString(value);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void adjustStackInfo() {
|
||||
StackFrameDataType editorStack = ((StackEditorModel) model).getEditorStack();
|
||||
StackFrameDataType editorStack = getStackModel().getEditorStack();
|
||||
|
||||
String frameSize = getNumberString(editorStack.getFrameSize());
|
||||
if (!frameSizeField.getText().trim().equals(frameSize)) {
|
||||
@ -265,67 +276,11 @@ public class StackEditorPanel extends CompositeEditorPanel {
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.app.plugin.compositeeditor.CompositeViewerModelListener#componentDataChanged()
|
||||
*/
|
||||
@Override
|
||||
public void componentDataChanged() {
|
||||
// Don't need to update other than table when component data changes.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dataTypeManagerRestored() {
|
||||
boolean reload = true;
|
||||
String objectType = "program";
|
||||
DataTypeManager dtm = ((StackEditorModel) model).getOriginalDataTypeManager();
|
||||
Composite originalDt = ((StackEditorModel) model).getOriginalComposite();
|
||||
if (originalDt instanceof StackFrameDataType) {
|
||||
StackFrameDataType sfdt = (StackFrameDataType) originalDt;
|
||||
Function function = sfdt.getFunction();
|
||||
if (function.isDeleted()) {
|
||||
// Cancel Editor.
|
||||
provider.dispose();
|
||||
PluginTool tool = ((StackEditorProvider) provider).getPlugin().getTool();
|
||||
tool.setStatusInfo("Stack Editor was closed for " + provider.getName());
|
||||
return;
|
||||
}
|
||||
StackFrame stack = function.getStackFrame();
|
||||
StackFrameDataType newSfdt = new StackFrameDataType(stack, dtm);
|
||||
if (!newSfdt.equals(((StackEditorModel) model).getViewComposite())) {
|
||||
originalDt = newSfdt;
|
||||
}
|
||||
}
|
||||
((StackEditorModel) model).updateAndCheckChangeState();
|
||||
if (model.hasChanges()) {
|
||||
String name = ((StackEditorModel) model).getTypeName();
|
||||
// The user has modified the structure so prompt for whether or
|
||||
// not to reload the structure.
|
||||
String question =
|
||||
"The " + objectType + " \"" + dtm.getName() + "\" has been restored.\n" + "\"" +
|
||||
model.getCompositeName() + "\" may have changed outside the editor.\n" +
|
||||
"Discard edits & reload the " + name + " Editor?";
|
||||
String title = "Reload " + name + " Editor?";
|
||||
int response = OptionDialog.showYesNoDialogWithNoAsDefaultButton(this, title, question);
|
||||
if (response != 1) {
|
||||
reload = false;
|
||||
}
|
||||
}
|
||||
if (reload) {
|
||||
cancelCellEditing();
|
||||
// TODO
|
||||
// boolean lockState = model.isLocked(); // save the lock state
|
||||
model.load(originalDt); // reload the structure
|
||||
// model.setLocked(lockState); // restore the lock state
|
||||
model.updateAndCheckChangeState();
|
||||
}
|
||||
else {
|
||||
((StackEditorModel) model).refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ghidra.app.plugin.compositeeditor.CompositeEditorPanel#dispose()
|
||||
*/
|
||||
@Override
|
||||
public void dispose() {
|
||||
removeFocusListeners(localSizeField);
|
||||
|
@ -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.
|
||||
@ -146,7 +146,7 @@ public class StackEditorProvider extends CompositeEditorProvider implements Doma
|
||||
}
|
||||
|
||||
private void refreshName() {
|
||||
StackFrameDataType origDt = (StackFrameDataType) stackModel.getOriginalComposite();
|
||||
StackFrameDataType origDt = stackModel.getOriginalComposite();
|
||||
StackFrameDataType viewDt = stackModel.getViewComposite();
|
||||
String oldName = origDt.getName();
|
||||
String newName = function.getName();
|
||||
@ -219,12 +219,13 @@ public class StackEditorProvider extends CompositeEditorProvider implements Doma
|
||||
}
|
||||
break;
|
||||
case SYMBOL_PRIMARY_STATE_CHANGED:
|
||||
sym = (Symbol) ((ProgramChangeRecord) rec).getObject();
|
||||
sym = (Symbol) ((ProgramChangeRecord) rec).getNewValue();
|
||||
symType = sym.getSymbolType();
|
||||
if (symType == SymbolType.LABEL &&
|
||||
sym.getAddress().equals(function.getEntryPoint())) {
|
||||
refreshName();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
@ -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,6 +29,8 @@ public abstract class AbstractStructureEditorTest extends AbstractEditorTest {
|
||||
|
||||
// Editor Actions
|
||||
ApplyAction applyAction;
|
||||
UndoChangeAction undoAction;
|
||||
RedoChangeAction redoAction;
|
||||
ArrayAction arrayAction;
|
||||
ClearAction clearAction;
|
||||
CreateInternalStructureAction createInternalStructureAction;
|
||||
@ -46,6 +48,7 @@ public abstract class AbstractStructureEditorTest extends AbstractEditorTest {
|
||||
InsertUndefinedAction insertUndefinedAction;
|
||||
HexNumbersAction hexNumbersAction;
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
clearActions();
|
||||
@ -100,6 +103,8 @@ public abstract class AbstractStructureEditorTest extends AbstractEditorTest {
|
||||
favorites.clear();
|
||||
cycles.clear();
|
||||
applyAction = null;
|
||||
undoAction = null;
|
||||
redoAction = null;
|
||||
arrayAction = null;
|
||||
clearAction = null;
|
||||
createInternalStructureAction = null;
|
||||
@ -130,6 +135,12 @@ public abstract class AbstractStructureEditorTest extends AbstractEditorTest {
|
||||
else if (action instanceof ApplyAction) {
|
||||
applyAction = (ApplyAction) action;
|
||||
}
|
||||
else if (action instanceof UndoChangeAction) {
|
||||
undoAction = (UndoChangeAction) action;
|
||||
}
|
||||
else if (action instanceof RedoChangeAction) {
|
||||
redoAction = (RedoChangeAction) action;
|
||||
}
|
||||
else if (action instanceof ArrayAction) {
|
||||
arrayAction = (ArrayAction) action;
|
||||
}
|
||||
|
@ -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.
|
||||
@ -23,7 +23,6 @@ import javax.swing.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import docking.widgets.OptionDialog;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Library;
|
||||
@ -126,6 +125,8 @@ public class StructureEditorAlignmentTest extends AbstractStructureEditorTest {
|
||||
addDataType(new FloatDataType());
|
||||
addDataType(arrayDt);
|
||||
|
||||
structureModel.viewDTM.clearUndo();
|
||||
|
||||
waitForSwing();
|
||||
|
||||
assertTrue(Arrays.equals(new int[] { 0 }, model.getSelectedRows()));
|
||||
@ -807,11 +808,7 @@ public class StructureEditorAlignmentTest extends AbstractStructureEditorTest {
|
||||
if (packingButton.isSelected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
pressButton(packingButton, false);
|
||||
OptionDialog confirmDialog = waitForDialogComponent(OptionDialog.class);
|
||||
pressButtonByText(confirmDialog, "Yes");
|
||||
waitForSwing();
|
||||
pressButton(packingButton, true);
|
||||
}
|
||||
|
||||
private void checkRow(int rowIndex, int offset, int length, String mnemonic, DataType dataType,
|
||||
@ -829,6 +826,7 @@ public class StructureEditorAlignmentTest extends AbstractStructureEditorTest {
|
||||
}
|
||||
|
||||
private DataTypeComponent addDataType(DataType dataType) {
|
||||
return structureModel.viewComposite.add(dataType);
|
||||
return structureModel.viewDTM.withTransaction("Add Test Component",
|
||||
() -> structureModel.viewComposite.add(dataType));
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
@ -22,6 +22,8 @@ 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 {
|
||||
@ -305,12 +307,17 @@ public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTes
|
||||
}
|
||||
|
||||
private DataTypeComponent addDataType(DataType dataType) {
|
||||
return structureModel.viewComposite.add(dataType);
|
||||
return structureModel.viewDTM.withTransaction("Add Test Component",
|
||||
() -> structureModel.viewComposite.add(dataType));
|
||||
}
|
||||
|
||||
private DataTypeComponent addFlexDataType(Structure struct, DataType dataType, String name,
|
||||
String comment) {
|
||||
ArrayDataType a = new ArrayDataType(dataType, 0, 1);
|
||||
if (struct instanceof DatabaseObject) {
|
||||
DataTypeManager dtm = struct.getDataTypeManager();
|
||||
return dtm.withTransaction("Add Flex Array", () -> struct.add(a, name, comment));
|
||||
}
|
||||
return struct.add(a, name, comment);
|
||||
}
|
||||
|
||||
@ -319,11 +326,7 @@ public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTes
|
||||
if (packingButton.isSelected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
pressButton(packingButton, false);
|
||||
OptionDialog confirmDialog = waitForDialogComponent(OptionDialog.class);
|
||||
pressButtonByText(confirmDialog, "Yes");
|
||||
waitForSwing();
|
||||
pressButton(packingButton, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -45,12 +45,7 @@ public class StructureEditorLockedActions1Test extends AbstractStructureEditorTe
|
||||
public void testArrayOnSelectionExtraUndefineds() throws Exception {
|
||||
init(simpleStructure, pgmBbCat);
|
||||
runSwing(() -> {
|
||||
try {
|
||||
model.clearComponents(new int[] { 4, 5 });
|
||||
}
|
||||
catch (UsrException e) {
|
||||
failWithException("Unexpected error", e);
|
||||
}
|
||||
model.clearComponents(new int[] { 4, 5 });
|
||||
});
|
||||
setSelection(new int[] { 3, 4, 5, 6, 7, 8, 9, 10 });// starts with DWord
|
||||
DataType dt3 = getDataType(3);
|
||||
@ -103,12 +98,7 @@ public class StructureEditorLockedActions1Test extends AbstractStructureEditorTe
|
||||
public void testCreateCycleOnPointer() throws Exception {
|
||||
init(simpleStructure, pgmBbCat);
|
||||
runSwing(() -> {
|
||||
try {
|
||||
model.clearComponents(new int[] { 2, 3 });
|
||||
}
|
||||
catch (UsrException e) {
|
||||
failWithException("Unexpected error", e);
|
||||
}
|
||||
model.clearComponents(new int[] { 2, 3 });
|
||||
});
|
||||
setSelection(new int[] { 1 });
|
||||
invoke(pointerAction);
|
||||
|
@ -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.
|
||||
@ -596,7 +596,7 @@ public class StructureEditorNotifiedTest extends AbstractStructureEditorTest {
|
||||
|
||||
int numComps = model.getNumComponents();
|
||||
int len = model.getLength();
|
||||
|
||||
|
||||
assertEquals(87, complexStructure.getComponent(16).getDataType().getLength());
|
||||
assertEquals(29, complexStructure.getComponent(19).getDataType().getLength());
|
||||
assertEquals(24, complexStructure.getComponent(20).getDataType().getLength());
|
||||
@ -675,17 +675,14 @@ public class StructureEditorNotifiedTest extends AbstractStructureEditorTest {
|
||||
|
||||
programDTM.replaceDataType(complexStructure, newComplexStructure, true);
|
||||
waitForSwing();
|
||||
DataType origCopy = newComplexStructure.clone(null);
|
||||
|
||||
// Verify the Reload Structure Editor? dialog is displayed.
|
||||
dialog = waitForWindow("Reload Structure Editor?");
|
||||
dialog = waitForWindow("Close Structure Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButtonByText(dialog, "Yes");
|
||||
dialog.dispose();
|
||||
dialog = null;
|
||||
waitForSwing();
|
||||
|
||||
assertEquals(((Structure) origCopy).getNumComponents(), model.getNumComponents());
|
||||
assertTrue(origCopy.isEquivalent(model.viewComposite));
|
||||
assertFalse(provider.isVisible());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -708,10 +705,12 @@ public class StructureEditorNotifiedTest extends AbstractStructureEditorTest {
|
||||
waitForSwing();
|
||||
|
||||
// Verify the Reload Structure Editor? dialog is displayed.
|
||||
Window dialog = waitForWindow("Reload Structure Editor?");
|
||||
Window dialog = waitForWindow("Close Structure Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButtonByText(dialog, "No");
|
||||
dialog.dispose();
|
||||
waitForSwing();
|
||||
|
||||
assertTrue(provider.isVisible());
|
||||
|
||||
assertEquals(((Structure) viewCopy).getNumComponents(), model.getNumComponents());
|
||||
assertTrue(viewCopy.isEquivalent(model.viewComposite));
|
||||
@ -728,8 +727,14 @@ public class StructureEditorNotifiedTest extends AbstractStructureEditorTest {
|
||||
|
||||
assertTrue(complexStructure.isEquivalent(model.viewComposite));
|
||||
programDTM.replaceDataType(complexStructure, newComplexStructure, true);
|
||||
|
||||
// Verify Structure Editor closes (we don't want two editors for the same type)
|
||||
Window dialog = waitForWindow("Closing Structure Editor");
|
||||
assertNotNull(dialog);
|
||||
pressButtonByText(dialog, "OK");
|
||||
waitForSwing();
|
||||
assertTrue(newComplexStructure.isEquivalent(model.viewComposite));
|
||||
|
||||
assertFalse(provider.isVisible());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
@ -36,7 +36,6 @@ public class StructureEditorProviderTest extends AbstractStructureEditorTest {
|
||||
|
||||
@Override
|
||||
protected void init(Structure dt, final Category cat, final boolean showInHex) {
|
||||
boolean commit = true;
|
||||
startTransaction("Structure Editor Test Initialization");
|
||||
try {
|
||||
DataTypeManager dataTypeManager = cat.getDataTypeManager();
|
||||
@ -49,13 +48,12 @@ public class StructureEditorProviderTest extends AbstractStructureEditorTest {
|
||||
dt.setCategoryPath(categoryPath);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
commit = false;
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
endTransaction(commit);
|
||||
endTransaction(true);
|
||||
}
|
||||
final Structure structDt = dt;
|
||||
runSwing(() -> {
|
||||
@ -67,364 +65,249 @@ public class StructureEditorProviderTest extends AbstractStructureEditorTest {
|
||||
getActions();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataTypeChanged() throws Exception {
|
||||
try {
|
||||
txId = program.startTransaction("Grow DataType");
|
||||
complexStructure.insert(22, DataType.DEFAULT);
|
||||
complexStructure.insert(22, DataType.DEFAULT);
|
||||
complexStructure.insert(22, DataType.DEFAULT);
|
||||
complexStructure.insert(22, DataType.DEFAULT);
|
||||
complexStructure.insert(22, DataType.DEFAULT);
|
||||
complexStructure.insert(22, DataType.DEFAULT);
|
||||
assertEquals(87, complexStructure.getComponent(16).getDataType().getLength());
|
||||
assertEquals(29, complexStructure.getComponent(19).getDataType().getLength());
|
||||
assertEquals(29, complexStructure.getComponent(21).getDataType().getLength());
|
||||
assertEquals(87, complexStructure.getComponent(16).getLength());
|
||||
assertEquals(29, complexStructure.getComponent(19).getLength());
|
||||
assertEquals(29, complexStructure.getComponent(21).getLength());
|
||||
assertEquals(1, complexStructure.getComponent(22).getLength());
|
||||
assertEquals(4, complexStructure.getComponent(28).getLength());
|
||||
assertEquals(331, complexStructure.getLength());
|
||||
assertEquals(29, complexStructure.getNumComponents());
|
||||
// Change the struct. simpleStructure was 29 bytes.
|
||||
simpleStructure.add(new DWordDataType());
|
||||
assertEquals(331, complexStructure.getLength());
|
||||
assertEquals(25, complexStructure.getNumComponents());
|
||||
assertEquals(99, complexStructure.getComponent(16).getDataType().getLength());
|
||||
assertEquals(33, complexStructure.getComponent(19).getDataType().getLength());
|
||||
assertEquals(33, complexStructure.getComponent(21).getDataType().getLength());
|
||||
assertEquals(87, complexStructure.getComponent(16).getLength());
|
||||
assertEquals(29, complexStructure.getComponent(19).getLength());
|
||||
assertEquals(33, complexStructure.getComponent(21).getLength());
|
||||
assertEquals(1, complexStructure.getComponent(22).getLength());
|
||||
assertEquals(4, complexStructure.getComponent(24).getLength());
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(txId, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Test Undo / Redo of program.
|
||||
@Test
|
||||
public void testModifiedDtAndProgramRestored() throws Exception {
|
||||
Window dialog;
|
||||
try {
|
||||
init(complexStructure, pgmTestCat, false);
|
||||
init(complexStructure, pgmTestCat, false);
|
||||
|
||||
// Change the structure
|
||||
runSwingLater(() -> {
|
||||
getTable().requestFocus();
|
||||
setSelection(new int[] { 4, 5 });
|
||||
deleteAction.actionPerformed(new DefaultActionContext());
|
||||
try {
|
||||
model.add(new WordDataType());
|
||||
}
|
||||
catch (UsrException e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
});
|
||||
waitForSwing();
|
||||
assertFalse(complexStructure.isEquivalent(model.viewComposite));
|
||||
// Change the structure
|
||||
runSwingLater(() -> {
|
||||
getTable().requestFocus();
|
||||
setSelection(new int[] { 4, 5 });
|
||||
deleteAction.actionPerformed(new DefaultActionContext());
|
||||
try {
|
||||
model.add(new WordDataType());
|
||||
}
|
||||
catch (UsrException e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
});
|
||||
waitForSwing();
|
||||
assertFalse(complexStructure.isEquivalent(model.viewComposite));
|
||||
|
||||
// Apply the changes
|
||||
invoke(applyAction);
|
||||
assertTrue(complexStructure.isEquivalent(model.viewComposite));
|
||||
// Apply the changes
|
||||
invoke(applyAction);
|
||||
assertTrue(complexStructure.isEquivalent(model.viewComposite));
|
||||
|
||||
// Change the structure again.
|
||||
runSwingLater(() -> {
|
||||
getTable().requestFocus();
|
||||
setSelection(new int[] { 1 });
|
||||
clearAction.actionPerformed(new DefaultActionContext());
|
||||
deleteAction.actionPerformed(new DefaultActionContext());// Must be undefined before it can delete.
|
||||
});
|
||||
waitForSwing();
|
||||
assertFalse(complexStructure.isEquivalent(model.viewComposite));
|
||||
// Change the structure again.
|
||||
runSwingLater(() -> {
|
||||
getTable().requestFocus();
|
||||
setSelection(new int[] { 1 });
|
||||
clearAction.actionPerformed(new DefaultActionContext());
|
||||
deleteAction.actionPerformed(new DefaultActionContext());// Must be undefined before it can delete.
|
||||
});
|
||||
waitForSwing();
|
||||
assertFalse(complexStructure.isEquivalent(model.viewComposite));
|
||||
|
||||
// Undo the apply
|
||||
undo(program, false);
|
||||
// Verify the Reload Structure Editor? dialog is displayed.
|
||||
dialog = waitForWindow("Reload Structure Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "No");
|
||||
dialog.dispose();
|
||||
dialog = null;
|
||||
assertFalse(complexStructure.isEquivalent(model.viewComposite));
|
||||
// Undo the apply
|
||||
undo(program, false);
|
||||
// Verify the Reload Structure Editor? dialog is displayed.
|
||||
Window dialog = waitForWindow("Reload Structure Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "No");
|
||||
waitForSwing();
|
||||
|
||||
// Redo the apply
|
||||
redo(program, false);
|
||||
// Verify the Reload Structure Editor? dialog is displayed.
|
||||
dialog = waitForWindow("Reload Structure Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "No");
|
||||
dialog.dispose();
|
||||
dialog = null;
|
||||
assertFalse(complexStructure.isEquivalent(model.viewComposite));
|
||||
}
|
||||
finally {
|
||||
dialog = null;
|
||||
}
|
||||
assertFalse(complexStructure.isEquivalent(model.viewComposite));
|
||||
|
||||
// Redo the apply
|
||||
redo(program, false);
|
||||
|
||||
// Verify the Reload Structure Editor? dialog is displayed.
|
||||
dialog = waitForWindow("Reload Structure Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "No");
|
||||
waitForSwing();
|
||||
|
||||
assertFalse(complexStructure.isEquivalent(model.viewComposite));
|
||||
}
|
||||
|
||||
// Test add a structure, start to edit it, and then undo the program so it goes away.
|
||||
// This should close the edit session.
|
||||
@Test
|
||||
public void testProgramRestoreRemovesEditedDt() throws Exception {
|
||||
Window dialog;
|
||||
|
||||
Structure s1 = new StructureDataType("s1", 0);
|
||||
s1.add(new ByteDataType());
|
||||
Structure s2 = new StructureDataType("s2", 0);
|
||||
s2.add(new WordDataType());
|
||||
s1.add(s2);
|
||||
|
||||
// Add the s1 data type so that we can undo its add.
|
||||
Structure s1Struct = null;
|
||||
startTransaction("Structure Editor Test Initialization");
|
||||
try {
|
||||
Structure s1 = new StructureDataType("s1", 0);
|
||||
s1.add(new ByteDataType());
|
||||
Structure s2 = new StructureDataType("s2", 0);
|
||||
s2.add(new WordDataType());
|
||||
s1.add(s2);
|
||||
|
||||
// Add the s1 data type so that we can undo its add.
|
||||
boolean commit = true;
|
||||
Structure s1Struct = null;
|
||||
startTransaction("Structure Editor Test Initialization");
|
||||
try {
|
||||
s1Struct =
|
||||
(Structure) pgmTestCat.addDataType(s1, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
}
|
||||
finally {
|
||||
endTransaction(commit);
|
||||
}
|
||||
assertNotNull(s1Struct);
|
||||
final Structure myS1Structure = s1Struct;
|
||||
|
||||
init(myS1Structure, pgmTestCat, false);
|
||||
|
||||
// Change the structure.
|
||||
runSwingLater(() -> {
|
||||
getTable().requestFocus();
|
||||
// Select blank line after components.
|
||||
setSelection(new int[] { myS1Structure.getNumComponents() });
|
||||
try {
|
||||
model.add(new WordDataType());
|
||||
}
|
||||
catch (UsrException e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
});
|
||||
waitForSwing();
|
||||
assertFalse(complexStructure.isEquivalent(model.viewComposite));
|
||||
|
||||
// Verify the editor provider is displayed.
|
||||
String mySubTitle = getProviderSubTitle(myS1Structure);
|
||||
assertTrue("Couldn't find editor = " + mySubTitle,
|
||||
isProviderShown(tool.getToolFrame(), "Structure Editor", mySubTitle));
|
||||
|
||||
// Undo the apply
|
||||
undo(program, false);
|
||||
waitForSwing();
|
||||
|
||||
// Verify the "Reload Structure Editor?" dialog is NOT displayed.
|
||||
dialog = getWindow("Reload Structure Editor?");
|
||||
assertNull(dialog);
|
||||
|
||||
// Verify the editor provider is gone.
|
||||
assertFalse(isProviderShown(tool.getToolFrame(), "Structure Editor", mySubTitle));
|
||||
s1Struct =
|
||||
(Structure) pgmTestCat.addDataType(s1, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
}
|
||||
finally {
|
||||
dialog = null;
|
||||
endTransaction(true);
|
||||
}
|
||||
assertNotNull(s1Struct);
|
||||
final Structure myS1Structure = s1Struct;
|
||||
|
||||
init(myS1Structure, pgmTestCat, false);
|
||||
|
||||
// Change the structure.
|
||||
runSwingLater(() -> {
|
||||
getTable().requestFocus();
|
||||
// Select blank line after components.
|
||||
setSelection(new int[] { myS1Structure.getNumComponents() });
|
||||
try {
|
||||
model.add(new WordDataType());
|
||||
}
|
||||
catch (UsrException e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
});
|
||||
waitForSwing();
|
||||
assertFalse(complexStructure.isEquivalent(model.viewComposite));
|
||||
|
||||
// Verify the editor provider is displayed.
|
||||
String mySubTitle = getProviderSubTitle(myS1Structure);
|
||||
assertTrue("Couldn't find editor = " + mySubTitle,
|
||||
isProviderShown(tool.getToolFrame(), "Structure Editor", mySubTitle));
|
||||
|
||||
// Undo the apply
|
||||
undo(program, false);
|
||||
|
||||
Window dialog = waitForWindow("Close Structure Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "Yes");
|
||||
waitForSwing();
|
||||
|
||||
// Verify the editor provider is gone.
|
||||
assertFalse(isProviderShown(tool.getToolFrame(), "Structure Editor", mySubTitle));
|
||||
}
|
||||
|
||||
// Test add a structure containing inner struct, start to edit inner struct, and then undo the
|
||||
// program so it goes away. This should close the edit session.
|
||||
// program so it goes away.
|
||||
@Test
|
||||
public void testProgramRestoreRemovesEditedDtComp() throws Exception {
|
||||
Window dialog;
|
||||
Structure s1 = new StructureDataType("s1", 0);
|
||||
s1.setCategoryPath(pgmTestCat.getCategoryPath());
|
||||
s1.add(new ByteDataType());
|
||||
Structure s2 = new StructureDataType("s2", 0);
|
||||
s2.setCategoryPath(pgmTestCat.getCategoryPath());
|
||||
s2.add(new WordDataType());
|
||||
s1.add(s2);
|
||||
|
||||
// Add the s1 data type so that we can undo its add.
|
||||
Structure s1Struct = null;
|
||||
startTransaction("Resolve s1");
|
||||
try {
|
||||
Structure s1 = new StructureDataType("s1", 0);
|
||||
s1.setCategoryPath(pgmTestCat.getCategoryPath());
|
||||
s1.add(new ByteDataType());
|
||||
Structure s2 = new StructureDataType("s2", 0);
|
||||
s2.setCategoryPath(pgmTestCat.getCategoryPath());
|
||||
s2.add(new WordDataType());
|
||||
s1.add(s2);
|
||||
|
||||
// Add the s1 data type so that we can undo its add.
|
||||
boolean commit = true;
|
||||
Structure s1Struct = null;
|
||||
startTransaction("Structure Editor Test Initialization");
|
||||
try {
|
||||
s1Struct =
|
||||
(Structure) pgmTestCat.addDataType(s1, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
}
|
||||
finally {
|
||||
endTransaction(commit);
|
||||
}
|
||||
assertNotNull(s1Struct);
|
||||
final Structure myS2Structure = (Structure) s1Struct.getComponent(1).getDataType();
|
||||
assertNotNull(myS2Structure);
|
||||
assertTrue(s2.isEquivalent(myS2Structure));
|
||||
|
||||
init(myS2Structure, pgmTestCat, false);
|
||||
|
||||
// Change the structure.
|
||||
runSwing(() -> {
|
||||
getTable().requestFocus();
|
||||
// Select blank line after components.
|
||||
setSelection(new int[] { myS2Structure.getNumComponents() });
|
||||
try {
|
||||
model.add(new WordDataType());
|
||||
}
|
||||
catch (UsrException e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}, false);
|
||||
waitForSwing();
|
||||
assertFalse(complexStructure.isEquivalent(model.viewComposite));
|
||||
|
||||
// Verify the editor provider is displayed.
|
||||
String mySubTitle = getProviderSubTitle(myS2Structure);
|
||||
assertTrue("Couldn't find editor = " + mySubTitle,
|
||||
isProviderShown(tool.getToolFrame(), "Structure Editor", mySubTitle));
|
||||
|
||||
// Undo the apply
|
||||
undo(program, false);
|
||||
waitForSwing();
|
||||
|
||||
// Verify the "Reload Structure Editor?" dialog is NOT displayed.
|
||||
dialog = getWindow("Reload Structure Editor?");
|
||||
assertNull(dialog);
|
||||
|
||||
// Verify the editor provider is gone.
|
||||
assertFalse(isProviderShown(tool.getToolFrame(), "Structure Editor", mySubTitle));
|
||||
s1Struct =
|
||||
(Structure) pgmTestCat.addDataType(s1, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
}
|
||||
finally {
|
||||
dialog = null;
|
||||
endTransaction(true);
|
||||
}
|
||||
assertNotNull(s1Struct);
|
||||
final Structure myS2Structure = (Structure) s1Struct.getComponent(1).getDataType();
|
||||
assertNotNull(myS2Structure);
|
||||
assertTrue(s2.isEquivalent(myS2Structure));
|
||||
|
||||
Structure editStruct = s1Struct;
|
||||
init(editStruct, pgmTestCat, false);
|
||||
|
||||
// Change the structure.
|
||||
|
||||
runSwing(() -> {
|
||||
getTable().requestFocus();
|
||||
// Select blank line after components.
|
||||
setSelection(new int[] { editStruct.getNumComponents() });
|
||||
try {
|
||||
model.add(new WordDataType());
|
||||
}
|
||||
catch (UsrException e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}, false);
|
||||
waitForSwing();
|
||||
assertFalse(s1.isEquivalent(model.viewComposite));
|
||||
|
||||
// Verify the editor provider is displayed.
|
||||
String mySubTitle = getProviderSubTitle(editStruct);
|
||||
assertTrue("Couldn't find editor = " + mySubTitle,
|
||||
isProviderShown(tool.getToolFrame(), "Structure Editor", mySubTitle));
|
||||
|
||||
// Undo the apply
|
||||
undo(program, false);
|
||||
waitForSwing();
|
||||
|
||||
Window dialog = waitForWindow("Close Structure Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "Yes");
|
||||
waitForSwing();
|
||||
|
||||
// Verify the editor provider is gone.
|
||||
assertFalse(isProviderShown(tool.getToolFrame(), "Structure Editor", mySubTitle));
|
||||
}
|
||||
|
||||
// Test add a structure, start to edit a structure that contains it, and then undo the program
|
||||
// so it goes away. The editor stays since the structure existed previously, but editor reloads.
|
||||
// so it goes away. The editor stays since the structure existed previously and has been modified.
|
||||
@Test
|
||||
public void testProgramRestoreRemovesEditedComponentDtYes() throws Exception {
|
||||
Window dialog;
|
||||
public void testProgramRestoreRemovesEditedComponentDt() throws Exception {
|
||||
|
||||
Structure myStruct = new StructureDataType("myStruct", 0);
|
||||
myStruct.add(new WordDataType());
|
||||
|
||||
init(emptyStructure, pgmTestCat, false);
|
||||
|
||||
// Add the data type so that we can undo its add.
|
||||
Structure pgmMyStruct = null;
|
||||
startTransaction("Structure Editor Test Initialization");
|
||||
try {
|
||||
Structure myStruct = new StructureDataType("myStruct", 0);
|
||||
myStruct.add(new WordDataType());
|
||||
|
||||
init(emptyStructure, pgmTestCat, false);
|
||||
|
||||
// Add the data type so that we can undo its add.
|
||||
boolean commit = true;
|
||||
Structure pgmMyStruct = null;
|
||||
startTransaction("Structure Editor Test Initialization");
|
||||
try {
|
||||
pgmMyStruct = (Structure) pgmTestCat.addDataType(myStruct,
|
||||
DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
}
|
||||
finally {
|
||||
endTransaction(commit);
|
||||
}
|
||||
assertNotNull(pgmMyStruct);
|
||||
final Structure myStructure = pgmMyStruct;
|
||||
|
||||
// Change the structure.
|
||||
runSwingLater(() -> {
|
||||
getTable().requestFocus();
|
||||
// Select blank line after components.
|
||||
setSelection(new int[] { emptyStructure.getNumComponents() });
|
||||
try {
|
||||
model.add(myStructure);
|
||||
}
|
||||
catch (UsrException e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
});
|
||||
waitForSwing();
|
||||
assertFalse(emptyStructure.isEquivalent(model.viewComposite));
|
||||
|
||||
// Verify the editor provider is displayed.
|
||||
String mySubTitle = getProviderSubTitle(emptyStructure);
|
||||
assertTrue("Couldn't find editor = " + mySubTitle,
|
||||
isProviderShown(tool.getToolFrame(), "Structure Editor", "emptyStructure (Test)"));
|
||||
|
||||
// Undo the apply
|
||||
undo(program, false);
|
||||
|
||||
// Verify the Reload Structure Editor? dialog is displayed.
|
||||
dialog = waitForWindow("Reload Structure Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "Yes");
|
||||
dialog.dispose();
|
||||
dialog = null;
|
||||
assertTrue(emptyStructure.isEquivalent(model.viewComposite));
|
||||
|
||||
// Verify the editor provider is reloaded.
|
||||
assertTrue(
|
||||
isProviderShown(tool.getToolFrame(), "Structure Editor", "emptyStructure (Test)"));
|
||||
pgmMyStruct = (Structure) pgmTestCat.addDataType(myStruct,
|
||||
DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
}
|
||||
finally {
|
||||
dialog = null;
|
||||
endTransaction(true);
|
||||
}
|
||||
}
|
||||
assertNotNull(pgmMyStruct);
|
||||
final Structure myStructure = pgmMyStruct;
|
||||
|
||||
// Test add a structure, start to edit a structure that contains it, and then undo the program
|
||||
// so it goes away. The editor stays since the structure existed previously, but doesn't reload.
|
||||
@Test
|
||||
public void testProgramRestoreRemovesEditedComponentDtNo() throws Exception {
|
||||
Window dialog;
|
||||
try {
|
||||
Structure myStruct = new StructureDataType("myStruct", 0);
|
||||
myStruct.add(new WordDataType());
|
||||
|
||||
init(emptyStructure, pgmTestCat, false);
|
||||
|
||||
// Add the data type so that we can undo its add.
|
||||
boolean commit = true;
|
||||
Structure pgmMyStruct = null;
|
||||
startTransaction("Structure Editor Test Initialization");
|
||||
// Change the structure.
|
||||
runSwingLater(() -> {
|
||||
getTable().requestFocus();
|
||||
// Select blank line after components.
|
||||
setSelection(new int[] { emptyStructure.getNumComponents() });
|
||||
try {
|
||||
pgmMyStruct = (Structure) pgmTestCat.addDataType(myStruct,
|
||||
DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
model.add(myStructure);
|
||||
}
|
||||
finally {
|
||||
endTransaction(commit);
|
||||
catch (UsrException e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
assertNotNull(pgmMyStruct);
|
||||
final Structure myStructure = pgmMyStruct;
|
||||
});
|
||||
waitForSwing();
|
||||
assertFalse(emptyStructure.isEquivalent(model.viewComposite));
|
||||
|
||||
// Change the structure.
|
||||
runSwingLater(() -> {
|
||||
getTable().requestFocus();
|
||||
// Select blank line after components.
|
||||
setSelection(new int[] { emptyStructure.getNumComponents() });
|
||||
try {
|
||||
model.add(myStructure);
|
||||
}
|
||||
catch (UsrException e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
});
|
||||
waitForSwing();
|
||||
assertFalse(emptyStructure.isEquivalent(model.viewComposite));
|
||||
// Verify the editor provider is displayed.
|
||||
String mySubTitle = getProviderSubTitle(emptyStructure);
|
||||
assertTrue("Couldn't find editor = " + mySubTitle,
|
||||
isProviderShown(tool.getToolFrame(), "Structure Editor", "emptyStructure (Test)"));
|
||||
|
||||
// Verify the editor provider is displayed.
|
||||
String mySubTitle = getProviderSubTitle(emptyStructure);
|
||||
assertTrue("Couldn't find editor = " + mySubTitle,
|
||||
isProviderShown(tool.getToolFrame(), "Structure Editor", "emptyStructure (Test)"));
|
||||
DataType dtCopy = model.viewComposite.copy(model.viewDTM);
|
||||
|
||||
// Undo the apply
|
||||
undo(program, false);
|
||||
// Verify the Reload Structure Editor? dialog is displayed.
|
||||
dialog = waitForWindow("Reload Structure Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "No");
|
||||
dialog.dispose();
|
||||
dialog = null;
|
||||
assertFalse(emptyStructure.isEquivalent(model.viewComposite));
|
||||
// Undo the apply
|
||||
undo(program, false);
|
||||
waitForSwing();
|
||||
|
||||
// Verify the editor provider is still on screen.
|
||||
assertTrue(
|
||||
isProviderShown(tool.getToolFrame(), "Structure Editor", "emptyStructure (Test)"));
|
||||
}
|
||||
finally {
|
||||
dialog = null;
|
||||
}
|
||||
assertTrue(pgmMyStruct.isDeleted());
|
||||
|
||||
// Verify the a reload/close dialog is not displayed.
|
||||
Window dialog = getWindow("Reload Structure Editor?");
|
||||
assertNull(dialog);
|
||||
dialog = getWindow("Close Structure Editor?");
|
||||
assertNull(dialog);
|
||||
|
||||
assertTrue(
|
||||
isProviderShown(tool.getToolFrame(), "Structure Editor", "emptyStructure (Test)"));
|
||||
|
||||
// Verify the editor provider remains visible with myStructure use cleared.
|
||||
assertFalse(emptyStructure.isEquivalent(model.viewComposite));
|
||||
assertFalse(dtCopy.isEquivalent(model.viewComposite));
|
||||
assertEquals(dtCopy.getLength(), model.viewComposite.getLength());
|
||||
assertEquals(2, model.viewComposite.getNumComponents());
|
||||
assertEquals(0, model.viewComposite.getNumDefinedComponents());
|
||||
}
|
||||
|
||||
// Test Undo / Redo of program.
|
||||
@ -446,14 +329,29 @@ public class StructureEditorProviderTest extends AbstractStructureEditorTest {
|
||||
});
|
||||
waitForSwing();
|
||||
assertFalse(complexStructure.isEquivalent(model.viewComposite));
|
||||
|
||||
// Apply the changes
|
||||
invoke(applyAction);
|
||||
assertTrue(complexStructure.isEquivalent(model.viewComposite));
|
||||
|
||||
// Undo the apply
|
||||
undo(program);
|
||||
|
||||
Window dialog = waitForWindow("Reload Structure Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "Yes");
|
||||
waitForSwing();
|
||||
|
||||
assertTrue(complexStructure.isEquivalent(model.viewComposite));
|
||||
|
||||
// Redo the apply
|
||||
redo(program);
|
||||
|
||||
dialog = waitForWindow("Reload Structure Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "Yes");
|
||||
waitForSwing();
|
||||
|
||||
assertTrue(complexStructure.isEquivalent(model.viewComposite));
|
||||
}
|
||||
|
||||
@ -569,8 +467,7 @@ public class StructureEditorProviderTest extends AbstractStructureEditorTest {
|
||||
dialog = waitForWindow("Save Structure Editor Changes?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "Cancel");
|
||||
dialog.dispose();
|
||||
dialog = null;
|
||||
|
||||
assertTrue(tool.isVisible(provider));
|
||||
assertFalse(complexStructure.isEquivalent(model.viewComposite));
|
||||
assertTrue(newDt.isEquivalent(model.viewComposite));
|
||||
@ -706,8 +603,6 @@ public class StructureEditorProviderTest extends AbstractStructureEditorTest {
|
||||
assertTrue(tool.isVisible(provider));
|
||||
assertTrue(complexStructure.isEquivalent(model.viewComposite));
|
||||
|
||||
Composite dt = model.viewComposite;
|
||||
|
||||
// set selected row
|
||||
int row = 2;
|
||||
setSelection(new int[] { row });
|
||||
@ -716,7 +611,7 @@ public class StructureEditorProviderTest extends AbstractStructureEditorTest {
|
||||
int editRow = 4; // offset 8; 'simpleUnion'
|
||||
String newFieldName = "newFieldName";
|
||||
tx(program, () -> {
|
||||
DataTypeComponent dtc = dt.getComponent(editRow);
|
||||
DataTypeComponent dtc = complexStructure.getComponent(editRow);
|
||||
dtc.setFieldName(newFieldName);
|
||||
});
|
||||
|
||||
@ -728,7 +623,8 @@ public class StructureEditorProviderTest extends AbstractStructureEditorTest {
|
||||
assertEquals(1, rows.length);
|
||||
assertEquals(row, rows[0]);
|
||||
|
||||
closeProviderIgnoringChanges();
|
||||
// External change should not register as unsved change to model
|
||||
assertFalse(model.hasChanges());
|
||||
}
|
||||
|
||||
private void closeProviderIgnoringChanges() {
|
||||
|
@ -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.
|
||||
@ -94,31 +94,84 @@ public class StructureEditorUnlockedActions5Test extends AbstractStructureEditor
|
||||
// model.getStatus());
|
||||
}
|
||||
|
||||
// Ignoring test for now. Don't know how to make the name invalid
|
||||
@Test
|
||||
public void testApplyWithInvalidName() throws Exception {
|
||||
init(complexStructure, pgmTestCat);
|
||||
|
||||
CompEditorPanel panel = (CompEditorPanel) getPanel();
|
||||
JTextField nameField = panel.nameTextField;
|
||||
assertTrue(model.isValidName());
|
||||
triggerActionKey(nameField, 0, KeyEvent.VK_END);
|
||||
triggerText(nameField, "#$/");
|
||||
DataType viewCopy = model.viewComposite.clone(null);
|
||||
|
||||
assertTrue(!model.isValidName());
|
||||
assertEquals("complexStructure#$/", nameField.getText());
|
||||
assertEquals("complexStructure#$/", model.getCompositeName());
|
||||
assertEquals("complexStructure", complexStructure.getName());
|
||||
assertTrue(complexStructure.isEquivalent(model.viewComposite));
|
||||
assertTrue(viewCopy.isEquivalent(model.viewComposite));
|
||||
assertEquals(model.getStatus(), "complexStructure#$/ is not a valid name.");
|
||||
invoke(applyAction);
|
||||
assertEquals(model.getStatus(), "Name is not valid.");
|
||||
assertTrue(complexStructure.isEquivalent(model.viewComposite));
|
||||
assertTrue(viewCopy.isEquivalent(model.viewComposite));
|
||||
assertTrue(model.getStatus().length() > 0);
|
||||
assertEquals("complexStructure#$/", model.getCompositeName());
|
||||
assertEquals("complexStructure", complexStructure.getName());
|
||||
CompEditorPanel panel = (CompEditorPanel) getPanel();
|
||||
assertFalse(panel.hasInvalidEntry());
|
||||
assertFalse(panel.hasUncomittedEntry());
|
||||
|
||||
JTextField nameField = panel.nameTextField;
|
||||
nameField.setText(null);
|
||||
triggerActionKey(nameField, 0, KeyEvent.VK_END);
|
||||
triggerText(nameField, " ");
|
||||
|
||||
assertTrue(panel.hasInvalidEntry());
|
||||
assertFalse(applyAction.isEnabled());
|
||||
assertFalse(applyAction.isEnabled());
|
||||
|
||||
assertEquals("complexStructure", model.getCompositeName()); // no change yet
|
||||
|
||||
triggerActionKey(nameField, 0, KeyEvent.VK_DELETE);
|
||||
triggerText(nameField, "xyz");
|
||||
|
||||
assertFalse(panel.hasInvalidEntry());
|
||||
assertTrue(panel.hasUncomittedEntry());
|
||||
assertFalse(applyAction.isEnabled());
|
||||
assertFalse(applyAction.isEnabled());
|
||||
|
||||
assertEquals("complexStructure", model.getCompositeName()); // no change yet
|
||||
|
||||
triggerActionKey(nameField, 0, KeyEvent.VK_ENTER);
|
||||
|
||||
assertFalse(panel.hasInvalidEntry());
|
||||
assertFalse(panel.hasUncomittedEntry());
|
||||
assertTrue(applyAction.isEnabled());
|
||||
assertTrue(applyAction.isEnabled());
|
||||
|
||||
assertTrue(model.isValidName());
|
||||
|
||||
assertEquals("xyz", model.getCompositeName()); // no change yet
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUncomittedNameRevert() throws Exception {
|
||||
init(complexStructure, pgmTestCat);
|
||||
|
||||
assertTrue(model.isValidName());
|
||||
|
||||
CompEditorPanel panel = (CompEditorPanel) getPanel();
|
||||
assertFalse(panel.hasInvalidEntry());
|
||||
assertFalse(panel.hasUncomittedEntry());
|
||||
|
||||
JTextField nameField = panel.nameTextField;
|
||||
nameField.setText(null);
|
||||
triggerActionKey(nameField, 0, KeyEvent.VK_END);
|
||||
triggerText(nameField, "xyz");
|
||||
assertEquals("xyz", nameField.getText());
|
||||
|
||||
assertFalse(panel.hasInvalidEntry());
|
||||
assertTrue(panel.hasUncomittedEntry());
|
||||
assertFalse(applyAction.isEnabled());
|
||||
assertFalse(applyAction.isEnabled());
|
||||
|
||||
assertEquals("complexStructure", model.getCompositeName()); // no change yet
|
||||
|
||||
triggerActionKey(nameField, 0, KeyEvent.VK_ESCAPE);
|
||||
|
||||
assertEquals("complexStructure", nameField.getText());
|
||||
|
||||
assertFalse(panel.hasInvalidEntry());
|
||||
assertFalse(panel.hasUncomittedEntry());
|
||||
assertFalse(applyAction.isEnabled());
|
||||
assertFalse(applyAction.isEnabled());
|
||||
|
||||
assertTrue(model.isValidName());
|
||||
|
||||
assertEquals("complexStructure", model.getCompositeName()); // no change yet
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -606,24 +659,53 @@ public class StructureEditorUnlockedActions5Test extends AbstractStructureEditor
|
||||
|
||||
CompEditorPanel panel = (CompEditorPanel) getPanel();
|
||||
JTextField nameField = panel.nameTextField;
|
||||
runSwing(() -> nameField.setText("myStruct"));
|
||||
|
||||
setText(nameField, "myStruct");
|
||||
triggerEnter(nameField);
|
||||
|
||||
assertEquals("myStruct", nameField.getText());
|
||||
assertEquals("myStruct", model.getCompositeName());
|
||||
|
||||
invoke(applyAction);
|
||||
runSwing(() -> nameField.setText("myStruct2"));
|
||||
invoke(applyAction);
|
||||
undo(program, false);
|
||||
program.flushEvents();
|
||||
waitForSwing();
|
||||
runSwing(() -> provider.dataTypeManagerRestored(), true);
|
||||
|
||||
waitForSwing();
|
||||
|
||||
assertEquals("myStruct", nameField.getText());
|
||||
assertEquals("myStruct", model.getCompositeName());
|
||||
redo(program, false);
|
||||
program.flushEvents();
|
||||
waitForSwing();
|
||||
runSwing(() -> provider.dataTypeManagerRestored(), true);
|
||||
waitForSwing();
|
||||
|
||||
setText(nameField, "myStruct2");
|
||||
triggerEnter(nameField);
|
||||
|
||||
assertEquals("myStruct2", nameField.getText());
|
||||
assertEquals("myStruct2", model.getCompositeName());
|
||||
|
||||
invoke(applyAction);
|
||||
|
||||
waitForSwing();
|
||||
|
||||
assertEquals("myStruct2", nameField.getText());
|
||||
assertEquals("myStruct2", model.getCompositeName());
|
||||
|
||||
undo(program, true);
|
||||
|
||||
Window dialog = waitForWindow("Reload Structure Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "Yes");
|
||||
waitForSwing();
|
||||
|
||||
assertEquals("myStruct", nameField.getText());
|
||||
assertEquals("myStruct", model.getCompositeName());
|
||||
|
||||
redo(program, true);
|
||||
|
||||
dialog = waitForWindow("Reload Structure Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "No");
|
||||
waitForSwing();
|
||||
|
||||
assertEquals("myStruct", nameField.getText());
|
||||
assertEquals("myStruct", model.getCompositeName());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -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.
|
||||
@ -253,8 +253,9 @@ public class StructureEditorUnlockedEnablementTest extends AbstractStructureEdit
|
||||
throws ArrayIndexOutOfBoundsException, InvalidDataTypeException {
|
||||
init(complexStructure, pgmBbCat);
|
||||
|
||||
((Structure) structureModel.viewComposite).insertBitField(2, 1, 4, CharDataType.dataType, 2,
|
||||
"bf1", null);
|
||||
structureModel.viewDTM.withTransaction("Add Bitfield",
|
||||
() -> ((Structure) structureModel.viewComposite).insertBitField(2, 1, 4,
|
||||
CharDataType.dataType, 2, "bf1", null));
|
||||
|
||||
setSelection(new int[] { 2 });
|
||||
assertEquals("char:2", getDataType(2).getDisplayName());
|
||||
@ -294,8 +295,9 @@ public class StructureEditorUnlockedEnablementTest extends AbstractStructureEdit
|
||||
throws ArrayIndexOutOfBoundsException, InvalidDataTypeException {
|
||||
init(complexStructure, pgmBbCat);
|
||||
|
||||
((Structure) structureModel.viewComposite).insertBitField(2, 1, 4, CharDataType.dataType, 2,
|
||||
"bf1", null);
|
||||
structureModel.viewDTM.withTransaction("Add Bitfield",
|
||||
() -> ((Structure) structureModel.viewComposite).insertBitField(2, 1, 4,
|
||||
CharDataType.dataType, 2, "bf1", null));
|
||||
|
||||
setSelection(new int[] { 2 });
|
||||
assertEquals("char:2", getDataType(2).getDisplayName());
|
||||
|
@ -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.
|
||||
@ -27,7 +27,7 @@ import ghidra.program.model.data.*;
|
||||
public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
|
||||
@Test
|
||||
public void testUnalignedUnion() {
|
||||
public void testUnalignedUnion() {
|
||||
init(emptyUnion, pgmRootCat, false);
|
||||
|
||||
assertTrue(unionModel.hasChanges());// empty union that hasn't been saved yet.
|
||||
@ -49,17 +49,14 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
|
||||
// Check enablement for empty table with modified state.
|
||||
CompositeEditorTableAction[] pActions = provider.getActions();
|
||||
for (int i = 0; i < pActions.length; i++) {
|
||||
if ((pActions[i] instanceof FavoritesAction) ||
|
||||
(pActions[i] instanceof CycleGroupAction) ||
|
||||
(pActions[i] instanceof EditFieldAction) ||
|
||||
(pActions[i] instanceof PointerAction) ||
|
||||
(pActions[i] instanceof HexNumbersAction) ||
|
||||
(pActions[i] instanceof ApplyAction)) {
|
||||
checkEnablement(pActions[i], true);
|
||||
for (CompositeEditorTableAction pAction : pActions) {
|
||||
if ((pAction instanceof FavoritesAction) || (pAction instanceof CycleGroupAction) ||
|
||||
(pAction instanceof EditFieldAction) || (pAction instanceof PointerAction) ||
|
||||
(pAction instanceof HexNumbersAction) || (pAction instanceof ApplyAction)) {
|
||||
checkEnablement(pAction, true);
|
||||
}
|
||||
else {
|
||||
checkEnablement(pActions[i], false);
|
||||
checkEnablement(pAction, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,7 +75,7 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultAlignedUnion() throws Exception {
|
||||
public void testDefaultAlignedUnion() throws Exception {
|
||||
init(emptyUnion, pgmRootCat, false);
|
||||
|
||||
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
||||
@ -101,34 +98,36 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnablementDefaultAlignedUnion() throws Exception {
|
||||
public void testEnablementDefaultAlignedUnion() throws Exception {
|
||||
emptyUnion.setPackingEnabled(true);
|
||||
init(emptyUnion, pgmRootCat, false);
|
||||
|
||||
CompositeEditorTableAction undoAction =
|
||||
provider.actionMgr.getNamedAction("Undo Editor Change");
|
||||
assertNotNull(undoAction);
|
||||
checkEnablement(undoAction, false);
|
||||
|
||||
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
||||
addDataType(new ByteDataType());
|
||||
addDataType(new FloatDataType());
|
||||
addDataType(arrayDt);
|
||||
|
||||
// Undo should be enabled
|
||||
|
||||
// Check enablement.
|
||||
CompositeEditorTableAction[] pActions = provider.getActions();
|
||||
for (int i = 0; i < pActions.length; i++) {
|
||||
if ((pActions[i] instanceof FavoritesAction) ||
|
||||
(pActions[i] instanceof CycleGroupAction) ||
|
||||
(pActions[i] instanceof EditFieldAction) ||
|
||||
(pActions[i] instanceof PointerAction) ||
|
||||
(pActions[i] instanceof HexNumbersAction) ||
|
||||
(pActions[i] instanceof MoveDownAction) ||
|
||||
(pActions[i] instanceof DuplicateAction) ||
|
||||
(pActions[i] instanceof DuplicateMultipleAction) ||
|
||||
(pActions[i] instanceof DeleteAction) ||
|
||||
(pActions[i] instanceof ArrayAction) ||
|
||||
(pActions[i] instanceof ShowComponentPathAction) ||
|
||||
(pActions[i] instanceof ApplyAction)) {
|
||||
checkEnablement(pActions[i], true);
|
||||
for (CompositeEditorTableAction pAction : pActions) {
|
||||
if ((pAction instanceof FavoritesAction) || (pAction instanceof CycleGroupAction) ||
|
||||
(pAction instanceof EditFieldAction) || (pAction instanceof PointerAction) ||
|
||||
(pAction instanceof HexNumbersAction) || (pAction instanceof MoveDownAction) ||
|
||||
(pAction instanceof DuplicateAction) ||
|
||||
(pAction instanceof DuplicateMultipleAction) || (pAction instanceof DeleteAction) ||
|
||||
(pAction instanceof ArrayAction) || (pAction instanceof ShowComponentPathAction) ||
|
||||
(pAction instanceof ApplyAction) || (pAction instanceof UndoChangeAction)) {
|
||||
checkEnablement(pAction, true);
|
||||
}
|
||||
else {
|
||||
checkEnablement(pActions[i], false);
|
||||
checkEnablement(pAction, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,7 +142,7 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMachineAlignedUnion() throws Exception {
|
||||
public void testMachineAlignedUnion() throws Exception {
|
||||
init(emptyUnion, pgmRootCat, false);
|
||||
|
||||
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
||||
@ -168,7 +167,7 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByValueAlignedUnion() throws Exception {
|
||||
public void testByValueAlignedUnion() throws Exception {
|
||||
init(emptyUnion, pgmRootCat, false);
|
||||
|
||||
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
||||
@ -200,31 +199,32 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByValue1AlignedUnion() throws Exception {
|
||||
public void testByValue1AlignedUnion() throws Exception {
|
||||
checkByValueAlignedUnion(1, 4, 8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByValue2AlignedUnion() throws Exception {
|
||||
public void testByValue2AlignedUnion() throws Exception {
|
||||
checkByValueAlignedUnion(2, 4, 8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByValue4AlignedUnion() throws Exception {
|
||||
public void testByValue4AlignedUnion() throws Exception {
|
||||
checkByValueAlignedUnion(4, 4, 8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByValue8AlignedUnion() throws Exception {
|
||||
public void testByValue8AlignedUnion() throws Exception {
|
||||
checkByValueAlignedUnion(8, 8, 8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByValue16AlignedUnion() throws Exception {
|
||||
public void testByValue16AlignedUnion() throws Exception {
|
||||
checkByValueAlignedUnion(16, 16, 16);
|
||||
}
|
||||
|
||||
public void checkByValueAlignedUnion(int minAlignment, int alignment, int length) throws Exception {
|
||||
public void checkByValueAlignedUnion(int minAlignment, int alignment, int length)
|
||||
throws Exception {
|
||||
emptyUnion.setPackingEnabled(true);
|
||||
emptyUnion.setExplicitMinimumAlignment(minAlignment);
|
||||
|
||||
@ -256,7 +256,7 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTurnOffAlignmentInUnion() throws Exception {
|
||||
public void testTurnOffAlignmentInUnion() throws Exception {
|
||||
emptyUnion.setPackingEnabled(true);
|
||||
emptyUnion.setExplicitMinimumAlignment(8);
|
||||
|
||||
@ -304,7 +304,7 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertUnaligned1() throws Exception {
|
||||
public void testInsertUnaligned1() throws Exception {
|
||||
emptyUnion.setPackingEnabled(false);
|
||||
|
||||
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
||||
@ -337,7 +337,7 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertUnaligned2() throws Exception {
|
||||
public void testInsertUnaligned2() throws Exception {
|
||||
emptyUnion.setPackingEnabled(false);
|
||||
|
||||
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
||||
@ -370,7 +370,7 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertUnaligned3() throws Exception {
|
||||
public void testInsertUnaligned3() throws Exception {
|
||||
emptyUnion.setPackingEnabled(false);
|
||||
|
||||
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
||||
@ -403,7 +403,7 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceUnaligned1() throws Exception {
|
||||
public void testReplaceUnaligned1() throws Exception {
|
||||
emptyUnion.setPackingEnabled(false);
|
||||
|
||||
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
||||
@ -435,7 +435,7 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceUnaligned2() throws Exception {
|
||||
public void testReplaceUnaligned2() throws Exception {
|
||||
emptyUnion.setPackingEnabled(false);
|
||||
|
||||
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
||||
@ -468,7 +468,7 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertAligned1() throws Exception {
|
||||
public void testInsertAligned1() throws Exception {
|
||||
emptyUnion.setPackingEnabled(true);
|
||||
|
||||
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
||||
@ -501,7 +501,7 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertAligned2() throws Exception {
|
||||
public void testInsertAligned2() throws Exception {
|
||||
emptyUnion.setPackingEnabled(true);
|
||||
|
||||
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
||||
@ -534,7 +534,7 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertAligned3() throws Exception {
|
||||
public void testInsertAligned3() throws Exception {
|
||||
emptyUnion.setPackingEnabled(true);
|
||||
|
||||
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
||||
@ -567,7 +567,7 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceAligned1() throws Exception {
|
||||
public void testReplaceAligned1() throws Exception {
|
||||
emptyUnion.setPackingEnabled(true);
|
||||
|
||||
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
||||
@ -599,7 +599,7 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceAligned2() throws Exception {
|
||||
public void testReplaceAligned2() throws Exception {
|
||||
emptyUnion.setPackingEnabled(true);
|
||||
|
||||
DataType arrayDt = new ArrayDataType(new CharDataType(), 5, 1);
|
||||
@ -643,7 +643,8 @@ public class UnionEditorAlignmentTest extends AbstractUnionEditorTest {
|
||||
}
|
||||
|
||||
private DataTypeComponent addDataType(DataType dataType) {
|
||||
return unionModel.viewComposite.add(dataType);
|
||||
return unionModel.viewDTM.withTransaction("Add Component",
|
||||
() -> unionModel.viewComposite.add(dataType));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
@ -79,10 +79,8 @@ public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
|
||||
assertEquals(pgmBbCat.getCategoryPathName(), model.getOriginalCategoryPath().getPath());
|
||||
pgmTestCat.moveCategory(pgmBbCat, TaskMonitor.DUMMY);
|
||||
waitForSwing();
|
||||
assertTrue(model.getOriginalCategoryPath()
|
||||
.getPath()
|
||||
.startsWith(
|
||||
pgmTestCat.getCategoryPathName()));
|
||||
assertTrue(
|
||||
model.getOriginalCategoryPath().getPath().startsWith(pgmTestCat.getCategoryPathName()));
|
||||
assertEquals(pgmBbCat.getCategoryPathName(), model.getOriginalCategoryPath().getPath());
|
||||
}
|
||||
|
||||
@ -117,8 +115,7 @@ public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
programDTM.remove(complexUnion, TaskMonitor.DUMMY);
|
||||
programDTM.getCategory(pgmRootCat.getCategoryPath())
|
||||
.removeCategory("Temp",
|
||||
TaskMonitor.DUMMY);
|
||||
.removeCategory("Temp", TaskMonitor.DUMMY);
|
||||
});
|
||||
|
||||
waitForSwing();
|
||||
@ -280,8 +277,7 @@ public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
|
||||
public void testEditedDataTypeMoved() {
|
||||
init(complexUnion, pgmTestCat, false);
|
||||
|
||||
assertEquals(pgmTestCat.getCategoryPathName(),
|
||||
model.getOriginalCategoryPath().getPath());
|
||||
assertEquals(pgmTestCat.getCategoryPathName(), model.getOriginalCategoryPath().getPath());
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
try {
|
||||
pgmAaCat.moveDataType(complexUnion, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
@ -299,9 +295,8 @@ public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
|
||||
init(complexUnion, pgmTestCat, false);
|
||||
|
||||
assertEquals(21, model.getNumComponents());
|
||||
SwingUtilities.invokeLater(() -> complexUnion.getDataTypeManager()
|
||||
.remove(
|
||||
simpleStructure, TaskMonitor.DUMMY));
|
||||
SwingUtilities.invokeLater(
|
||||
() -> complexUnion.getDataTypeManager().remove(simpleStructure, TaskMonitor.DUMMY));
|
||||
waitForSwing();
|
||||
assertEquals(15, model.getNumComponents());
|
||||
}
|
||||
@ -321,9 +316,8 @@ public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
|
||||
waitForSwing();
|
||||
assertTrue(simpleUnion.isEquivalent(getDataType(0)));
|
||||
|
||||
SwingUtilities.invokeLater(() -> simpleUnion.getDataTypeManager()
|
||||
.remove(simpleUnion,
|
||||
TaskMonitor.DUMMY));
|
||||
SwingUtilities.invokeLater(
|
||||
() -> simpleUnion.getDataTypeManager().remove(simpleUnion, TaskMonitor.DUMMY));
|
||||
waitForSwing();
|
||||
assertEquals(0, model.getNumComponents());
|
||||
}
|
||||
@ -497,18 +491,14 @@ public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
|
||||
newComplexUnion.add(new CharDataType(), 1);
|
||||
|
||||
programDTM.replaceDataType(complexUnion, newComplexUnion, true);
|
||||
waitForSwing();
|
||||
DataType origCopy = newComplexUnion.clone(null);
|
||||
|
||||
// Verify the Reload Union Editor? dialog is displayed.
|
||||
Window dialog = waitForWindow("Reload Union Editor?");
|
||||
Window dialog = waitForWindow("Close Union Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButtonByText(dialog, "Yes");
|
||||
dialog.dispose();
|
||||
dialog = null;
|
||||
waitForSwing();
|
||||
|
||||
assertEquals(((Union) origCopy).getNumComponents(), model.getNumComponents());
|
||||
assertTrue(origCopy.isEquivalent(model.viewComposite));
|
||||
assertFalse(provider.isVisible());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -532,14 +522,14 @@ public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
|
||||
newComplexUnion.add(new CharDataType(), 1);
|
||||
|
||||
programDTM.replaceDataType(complexUnion, newComplexUnion, true);
|
||||
waitForSwing();
|
||||
|
||||
// Verify the Reload Union Editor? dialog is displayed.
|
||||
Window dialog = waitForWindow("Reload Union Editor?");
|
||||
Window dialog = waitForWindow("Close Union Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButtonByText(dialog, "No");
|
||||
dialog.dispose();
|
||||
dialog = null;
|
||||
waitForSwing();
|
||||
|
||||
assertTrue(provider.isVisible());
|
||||
|
||||
assertEquals(((Union) viewCopy).getNumComponents(), model.getNumComponents());
|
||||
assertTrue(viewCopy.isEquivalent(model.viewComposite));
|
||||
@ -556,8 +546,14 @@ public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
|
||||
|
||||
assertTrue(complexUnion.isEquivalent(model.viewComposite));
|
||||
programDTM.replaceDataType(complexUnion, newComplexUnion, true);
|
||||
|
||||
// Verify Union Editor closes (we don't want two editors for the same type)
|
||||
Window dialog = waitForWindow("Closing Union Editor");
|
||||
assertNotNull(dialog);
|
||||
pressButtonByText(dialog, "OK");
|
||||
waitForSwing();
|
||||
assertTrue(newComplexUnion.isEquivalent(model.viewComposite));
|
||||
|
||||
assertFalse(provider.isVisible());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
@ -160,14 +160,28 @@ public class UnionEditorProviderTest extends AbstractUnionEditorTest {
|
||||
|
||||
// Apply the changes
|
||||
invoke(applyAction);
|
||||
waitForSwing();
|
||||
|
||||
assertTrue(complexUnion.isEquivalent(model.viewComposite));
|
||||
|
||||
// Undo the apply
|
||||
undo(program);
|
||||
|
||||
Window dialog = waitForWindow("Reload Union Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "Yes");
|
||||
waitForSwing();
|
||||
|
||||
assertTrue(complexUnion.isEquivalent(model.viewComposite));
|
||||
|
||||
// Redo the apply
|
||||
redo(program);
|
||||
|
||||
dialog = waitForWindow("Reload Union Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "Yes");
|
||||
waitForSwing();
|
||||
|
||||
assertTrue(complexUnion.isEquivalent(model.viewComposite));
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
@ -170,7 +170,7 @@ public class StackEditorProvider1Test extends AbstractStackEditorProviderTest {
|
||||
failWithException("Editor apply failure", e);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
deleteFunction("0x200");
|
||||
|
||||
// Verify the Reload Stack Editor? dialog is not displayed.
|
||||
@ -378,7 +378,6 @@ public class StackEditorProvider1Test extends AbstractStackEditorProviderTest {
|
||||
|
||||
@Test
|
||||
public void testUndoApplyComponentChanges() throws Exception {
|
||||
Window dialog;
|
||||
|
||||
editStack(function.getEntryPoint().toString());
|
||||
|
||||
@ -404,7 +403,7 @@ public class StackEditorProvider1Test extends AbstractStackEditorProviderTest {
|
||||
|
||||
// Verify the Reload Stack Editor? dialog is displayed.
|
||||
waitForSwing();
|
||||
dialog = getWindow("Reload Stack Editor?");
|
||||
Window dialog = getWindow("Reload Stack Editor?");
|
||||
assertNull(dialog);
|
||||
sv = stack.getVariableContaining(-0x8);
|
||||
assertNotNull(sv);
|
||||
@ -428,41 +427,60 @@ public class StackEditorProvider1Test extends AbstractStackEditorProviderTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUndoNewDtComponent() throws Exception {
|
||||
public void testUndoNewDtComponentWithChange() throws Exception {
|
||||
|
||||
// NOTE: This test appears to verify that the undefined*16 type
|
||||
// resolved against the program DTM used by the stack editor
|
||||
// is removed on the first undo - unfortunately, the redo
|
||||
// does not restore the editor state. It is unclear why a private
|
||||
// DTM is not employed similar to the Structure editor which
|
||||
// would allow the new undefined*16 type to persist after the undo (see SCR 10280)
|
||||
editStack(function.getEntryPoint().toString());
|
||||
|
||||
Window dialog;
|
||||
// Put 2 byte pointer at -0x1b
|
||||
DataType ptr = new Pointer16DataType();
|
||||
setType(ptr, 4);
|
||||
|
||||
apply();
|
||||
waitForSwing();
|
||||
|
||||
// Put word pointer at -0x1b
|
||||
setType(WordDataType.dataType, 4);
|
||||
|
||||
// Undo the apply of a new data type to an editor component.
|
||||
undo(program, false);
|
||||
|
||||
// Verify the Reload Stack Editor? dialog is displayed.
|
||||
Window dialog = waitForWindow("Reload Stack Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "No");
|
||||
|
||||
waitForSwing();
|
||||
|
||||
// Redo the apply
|
||||
redo(program, false);
|
||||
|
||||
dialog = waitForWindow("Reload Stack Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "Yes");
|
||||
waitForSwing();
|
||||
|
||||
assertTrue(ptr.isEquivalent(getDataType(4)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUndoNewDtComponentWithoutChange() throws Exception {
|
||||
|
||||
editStack(function.getEntryPoint().toString());
|
||||
|
||||
// Put 2 byte pointer at -0x1b
|
||||
setType(new Pointer16DataType(), 4);
|
||||
|
||||
apply();
|
||||
waitForSwing();
|
||||
|
||||
// Undo the apply of a new data type to an editor component.
|
||||
undo(program, false);
|
||||
|
||||
// Verify the Reload Stack Editor? dialog is displayed.
|
||||
dialog = waitForWindow("Reload Stack Editor?");
|
||||
assertNotNull(dialog);
|
||||
pressButton(dialog, "No");
|
||||
dialog.dispose();
|
||||
waitForSwing();
|
||||
|
||||
dialog = getWindow("Reload Stack Editor?");
|
||||
Window dialog = getWindow("Reload Stack Editor?");
|
||||
assertNull(dialog);
|
||||
|
||||
// Redo the apply
|
||||
redo(program, false);
|
||||
waitForSwing();
|
||||
dialog = getWindow("Reload Stack Editor?");
|
||||
assertNull(dialog);
|
||||
|
||||
cleanup();
|
||||
assertEquals(DataType.DEFAULT, getDataType(4));
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
@ -685,6 +685,8 @@ public class CategoryTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
DataType byteDt = root.getDataType("byte");
|
||||
DataType wordDt = root.getDataType("word");
|
||||
|
||||
assertEquals(4, getEventCount());
|
||||
|
||||
Event ev = getEvent(0);
|
||||
assertEquals("Cat Added", ev.evName);
|
||||
assertEquals(null, ev.dt);
|
||||
@ -701,22 +703,10 @@ public class CategoryTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertEquals(root.getCategoryPath(), ev.parent);
|
||||
|
||||
ev = getEvent(3);
|
||||
assertEquals("DT Changed", ev.evName);
|
||||
assertTrue(dt.isEquivalent(ev.dt));
|
||||
assertEquals(null, ev.parent);
|
||||
|
||||
// ev = getEvent(4); // eliminated size change event during creation
|
||||
// assertEquals("DT Changed", ev.evName);
|
||||
// assertTrue(dt.isEquivalent(ev.dt));
|
||||
// assertEquals(null, ev.parent);
|
||||
|
||||
ev = getEvent(4);
|
||||
assertEquals("DT Added", ev.evName);
|
||||
assertTrue(dt.isEquivalent(ev.dt));
|
||||
assertEquals(sub1.getCategoryPath(), ev.parent);
|
||||
|
||||
assertEquals(5, getEventCount());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -807,8 +797,9 @@ public class CategoryTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
struct2 = (Structure) newDt.insert(3, struct2).getDataType();
|
||||
|
||||
assertEquals(4, getEventCount());
|
||||
Event ev = getEvent(3);
|
||||
assertEquals(3, getEventCount());
|
||||
|
||||
Event ev = getEvent(2);
|
||||
assertEquals("DT Changed", ev.evName);
|
||||
assertEquals(newDt, ev.dt);
|
||||
}
|
||||
|
@ -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.
|
||||
@ -283,6 +283,7 @@ public class UnionDataTypeTest extends AbstractGenericTest {
|
||||
union.delete(Sets.newHashSet(2, 4));
|
||||
|
||||
assertEquals(2, union.getLength());
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||
"pack(disabled)\n" +
|
||||
@ -293,6 +294,10 @@ public class UnionDataTypeTest extends AbstractGenericTest {
|
||||
"}\n" +
|
||||
"Length: 2 Alignment: 1", union);
|
||||
//@formatter:on
|
||||
|
||||
DataTypeComponent[] comps = union.getDefinedComponents();
|
||||
assertEquals(ByteDataType.class, comps[2].getDataType().getClass());
|
||||
assertEquals(2, comps[2].getOrdinal());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -10,10 +10,6 @@ color.bg.version.tracking.dual.listing.highlight.markup.failed = color.palette.r
|
||||
color.bg.version.tracking.dual.listing.highlight.markup.no.address = color.palette.lavender
|
||||
color.bg.version.tracking.dual.listing.highlight.markup.same = color.palette.lightskyblue
|
||||
color.bg.version.tracking.dual.listing.highlight.markup.conflict = color.palette.gold
|
||||
|
||||
color.bg.version.tracking.filter.formatted.field.error = color.palette.lightgray
|
||||
color.bg.version.tracking.filter.formatted.field.editing = color.bg.filterfield
|
||||
color.fg.version.tracking.filter.formatted.field.editing = color.fg.filterfield
|
||||
|
||||
color.bg.version.tracking.match.table.locked.out = color.palette.aliceblue
|
||||
color.bg.version.tracking.match.table.markup.status.applied = color.palette.limegreen
|
||||
@ -83,7 +79,6 @@ icon.version.tracking.tag.status.deleted = tag_blue_delete.png
|
||||
icon.version.tracking.tag.status.existing = tag_blue.png
|
||||
icon.version.tracking.tag.button.undo = undo-apply.png
|
||||
|
||||
icon.version.tracking.filter.status.changed = bullet_black.png
|
||||
icon.version.tracking.filter.status.invalid = no_small.png
|
||||
icon.version.tracking.filter.status.applied = bullet_green.png
|
||||
|
||||
|
@ -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,9 @@ import docking.widgets.checkbox.GCheckBox;
|
||||
import docking.widgets.combobox.GhidraComboBox;
|
||||
import docking.widgets.label.GDLabel;
|
||||
import docking.widgets.label.GHtmlLabel;
|
||||
import docking.widgets.textfield.HexIntegerFormatter;
|
||||
import docking.widgets.numberformat.HexIntegerFormatter;
|
||||
import docking.widgets.numberformat.IntegerFormatterFactory;
|
||||
import docking.widgets.textfield.*;
|
||||
import generic.theme.GColor;
|
||||
import ghidra.feature.vt.api.main.VTAssociation;
|
||||
import ghidra.feature.vt.gui.provider.matchtable.NumberRangeProducer;
|
||||
@ -59,8 +61,8 @@ public abstract class AbstractAddressRangeFilter<T> extends AncillaryFilter<T>
|
||||
private static final Long MAX_ADDRESS_VALUE = Long.MAX_VALUE;
|
||||
|
||||
private JComponent component;
|
||||
private FilterFormattedTextField lowerAddressRangeTextField;
|
||||
private FilterFormattedTextField upperAddressRangeTextField;
|
||||
private GFormattedTextField lowerAddressRangeTextField;
|
||||
private GFormattedTextField upperAddressRangeTextField;
|
||||
private JComboBox<String> lowerRangeComboBox;
|
||||
private JComboBox<String> upperRangeComboBox;
|
||||
|
||||
@ -90,14 +92,14 @@ public abstract class AbstractAddressRangeFilter<T> extends AncillaryFilter<T>
|
||||
enablePanel.add(enableCheckBox, BorderLayout.NORTH);
|
||||
|
||||
// begin address field (long input field with hex)
|
||||
lowerAddressRangeTextField = new FilterFormattedTextField(
|
||||
lowerAddressRangeTextField = new GFormattedTextField(
|
||||
new IntegerFormatterFactory(new HexIntegerFormatter(), false), MIN_ADDRESS_VALUE);
|
||||
lowerAddressRangeTextField.setName("Lower Address Range Text Field"); // for tracking state
|
||||
lowerAddressRangeTextField.setColumns(15);
|
||||
lowerAddressRangeTextField.setMinimumSize(lowerAddressRangeTextField.getPreferredSize());
|
||||
|
||||
// end address field (long input field with hex)
|
||||
upperAddressRangeTextField = new FilterFormattedTextField(
|
||||
upperAddressRangeTextField = new GFormattedTextField(
|
||||
new IntegerFormatterFactory(new HexIntegerFormatter(), false), MAX_ADDRESS_VALUE);
|
||||
upperAddressRangeTextField.setName("Upper Address Range Text Field"); // for tracking state
|
||||
upperAddressRangeTextField.setColumns(15);
|
||||
@ -169,17 +171,20 @@ public abstract class AbstractAddressRangeFilter<T> extends AncillaryFilter<T>
|
||||
}
|
||||
};
|
||||
|
||||
FilterStatusListener notificationListener = status -> fireStatusChanged(status);
|
||||
TextEntryStatusListener notificationListener = s -> {
|
||||
FilterEditingStatus status = FilterEditingStatus.getFilterStatus(s);
|
||||
fireStatusChanged(status);
|
||||
};
|
||||
|
||||
StatusLabel lowerScoreStatusLabel =
|
||||
new StatusLabel(lowerAddressRangeTextField, MIN_ADDRESS_VALUE);
|
||||
lowerAddressRangeTextField.addFilterStatusListener(lowerScoreStatusLabel);
|
||||
lowerAddressRangeTextField.addFilterStatusListener(notificationListener);
|
||||
lowerAddressRangeTextField.addTextEntryStatusListener(lowerScoreStatusLabel);
|
||||
lowerAddressRangeTextField.addTextEntryStatusListener(notificationListener);
|
||||
|
||||
StatusLabel upperScoreStatusLabel =
|
||||
new StatusLabel(upperAddressRangeTextField, MAX_ADDRESS_VALUE);
|
||||
upperAddressRangeTextField.addFilterStatusListener(upperScoreStatusLabel);
|
||||
upperAddressRangeTextField.addFilterStatusListener(notificationListener);
|
||||
upperAddressRangeTextField.addTextEntryStatusListener(upperScoreStatusLabel);
|
||||
upperAddressRangeTextField.addTextEntryStatusListener(notificationListener);
|
||||
|
||||
disabledScreen = createDisabledScreen(layeredPane);
|
||||
|
||||
@ -246,7 +251,7 @@ public abstract class AbstractAddressRangeFilter<T> extends AncillaryFilter<T>
|
||||
component.validate();
|
||||
}
|
||||
|
||||
private JComboBox<String> createComboBox(FilterFormattedTextField field, Long defaultValue,
|
||||
private JComboBox<String> createComboBox(GFormattedTextField field, Long defaultValue,
|
||||
String prototypeString) {
|
||||
GhidraComboBox<String> comboBox = new GhidraComboBox<>(new LimitedHistoryComboBoxModel()) {
|
||||
// overridden to paint seamlessly with out color changing text field
|
||||
@ -287,14 +292,22 @@ public abstract class AbstractAddressRangeFilter<T> extends AncillaryFilter<T>
|
||||
return component;
|
||||
}
|
||||
|
||||
private FilterEditingStatus getLowerAddressRangeStatus() {
|
||||
return FilterEditingStatus.getFilterStatus(lowerAddressRangeTextField);
|
||||
}
|
||||
|
||||
private FilterEditingStatus getUpperAddressRangeStatus() {
|
||||
return FilterEditingStatus.getFilterStatus(upperAddressRangeTextField);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterEditingStatus getFilterStatus() {
|
||||
if (!isEnabled) {
|
||||
return FilterEditingStatus.NONE;
|
||||
}
|
||||
|
||||
FilterEditingStatus lowerStatus = lowerAddressRangeTextField.getFilterStatus();
|
||||
FilterEditingStatus upperStatus = upperAddressRangeTextField.getFilterStatus();
|
||||
FilterEditingStatus lowerStatus = getLowerAddressRangeStatus();
|
||||
FilterEditingStatus upperStatus = getUpperAddressRangeStatus();
|
||||
|
||||
if (lowerStatus == FilterEditingStatus.ERROR || upperStatus == FilterEditingStatus.ERROR) {
|
||||
return FilterEditingStatus.ERROR;
|
||||
@ -339,8 +352,8 @@ public abstract class AbstractAddressRangeFilter<T> extends AncillaryFilter<T>
|
||||
return true;
|
||||
}
|
||||
|
||||
if (lowerAddressRangeTextField.getFilterStatus() == FilterEditingStatus.ERROR ||
|
||||
upperAddressRangeTextField.getFilterStatus() == FilterEditingStatus.ERROR) {
|
||||
if (getLowerAddressRangeStatus() == FilterEditingStatus.ERROR ||
|
||||
getUpperAddressRangeStatus() == FilterEditingStatus.ERROR) {
|
||||
return true; // for an invalid filter state, we let all values through
|
||||
}
|
||||
|
||||
@ -572,10 +585,10 @@ public abstract class AbstractAddressRangeFilter<T> extends AncillaryFilter<T>
|
||||
private class FormattedFieldComboBoxEditor implements ComboBoxEditor {
|
||||
|
||||
private EventListenerList listeners = new EventListenerList();
|
||||
private final FilterFormattedTextField textField;
|
||||
private final GFormattedTextField textField;
|
||||
private final Object defaultValue;
|
||||
|
||||
FormattedFieldComboBoxEditor(FilterFormattedTextField textField) {
|
||||
FormattedFieldComboBoxEditor(GFormattedTextField textField) {
|
||||
this.textField = textField;
|
||||
defaultValue = textField.getValue();
|
||||
}
|
||||
|
@ -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.
|
||||
@ -22,6 +22,7 @@ import java.util.Set;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
|
||||
import docking.widgets.textfield.GFormattedTextField;
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.util.exception.AssertException;
|
||||
@ -72,8 +73,6 @@ public abstract class Filter<T> {
|
||||
|
||||
public enum FilterEditingStatus {
|
||||
NONE("", null),
|
||||
DIRTY("Filter contents have changed, but are not yet applied", new GIcon(
|
||||
"icon.version.tracking.filter.status.changed")),
|
||||
ERROR("Filter contents are not valid", new GIcon(
|
||||
"icon.version.tracking.filter.status.invalid")),
|
||||
APPLIED("Filter applied", new GIcon("icon.version.tracking.filter.status.applied"));
|
||||
@ -93,6 +92,17 @@ public abstract class Filter<T> {
|
||||
Icon getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public static FilterEditingStatus getFilterStatus(GFormattedTextField textEntryField) {
|
||||
switch (textEntryField.getTextEntryStatus()) {
|
||||
case INVALID:
|
||||
return FilterEditingStatus.ERROR;
|
||||
case CHANGED:
|
||||
return FilterEditingStatus.APPLIED;
|
||||
default:
|
||||
return FilterEditingStatus.NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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.
|
||||
@ -21,9 +21,11 @@ import java.awt.event.*;
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.widgets.label.GDLabel;
|
||||
import docking.widgets.textfield.GFormattedTextField;
|
||||
import docking.widgets.textfield.TextEntryStatusListener;
|
||||
import ghidra.feature.vt.gui.filters.Filter.FilterEditingStatus;
|
||||
|
||||
public class StatusLabel extends GDLabel implements FilterStatusListener {
|
||||
public class StatusLabel extends GDLabel implements TextEntryStatusListener {
|
||||
|
||||
private final JFormattedTextField textField;
|
||||
|
||||
@ -82,7 +84,8 @@ public class StatusLabel extends GDLabel implements FilterStatusListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void filterStatusChanged(FilterEditingStatus status) {
|
||||
public void statusChanged(GFormattedTextField textEntryField) {
|
||||
FilterEditingStatus status = FilterEditingStatus.getFilterStatus(textEntryField);
|
||||
resetBounds();
|
||||
setIcon(status.getIcon());
|
||||
setToolTipText(status.getDescription() + " (click to reset)");
|
||||
|
@ -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,6 +26,8 @@ import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.widgets.label.GDLabel;
|
||||
import docking.widgets.numberformat.BoundedRangeDecimalFormatterFactory;
|
||||
import docking.widgets.textfield.GFormattedTextField;
|
||||
import docking.widgets.textfield.TextEntryStatusListener;
|
||||
import ghidra.feature.vt.gui.filters.*;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.util.layout.HorizontalLayout;
|
||||
@ -41,8 +43,8 @@ public abstract class AbstractDoubleRangeFilter<T> extends Filter<T>
|
||||
private final Double minValue;
|
||||
|
||||
private JComponent component;
|
||||
private FilterFormattedTextField upperBoundField;
|
||||
private FilterFormattedTextField lowerBoundField;
|
||||
private GFormattedTextField upperBoundField;
|
||||
private GFormattedTextField lowerBoundField;
|
||||
private String filterName;
|
||||
|
||||
AbstractDoubleRangeFilter(String filterName, Double minValue, Double maxValue) {
|
||||
@ -54,7 +56,7 @@ public abstract class AbstractDoubleRangeFilter<T> extends Filter<T>
|
||||
}
|
||||
|
||||
private void createLowerBoundField() {
|
||||
lowerBoundField = new FilterFormattedTextField(
|
||||
lowerBoundField = new GFormattedTextField(
|
||||
new BoundedRangeDecimalFormatterFactory(maxValue, minValue, FORMAT), minValue);
|
||||
lowerBoundField.setName("Lower " + filterName + " Filter Field"); // for debugging
|
||||
lowerBoundField.setColumns(4);
|
||||
@ -63,7 +65,7 @@ public abstract class AbstractDoubleRangeFilter<T> extends Filter<T>
|
||||
}
|
||||
|
||||
private void createUpperBoundField() {
|
||||
upperBoundField = new FilterFormattedTextField(
|
||||
upperBoundField = new GFormattedTextField(
|
||||
new BoundedRangeDecimalFormatterFactory(maxValue, minValue, FORMAT), maxValue);
|
||||
upperBoundField.setName("Upper " + filterName + " Filter Field"); // for debugging
|
||||
upperBoundField.setColumns(4);
|
||||
@ -93,15 +95,18 @@ public abstract class AbstractDoubleRangeFilter<T> extends Filter<T>
|
||||
panel.add(middleLabel);
|
||||
panel.add(upperBoundField);
|
||||
|
||||
FilterStatusListener notificationListener = status -> fireStatusChanged(status);
|
||||
TextEntryStatusListener notificationListener = s -> {
|
||||
FilterEditingStatus status = FilterEditingStatus.getFilterStatus(s);
|
||||
fireStatusChanged(status);
|
||||
};
|
||||
|
||||
StatusLabel lowerBoundStatusLabel = new StatusLabel(lowerBoundField, minValue);
|
||||
lowerBoundField.addFilterStatusListener(lowerBoundStatusLabel);
|
||||
lowerBoundField.addFilterStatusListener(notificationListener);
|
||||
lowerBoundField.addTextEntryStatusListener(lowerBoundStatusLabel);
|
||||
lowerBoundField.addTextEntryStatusListener(notificationListener);
|
||||
|
||||
StatusLabel upperBoundStatusLabel = new StatusLabel(upperBoundField, maxValue);
|
||||
upperBoundField.addFilterStatusListener(upperBoundStatusLabel);
|
||||
upperBoundField.addFilterStatusListener(notificationListener);
|
||||
upperBoundField.addTextEntryStatusListener(upperBoundStatusLabel);
|
||||
upperBoundField.addTextEntryStatusListener(notificationListener);
|
||||
|
||||
JLayeredPane layeredPane = new JLayeredPane();
|
||||
layeredPane.add(panel, BASE_COMPONENT_LAYER);
|
||||
@ -127,10 +132,18 @@ public abstract class AbstractDoubleRangeFilter<T> extends Filter<T>
|
||||
return component;
|
||||
}
|
||||
|
||||
private FilterEditingStatus getLowerBoundStatus() {
|
||||
return FilterEditingStatus.getFilterStatus(lowerBoundField);
|
||||
}
|
||||
|
||||
private FilterEditingStatus getUpperBoundStatus() {
|
||||
return FilterEditingStatus.getFilterStatus(upperBoundField);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterEditingStatus getFilterStatus() {
|
||||
FilterEditingStatus lowerStatus = lowerBoundField.getFilterStatus();
|
||||
FilterEditingStatus upperStatus = upperBoundField.getFilterStatus();
|
||||
FilterEditingStatus lowerStatus = getLowerBoundStatus();
|
||||
FilterEditingStatus upperStatus = getUpperBoundStatus();
|
||||
|
||||
if (lowerStatus == FilterEditingStatus.ERROR || upperStatus == FilterEditingStatus.ERROR) {
|
||||
return FilterEditingStatus.ERROR;
|
||||
@ -146,8 +159,8 @@ public abstract class AbstractDoubleRangeFilter<T> extends Filter<T>
|
||||
|
||||
@Override
|
||||
public boolean passesFilter(T t) {
|
||||
if (lowerBoundField.getFilterStatus() == FilterEditingStatus.ERROR ||
|
||||
upperBoundField.getFilterStatus() == FilterEditingStatus.ERROR) {
|
||||
if (getLowerBoundStatus() == FilterEditingStatus.ERROR ||
|
||||
getUpperBoundStatus() == FilterEditingStatus.ERROR) {
|
||||
return true; // for an invalid filter state, we let all values through
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
@ -27,6 +27,8 @@ import javax.swing.border.Border;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.widgets.label.GDLabel;
|
||||
import docking.widgets.numberformat.IntegerFormatterFactory;
|
||||
import docking.widgets.textfield.GFormattedTextField;
|
||||
import ghidra.feature.vt.api.main.VTMatch;
|
||||
import ghidra.feature.vt.gui.filters.*;
|
||||
import ghidra.framework.options.SaveState;
|
||||
@ -39,7 +41,7 @@ public class LengthFilter extends Filter<VTMatch> {
|
||||
private static final Integer DEFAULT_FILTER_VALUE = 0;
|
||||
|
||||
private JComponent component;
|
||||
private FilterFormattedTextField textField;
|
||||
private GFormattedTextField textField;
|
||||
|
||||
public LengthFilter() {
|
||||
component = createComponent();
|
||||
@ -49,7 +51,7 @@ public class LengthFilter extends Filter<VTMatch> {
|
||||
final JLabel label = new GDLabel("Length Filter: ");
|
||||
|
||||
Integer defaultValue = DEFAULT_FILTER_VALUE;
|
||||
textField = new FilterFormattedTextField(new IntegerFormatterFactory(false), defaultValue);
|
||||
textField = new GFormattedTextField(new IntegerFormatterFactory(false), defaultValue);
|
||||
textField.setName("Length Filter Field"); // for debugging
|
||||
textField.setInputVerifier(new IntegerInputVerifier());
|
||||
textField.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
@ -67,8 +69,11 @@ public class LengthFilter extends Filter<VTMatch> {
|
||||
final JLayeredPane layeredPane = new JLayeredPane();
|
||||
|
||||
StatusLabel statusLabel = new StatusLabel(textField, defaultValue);
|
||||
textField.addFilterStatusListener(statusLabel);
|
||||
textField.addFilterStatusListener(status -> fireStatusChanged(status));
|
||||
textField.addTextEntryStatusListener(statusLabel);
|
||||
textField.addTextEntryStatusListener(s -> {
|
||||
FilterEditingStatus status = FilterEditingStatus.getFilterStatus(s);
|
||||
fireStatusChanged(status);
|
||||
});
|
||||
layeredPane.add(panel, BASE_COMPONENT_LAYER);
|
||||
layeredPane.add(statusLabel, HOVER_COMPONENT_LAYER);
|
||||
layeredPane.setPreferredSize(panel.getPreferredSize());
|
||||
@ -91,7 +96,7 @@ public class LengthFilter extends Filter<VTMatch> {
|
||||
|
||||
@Override
|
||||
public FilterEditingStatus getFilterStatus() {
|
||||
return textField.getFilterStatus();
|
||||
return FilterEditingStatus.getFilterStatus(textField);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -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.
|
||||
@ -28,9 +28,11 @@ import javax.swing.text.DefaultFormatterFactory;
|
||||
|
||||
import docking.widgets.label.GDLabel;
|
||||
import docking.widgets.table.GTable;
|
||||
import docking.widgets.textfield.GFormattedTextField;
|
||||
import ghidra.feature.vt.api.main.VTAssociation;
|
||||
import ghidra.feature.vt.api.main.VTSession;
|
||||
import ghidra.feature.vt.gui.filters.*;
|
||||
import ghidra.feature.vt.gui.filters.Filter;
|
||||
import ghidra.feature.vt.gui.filters.StatusLabel;
|
||||
import ghidra.feature.vt.gui.plugin.VTController;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.program.model.address.Address;
|
||||
@ -44,7 +46,7 @@ public abstract class AbstractTextFilter<T> extends Filter<T> {
|
||||
private static final Integer HOVER_COMPONENT_LAYER = 2;
|
||||
|
||||
private JComponent component;
|
||||
private FilterFormattedTextField textField;
|
||||
private GFormattedTextField textField;
|
||||
private String defaultValue = "";
|
||||
protected VTController controller;
|
||||
protected final GTable table;
|
||||
@ -62,7 +64,7 @@ public abstract class AbstractTextFilter<T> extends Filter<T> {
|
||||
panel.setBorder(BorderFactory.createCompoundBorder(outsideBorder, paddingBorder));
|
||||
|
||||
DefaultFormatterFactory factory = new DefaultFormatterFactory(new DefaultFormatter());
|
||||
textField = new FilterFormattedTextField(factory, defaultValue);
|
||||
textField = new GFormattedTextField(factory, defaultValue);
|
||||
textField.setName(filterName + " Field"); // for debugging
|
||||
textField.setColumns(20);
|
||||
textField.setMinimumSize(textField.getPreferredSize());
|
||||
@ -76,8 +78,11 @@ public abstract class AbstractTextFilter<T> extends Filter<T> {
|
||||
panel.add(textField, BorderLayout.CENTER);
|
||||
|
||||
StatusLabel nameFieldStatusLabel = new StatusLabel(textField, defaultValue);
|
||||
textField.addFilterStatusListener(nameFieldStatusLabel);
|
||||
textField.addFilterStatusListener(status -> fireStatusChanged(status));
|
||||
textField.addTextEntryStatusListener(nameFieldStatusLabel);
|
||||
textField.addTextEntryStatusListener(s -> {
|
||||
FilterEditingStatus status = FilterEditingStatus.getFilterStatus(s);
|
||||
fireStatusChanged(status);
|
||||
});
|
||||
|
||||
final JLayeredPane layeredPane = new JLayeredPane();
|
||||
layeredPane.add(panel, BASE_COMPONENT_LAYER);
|
||||
@ -127,7 +132,7 @@ public abstract class AbstractTextFilter<T> extends Filter<T> {
|
||||
|
||||
@Override
|
||||
public FilterEditingStatus getFilterStatus() {
|
||||
return textField.getFilterStatus();
|
||||
return FilterEditingStatus.getFilterStatus(textField);
|
||||
}
|
||||
|
||||
protected String getTextFieldText() {
|
||||
|
@ -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.
|
||||
@ -532,6 +532,16 @@ public class DBHandle {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a means of detecting changes to the underlying database buffers
|
||||
* during a transaction.
|
||||
*
|
||||
* @return current modification count
|
||||
*/
|
||||
public long getModCount() {
|
||||
return bufferMgr.getModCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there are uncommitted changes to the database.
|
||||
* @return true if there are uncommitted changes to the database.
|
||||
|
@ -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.
|
||||
@ -68,6 +68,7 @@ public class BufferMgr {
|
||||
private Object snapshotLock = new Object(); // Used to prevent BufferNode modifications during snapshot
|
||||
private boolean modifiedSinceSnapshot = false;
|
||||
private boolean hasNonUndoableChanges = false;
|
||||
private long modCount;
|
||||
|
||||
private int bufferSize;
|
||||
|
||||
@ -238,7 +239,7 @@ public class BufferMgr {
|
||||
if (lockCount != 0) {
|
||||
throw new IOException("Unable to re-initialize buffer cache while in-use");
|
||||
}
|
||||
|
||||
|
||||
if (cacheFile != null) {
|
||||
cacheFile.delete();
|
||||
}
|
||||
@ -248,7 +249,7 @@ public class BufferMgr {
|
||||
cacheTail = new BufferNode(TAIL, -1);
|
||||
cacheHead.nextCached = cacheTail;
|
||||
cacheTail.prevCached = cacheHead;
|
||||
|
||||
|
||||
cacheSize = 0;
|
||||
buffersOnHand = 0;
|
||||
|
||||
@ -264,7 +265,7 @@ public class BufferMgr {
|
||||
cacheFile.setParameter(name, sourceFile.getParameter(name));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
resetCacheStatistics();
|
||||
|
||||
if (alwaysPreCache) {
|
||||
@ -1093,6 +1094,7 @@ public class BufferMgr {
|
||||
throw new AssertException();
|
||||
}
|
||||
|
||||
++modCount;
|
||||
modifiedSinceSnapshot = true;
|
||||
|
||||
// Establish current checkpoint if necessary
|
||||
@ -1199,6 +1201,14 @@ public class BufferMgr {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a means of detecting changes to the underlying database during a transaction.
|
||||
* @return current modification count
|
||||
*/
|
||||
public synchronized long getModCount() {
|
||||
return modCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if unsaved "buffer" changes exist.
|
||||
* If no changes have been made, or all changes have been
|
||||
|
@ -54,6 +54,10 @@ color.bg.widget.tabs.more.tabs.hover = color.bg.widget.tabs.selected
|
||||
|
||||
color.fg.widget.tabs.list = color.fg
|
||||
|
||||
color.bg.formatted.field.error = color.palette.lightcoral
|
||||
color.bg.formatted.field.editing = color.bg.filterfield
|
||||
color.fg.formatted.field.editing = color.fg.filterfield
|
||||
|
||||
|
||||
icon.folder.new = folder_add.png
|
||||
icon.toggle.expand = expand.gif
|
||||
|
@ -4,16 +4,16 @@
|
||||
* 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 docking.widgets.textfield;
|
||||
package docking.widgets.numberformat;
|
||||
|
||||
import java.text.Format;
|
||||
import java.text.ParseException;
|
@ -1,20 +1,19 @@
|
||||
/* ###
|
||||
* 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 docking.widgets.textfield;
|
||||
package docking.widgets.numberformat;
|
||||
|
||||
import java.awt.Toolkit;
|
||||
import java.text.*;
|
@ -1,27 +1,24 @@
|
||||
/* ###
|
||||
* 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.feature.vt.gui.filters;
|
||||
package docking.widgets.numberformat;
|
||||
|
||||
import javax.swing.JFormattedTextField;
|
||||
import javax.swing.JFormattedTextField.AbstractFormatter;
|
||||
import javax.swing.text.DefaultFormatterFactory;
|
||||
|
||||
import docking.widgets.textfield.IntegerFormatter;
|
||||
|
||||
public class IntegerFormatterFactory extends DefaultFormatterFactory {
|
||||
|
||||
private AbstractFormatter formatter = new IntegerFormatter();
|
@ -4,18 +4,16 @@
|
||||
* 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.feature.vt.gui.filters;
|
||||
|
||||
import static ghidra.feature.vt.gui.filters.Filter.FilterEditingStatus.*;
|
||||
package docking.widgets.textfield;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.event.FocusEvent;
|
||||
@ -30,34 +28,42 @@ import javax.swing.event.DocumentListener;
|
||||
|
||||
import generic.theme.GColor;
|
||||
import generic.theme.GThemeDefaults.Colors;
|
||||
import ghidra.feature.vt.gui.filters.Filter.FilterEditingStatus;
|
||||
import ghidra.util.SystemUtilities;
|
||||
|
||||
public class FilterFormattedTextField extends JFormattedTextField {
|
||||
/**
|
||||
* {@link GFormattedTextField} provides an implementation of {@link JFormattedTextField}
|
||||
* which facilitates entry validation with an indication of its current status.
|
||||
* <br>
|
||||
* When modified from its default value the field background will reflect its
|
||||
* current status.
|
||||
*/
|
||||
public class GFormattedTextField extends JFormattedTextField {
|
||||
private static final Color ERROR_BACKGROUND_COLOR =
|
||||
new GColor("color.bg.version.tracking.filter.formatted.field.error");
|
||||
new GColor("color.bg.formatted.field.error");
|
||||
private static final Color EDITING_BACKGROUND_COLOR =
|
||||
new GColor("color.bg.version.tracking.filter.formatted.field.editing");
|
||||
new GColor("color.bg.formatted.field.editing");
|
||||
private static final Color EDITING_FOREGROUND_COLOR =
|
||||
new GColor("color.fg.version.tracking.filter.formatted.field.editing");
|
||||
new GColor("color.fg.formatted.field.editing");
|
||||
|
||||
private Set<FilterStatusListener> listeners = new HashSet<>();
|
||||
public static enum Status {
|
||||
UNCHANGED, CHANGED, INVALID;
|
||||
}
|
||||
|
||||
private FilterEditingStatus currentStatus = NONE;
|
||||
private final Object defaultValue;
|
||||
private final String defaultText;
|
||||
private Set<TextEntryStatusListener> listeners = new HashSet<>();
|
||||
|
||||
private Status currentStatus = Status.UNCHANGED;
|
||||
private Object defaultValue;
|
||||
private String defaultText;
|
||||
private boolean isError;
|
||||
private boolean ignoreFocusEditChanges;
|
||||
|
||||
/** A flag to let us know when we can ignore focus updates */
|
||||
private boolean isProcessingFocusEvent;
|
||||
|
||||
public FilterFormattedTextField(AbstractFormatterFactory factory, Object defaultValue) {
|
||||
public GFormattedTextField(AbstractFormatterFactory factory, Object defaultValue) {
|
||||
super(factory);
|
||||
|
||||
setValue(defaultValue);
|
||||
this.defaultValue = defaultValue;
|
||||
this.defaultText = getText(); // get the formatted text
|
||||
this.currentStatus = NONE;
|
||||
|
||||
getDocument().addDocumentListener(new DocumentListener() {
|
||||
@Override
|
||||
@ -76,8 +82,18 @@ public class FilterFormattedTextField extends JFormattedTextField {
|
||||
}
|
||||
});
|
||||
|
||||
addPropertyChangeListener("value", evt -> editingFinished());
|
||||
setDefaultValue(defaultValue);
|
||||
|
||||
addPropertyChangeListener("value", evt -> editingFinished());
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish default value. Text field value should be set before invoking this method.
|
||||
* @param defaultValue default value
|
||||
*/
|
||||
public void setDefaultValue(Object defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
this.defaultText = getText(); // get the formatted text
|
||||
update();
|
||||
}
|
||||
|
||||
@ -100,22 +116,22 @@ public class FilterFormattedTextField extends JFormattedTextField {
|
||||
isProcessingFocusEvent = false;
|
||||
}
|
||||
|
||||
public FilterEditingStatus getFilterStatus() {
|
||||
public Status getTextEntryStatus() {
|
||||
return currentStatus;
|
||||
}
|
||||
|
||||
public void addFilterStatusListener(FilterStatusListener listener) {
|
||||
public void addTextEntryStatusListener(TextEntryStatusListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
private void filterStatusChanged(FilterEditingStatus status) {
|
||||
private void textEntryStatusChanged(Status status) {
|
||||
currentStatus = status;
|
||||
if (listeners == null) {
|
||||
return; // happens during construction
|
||||
}
|
||||
|
||||
for (FilterStatusListener listener : listeners) {
|
||||
listener.filterStatusChanged(status);
|
||||
for (TextEntryStatusListener listener : listeners) {
|
||||
listener.statusChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,24 +211,24 @@ public class FilterFormattedTextField extends JFormattedTextField {
|
||||
setBackground(Colors.BACKGROUND);
|
||||
}
|
||||
|
||||
filterStatusChanged(currentStatus);
|
||||
textEntryStatusChanged(currentStatus);
|
||||
}
|
||||
|
||||
private void updateStatus() {
|
||||
FilterEditingStatus oldStatus = currentStatus;
|
||||
Status oldStatus = currentStatus;
|
||||
if (isError) {
|
||||
currentStatus = FilterEditingStatus.ERROR;
|
||||
currentStatus = Status.INVALID;
|
||||
}
|
||||
|
||||
else if (hasNonDefaultValue()) {
|
||||
currentStatus = APPLIED;
|
||||
currentStatus = Status.CHANGED;
|
||||
}
|
||||
else {
|
||||
currentStatus = NONE;
|
||||
currentStatus = Status.UNCHANGED;
|
||||
}
|
||||
|
||||
if (oldStatus != currentStatus) {
|
||||
filterStatusChanged(currentStatus);
|
||||
textEntryStatusChanged(currentStatus);
|
||||
}
|
||||
}
|
||||
|
@ -4,28 +4,18 @@
|
||||
* 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;
|
||||
package docking.widgets.textfield;
|
||||
|
||||
public interface EditorAction extends CompositeEditorModelListener {
|
||||
|
||||
static final String BASIC_ACTION_GROUP = "1_BASIC_EDITOR_ACTION";
|
||||
static final String DATA_ACTION_GROUP = "2_DATA_EDITOR_ACTION";
|
||||
static final String COMPONENT_ACTION_GROUP = "3_COMPONENT_EDITOR_ACTION";
|
||||
static final String BITFIELD_ACTION_GROUP = "4_COMPONENT_EDITOR_ACTION";
|
||||
|
||||
/**
|
||||
* Method to set the action's enablement based on the associated editor
|
||||
* model's current state.
|
||||
*/
|
||||
public void adjustEnablement();
|
||||
public interface TextEntryStatusListener {
|
||||
|
||||
public void statusChanged(GFormattedTextField textField);
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
package ghidra.program.database.data;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
import db.DBRecord;
|
||||
import ghidra.docking.settings.Settings;
|
||||
@ -212,6 +213,9 @@ abstract class CompositeDB extends DataTypeDB implements CompositeInternal {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
if (Objects.equals(desc, record.getString(CompositeDBAdapter.COMPOSITE_COMMENT_COL))) {
|
||||
return;
|
||||
}
|
||||
record.setString(CompositeDBAdapter.COMPOSITE_COMMENT_COL, desc);
|
||||
compositeAdapter.updateRecord(record, true);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
@ -391,13 +395,17 @@ abstract class CompositeDB extends DataTypeDB implements CompositeInternal {
|
||||
return record.getLongValue(CompositeDBAdapter.COMPOSITE_LAST_CHANGE_TIME_COL);
|
||||
}
|
||||
|
||||
void doSetLastChangeTime(long lastChangeTime) throws IOException {
|
||||
record.setLongValue(CompositeDBAdapter.COMPOSITE_LAST_CHANGE_TIME_COL, lastChangeTime);
|
||||
compositeAdapter.updateRecord(record, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastChangeTime(long lastChangeTime) {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
record.setLongValue(CompositeDBAdapter.COMPOSITE_LAST_CHANGE_TIME_COL, lastChangeTime);
|
||||
compositeAdapter.updateRecord(record, false);
|
||||
doSetLastChangeTime(lastChangeTime);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
@ -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.
|
||||
@ -138,7 +138,11 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
|
||||
if (id == -1) {
|
||||
return DataType.DEFAULT;
|
||||
}
|
||||
return dataMgr.getDataType(id);
|
||||
DataType dt = dataMgr.getDataType(id);
|
||||
if (dt == null) {
|
||||
return BadDataType.dataType;
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -191,6 +195,7 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
|
||||
|
||||
@Override
|
||||
public Settings getDefaultSettings() {
|
||||
|
||||
if (!hasSettings()) {
|
||||
return SettingsImpl.NO_SETTINGS;
|
||||
}
|
||||
|
@ -1693,8 +1693,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||
// (preference is given to similar kind of datatype when checking existing conflict types)
|
||||
DataType existingDataType = findDataTypeSameLocation(dataType);
|
||||
if (existingDataType == null) {
|
||||
return createDataType(dataType, getUnusedConflictName(dataType), sourceArchive,
|
||||
currentHandler);
|
||||
// create non-existing datatype - keep original name unless it is already used
|
||||
String name = dataType.getName();
|
||||
if (getDataType(dataType.getCategoryPath(), name) != null) {
|
||||
name = getUnusedConflictName(dataType);
|
||||
}
|
||||
return createDataType(dataType, name, sourceArchive, currentHandler);
|
||||
}
|
||||
|
||||
// So we have a dataType with the same path and name, but not equivalent, so use
|
||||
@ -2310,7 +2314,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||
if (id <= 0) { // removal of certain special types not permitted
|
||||
return false;
|
||||
}
|
||||
idsToDelete.add(Long.valueOf(id));
|
||||
idsToDelete.add(id);
|
||||
removeQueuedDataTypes();
|
||||
return true;
|
||||
}
|
||||
@ -3130,8 +3134,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||
|
||||
structDB.doReplaceWith(struct, false);
|
||||
|
||||
// doReplaceWith may have updated the last change time so set it back to what we want.
|
||||
structDB.setLastChangeTime(struct.getLastChangeTime());
|
||||
// doReplaceWith may have updated the last change time so set it back to what we want
|
||||
// without triggering change notification
|
||||
structDB.doSetLastChangeTime(struct.getLastChangeTime());
|
||||
|
||||
return structDB;
|
||||
}
|
||||
@ -3198,8 +3203,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||
|
||||
unionDB.doReplaceWith(union, false);
|
||||
|
||||
// doReplaceWith updated the last change time so set it back to what we want.
|
||||
unionDB.setLastChangeTime(union.getLastChangeTime());
|
||||
// doReplaceWith may have updated the last change time so set it back to what we want
|
||||
// without triggering change notification
|
||||
unionDB.doSetLastChangeTime(union.getLastChangeTime());
|
||||
|
||||
return unionDB;
|
||||
}
|
||||
@ -3717,7 +3723,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||
}
|
||||
}
|
||||
|
||||
void removeParentChildRecord(long parentID, long childID) {
|
||||
protected void removeParentChildRecord(long parentID, long childID) {
|
||||
|
||||
if (isBulkRemoving) {
|
||||
// we are in the process of bulk removing the given child; no need to call
|
||||
@ -3733,6 +3739,26 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||
}
|
||||
}
|
||||
|
||||
protected Set<Long> getChildIds(long parentID) {
|
||||
try {
|
||||
return parentChildAdapter.getChildIds(parentID);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
}
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
protected boolean hasParent(long childID) {
|
||||
try {
|
||||
return parentChildAdapter.hasParent(childID);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
List<DataType> getParentDataTypes(long dataTypeId) {
|
||||
lock.acquire();
|
||||
try {
|
||||
|
@ -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.
|
||||
@ -80,6 +80,16 @@ abstract class ParentChildAdapter {
|
||||
|
||||
abstract void removeRecord(long parentID, long childID) throws IOException;
|
||||
|
||||
/**
|
||||
* Get the unique set of child IDs associated with the specified parent ID.
|
||||
* Since a parent may have duplicate parent-child records, this method
|
||||
* avoids returning the same child more than once.
|
||||
* @param parentID parent datatype ID
|
||||
* @return set of child datatype IDs
|
||||
* @throws IOException if a DB IO error occurs
|
||||
*/
|
||||
abstract Set<Long> getChildIds(long parentID) throws IOException;
|
||||
|
||||
/**
|
||||
* Get the unique set of parent ID associated with the specified childID.
|
||||
* Since composite parents may have duplicate parent-child records, this method
|
||||
@ -90,6 +100,14 @@ abstract class ParentChildAdapter {
|
||||
*/
|
||||
abstract Set<Long> getParentIds(long childID) throws IOException;
|
||||
|
||||
/**
|
||||
* Determine if there is one or more parents associated with the specified childID.
|
||||
* @param childID child datatype ID
|
||||
* @return true if a parent was identified, else false
|
||||
* @throws IOException if a DB IO error occurs
|
||||
*/
|
||||
abstract boolean hasParent(long childID) throws IOException;
|
||||
|
||||
abstract void removeAllRecordsForParent(long parentID) throws IOException;
|
||||
|
||||
abstract void removeAllRecordsForChild(long childID) throws IOException;
|
||||
|
@ -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.
|
||||
@ -43,11 +43,21 @@ class ParentChildDBAdapterNoTable extends ParentChildAdapter {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<Long> getChildIds(long parentID) throws IOException {
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<Long> getParentIds(long childID) throws IOException {
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean hasParent(long childID) throws IOException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean needsInitializing() {
|
||||
return false;
|
||||
|
@ -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.
|
||||
@ -88,17 +88,33 @@ class ParentChildDBAdapterV0 extends ParentChildAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<Long> getChildIds(long parentID) throws IOException {
|
||||
Field[] ids = table.findRecords(new LongField(parentID), PARENT_COL);
|
||||
Set<Long> childIds = new HashSet<>(ids.length);
|
||||
for (Field id : ids) {
|
||||
DBRecord rec = table.getRecord(id);
|
||||
childIds.add(rec.getLongValue(CHILD_COL));
|
||||
}
|
||||
return childIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<Long> getParentIds(long childID) throws IOException {
|
||||
Field[] ids = table.findRecords(new LongField(childID), CHILD_COL);
|
||||
Set<Long> parentIds = new HashSet<>(ids.length);
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
DBRecord rec = table.getRecord(ids[i]);
|
||||
for (Field id : ids) {
|
||||
DBRecord rec = table.getRecord(id);
|
||||
parentIds.add(rec.getLongValue(PARENT_COL));
|
||||
}
|
||||
return parentIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean hasParent(long childID) throws IOException {
|
||||
return table.hasRecord(new LongField(childID), CHILD_COL);
|
||||
}
|
||||
|
||||
public void setNeedsInitializing() {
|
||||
needsInitializing = true;
|
||||
}
|
||||
|
@ -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.
|
||||
@ -111,9 +111,6 @@ abstract class PointerDBAdapter implements RecordTranslator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
abstract void deleteTable(DBHandle handle) throws IOException;
|
||||
|
||||
/**
|
||||
|
@ -2301,7 +2301,7 @@ class StructureDB extends CompositeDB implements StructureInternal {
|
||||
checkAncestry(replacementDt);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// TODO: should we flag bad replacement
|
||||
// Handle bad replacement with use of undefined component
|
||||
replacementDt = isPackingEnabled() ? Undefined1DataType.dataType : DataType.DEFAULT;
|
||||
}
|
||||
|
||||
|
@ -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,6 +15,8 @@
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
@ -36,7 +38,7 @@ public final class DataUtilities {
|
||||
* @return true if name is valid, else false
|
||||
*/
|
||||
public static boolean isValidDataTypeName(String name) {
|
||||
if (name == null || name.length() == 0) {
|
||||
if (StringUtils.isBlank(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -872,6 +872,14 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos
|
||||
return transaction.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of active transactions
|
||||
* @return number of active transactions
|
||||
*/
|
||||
protected int getTransactionCount() {
|
||||
return transactionCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endTransaction(int transactionID, boolean commit) {
|
||||
boolean restored = false;
|
||||
@ -953,6 +961,8 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos
|
||||
protected synchronized void clearUndo() {
|
||||
undoList.clear();
|
||||
redoList.clear();
|
||||
|
||||
// Flatten all checkpoints then restore undo stack size
|
||||
dbHandle.setMaxUndos(0);
|
||||
dbHandle.setMaxUndos(NUM_UNDOS);
|
||||
}
|
||||
|
@ -1640,13 +1640,13 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
||||
* @param dataType the data type of the new component
|
||||
* @param newOffset offset of replacement component which must fall within origComponents bounds
|
||||
* @param length the length of the new component
|
||||
* @param name the field name of the new component
|
||||
* @param fieldName the field name of the new component
|
||||
* @param comment the comment for the new component
|
||||
* @return the new component or null if only a clear operation was performed.
|
||||
* @throws IllegalArgumentException if unable to identify/make sufficient space
|
||||
*/
|
||||
private DataTypeComponent replaceComponents(LinkedList<DataTypeComponentImpl> origComponents,
|
||||
DataType dataType, int newOffset, int length, String name, String comment)
|
||||
DataType dataType, int newOffset, int length, String fieldName, String comment)
|
||||
throws IllegalArgumentException {
|
||||
|
||||
boolean clearOnly = false;
|
||||
@ -1721,8 +1721,8 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
||||
DataTypeComponentImpl newDtc = null;
|
||||
if (!clearOnly) {
|
||||
// insert new component
|
||||
newDtc = new DataTypeComponentImpl(dataType, this, length, newOrdinal, newOffset, name,
|
||||
comment);
|
||||
newDtc = new DataTypeComponentImpl(dataType, this, length, newOrdinal, newOffset,
|
||||
fieldName, comment);
|
||||
components.add(index, newDtc);
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
@ -32,7 +32,8 @@ import ghidra.util.task.TaskMonitorAdapter;
|
||||
public class StructureDBTest extends AbstractGenericTest {
|
||||
|
||||
private StructureDB struct;
|
||||
private DataTypeManagerDB dataMgr;
|
||||
private StandAloneDataTypeManager dataMgr;
|
||||
private int txId;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@ -42,7 +43,7 @@ public class StructureDBTest extends AbstractGenericTest {
|
||||
// default data organization is little-endian
|
||||
// default BitFieldPackingImpl uses gcc conventions with type alignment enabled
|
||||
|
||||
dataMgr.startTransaction("Test");
|
||||
txId = dataMgr.startTransaction("Test");
|
||||
|
||||
struct = createStructure("Test", 0);
|
||||
struct.add(new ByteDataType(), "field1", "Comment1");
|
||||
@ -52,6 +53,14 @@ public class StructureDBTest extends AbstractGenericTest {
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (dataMgr != null) {
|
||||
dataMgr.endTransaction(txId, true);
|
||||
dataMgr.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void transitionToBigEndian() {
|
||||
|
||||
Structure structClone = struct.clone(null);
|
||||
@ -1442,7 +1451,45 @@ public class StructureDBTest extends AbstractGenericTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteMany() throws InvalidDataTypeException {
|
||||
public void testDeleteMany() {
|
||||
|
||||
struct.growStructure(20);
|
||||
struct.insertAtOffset(12, WordDataType.dataType, -1, "A", null);
|
||||
struct.insertAtOffset(16, WordDataType.dataType, -1, "B", null);
|
||||
|
||||
assertEquals(32, struct.getLength());
|
||||
assertEquals(26, struct.getNumComponents());
|
||||
assertEquals(6, struct.getNumDefinedComponents());
|
||||
|
||||
struct.delete(Sets.newHashSet(1, 4, 5));
|
||||
|
||||
assertEquals(28, struct.getLength());
|
||||
assertEquals(23, struct.getNumComponents());
|
||||
assertEquals(5, struct.getNumDefinedComponents());
|
||||
|
||||
DataTypeComponent[] comps = struct.getDefinedComponents();
|
||||
assertEquals(WordDataType.class, comps[3].getDataType().getClass());
|
||||
assertEquals(5, comps[3].getOrdinal());
|
||||
assertEquals(8, comps[3].getOffset());
|
||||
|
||||
// Verify that records were properly updated by comitting and performing an undo/redo
|
||||
dataMgr.endTransaction(txId, true);
|
||||
dataMgr.undo();
|
||||
dataMgr.redo();
|
||||
txId = dataMgr.startTransaction("Continue Test");
|
||||
|
||||
assertEquals(28, struct.getLength());
|
||||
assertEquals(23, struct.getNumComponents());
|
||||
assertEquals(5, struct.getNumDefinedComponents());
|
||||
|
||||
comps = struct.getDefinedComponents();
|
||||
assertEquals(WordDataType.class, comps[3].getDataType().getClass());
|
||||
assertEquals(5, comps[3].getOrdinal());
|
||||
assertEquals(8, comps[3].getOffset());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteManyBF() throws InvalidDataTypeException {
|
||||
|
||||
struct.insertBitFieldAt(2, 4, 0, IntegerDataType.dataType, 3, "bf1", "bf1Comment");
|
||||
struct.insertBitFieldAt(2, 4, 3, IntegerDataType.dataType, 3, "bf2", "bf2Comment");
|
||||
|
@ -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.
|
||||
@ -30,8 +30,9 @@ import ghidra.util.task.TaskMonitor;
|
||||
*/
|
||||
public class UnionDBTest extends AbstractGenericTest {
|
||||
|
||||
private DataTypeManager dataMgr;
|
||||
private StandAloneDataTypeManager dataMgr;
|
||||
private UnionDB union;
|
||||
private int txId;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@ -41,7 +42,7 @@ public class UnionDBTest extends AbstractGenericTest {
|
||||
// default data organization is little-endian
|
||||
// default BitFieldPackingImpl uses gcc conventions
|
||||
|
||||
dataMgr.startTransaction("Test");
|
||||
txId = dataMgr.startTransaction("Test");
|
||||
|
||||
union = createUnion("TestUnion");
|
||||
union.add(new ByteDataType(), "field1", "Comment1");
|
||||
@ -50,6 +51,14 @@ public class UnionDBTest extends AbstractGenericTest {
|
||||
union.add(new ByteDataType(), "field4", "Comment4");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (dataMgr != null) {
|
||||
dataMgr.endTransaction(txId, true);
|
||||
dataMgr.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void transitionToBigEndian() {
|
||||
|
||||
Union unionClone = union.clone(null);
|
||||
@ -380,6 +389,7 @@ public class UnionDBTest extends AbstractGenericTest {
|
||||
union.delete(Sets.newHashSet(2, 4));
|
||||
|
||||
assertEquals(2, union.getLength());
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||
"pack(disabled)\n" +
|
||||
@ -390,6 +400,33 @@ public class UnionDBTest extends AbstractGenericTest {
|
||||
"}\n" +
|
||||
"Length: 2 Alignment: 1", union);
|
||||
//@formatter:on
|
||||
|
||||
DataTypeComponent[] comps = union.getDefinedComponents();
|
||||
assertEquals(ByteDataType.class, comps[2].getDataType().getClass());
|
||||
assertEquals(2, comps[2].getOrdinal());
|
||||
|
||||
// Verify that records were properly updated by comitting and performing an undo/redo
|
||||
dataMgr.endTransaction(txId, true);
|
||||
dataMgr.undo();
|
||||
dataMgr.redo();
|
||||
txId = dataMgr.startTransaction("Continue Test");
|
||||
|
||||
assertEquals(2, union.getLength());
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Union TestUnion {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 0 word 2 \"Comment2\"\n" +
|
||||
" 0 byte 1 field4 \"Comment4\"\n" +
|
||||
"}\n" +
|
||||
"Length: 2 Alignment: 1", union);
|
||||
//@formatter:on
|
||||
|
||||
comps = union.getDefinedComponents();
|
||||
assertEquals(ByteDataType.class, comps[2].getDataType().getClass());
|
||||
assertEquals(2, comps[2].getOrdinal());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -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,8 +26,8 @@ import javax.swing.JFormattedTextField;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import docking.widgets.textfield.HexIntegerFormatter;
|
||||
import ghidra.feature.vt.gui.filters.IntegerFormatterFactory;
|
||||
import docking.widgets.numberformat.HexIntegerFormatter;
|
||||
import docking.widgets.numberformat.IntegerFormatterFactory;
|
||||
|
||||
public class HexIntegerFormatterTest {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user