mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-23 10:26:02 +08:00
Merge remote-tracking branch 'origin/GP-4740_ghidra1_CompositeEditorUndoRedo--SQUASHED'
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
+5
-3
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-11
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+8
-5
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-6
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-2
@@ -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;
|
||||
}
|
||||
|
||||
+4
-10
@@ -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();
|
||||
}
|
||||
|
||||
+8
-5
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+415
-281
File diff suppressed because it is too large
Load Diff
+391
-329
File diff suppressed because it is too large
Load Diff
+562
-294
File diff suppressed because it is too large
Load Diff
+15
-23
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+22
-66
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-5
@@ -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);
|
||||
|
||||
+20
-11
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+320
-38
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+107
-249
File diff suppressed because it is too large
Load Diff
+7
-5
@@ -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() {
|
||||
|
||||
+7
-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.
|
||||
@@ -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
|
||||
|
||||
-13
@@ -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.
|
||||
|
||||
+8
-5
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-7
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-7
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-6
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-5
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+19
-22
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-366
@@ -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();
|
||||
|
||||
}
|
||||
+6
-10
@@ -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
|
||||
|
||||
+13
-9
@@ -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) {
|
||||
|
||||
+8
-6
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+145
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+10
-5
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-5
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-5
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-13
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+62
@@ -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;
|
||||
}
|
||||
}
|
||||
+7
-5
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+11
-6
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+294
-263
File diff suppressed because it is too large
Load Diff
+7
-7
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+63
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+67
-59
@@ -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;
|
||||
|
||||
-4
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -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),
|
||||
|
||||
+8
-6
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+2
-8
@@ -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
|
||||
|
||||
+3
-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.
|
||||
@@ -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) {
|
||||
|
||||
-101
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
-136
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-125
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user