mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-18 09:28:28 +08:00
GP-4740 Added undo/redo support to composite editor. Switched actions to use isEnabledForContext. Transitioned VT FilterFormattedTestField to GFormattedTextField and use for editor text entry fields. Cleanup of old datatype tree actions no longer in use. Lots of changes to improve handling of data type dependency changes and restored original DTM.
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>
|
||||
|
||||
|
||||
+37
-22
@@ -492,16 +492,17 @@
|
||||
changes, a dialog will appear providing an opportunity to save the changes.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Save"></A>Saving Changes to a File Data Type Archive</H3>
|
||||
<H3><A name="Save"></A>Saving Changes to a Data Type Archive</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>Whenever a data type archive has been <A href="#open_for_editing">opened for
|
||||
editing</A> and has unsaved changes, the node will display its name with '*' attached.
|
||||
<P>Whenever a data type archive has been opened for
|
||||
editing and has unsaved changes, the node will display its name with '*' attached.
|
||||
For example the archive "MyArchive" will display as "MyArchive *". To save these changes,
|
||||
right-click on the unsaved archive and select the <I><B>Save Archive</B></I> action. The
|
||||
changes will be saved and the name will be updated to not show a '*'.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<!-- Unimplemented Action
|
||||
<H3><A name="Save_As"></A>Saving a File Data Type Archive to a New File<BR>
|
||||
</H3>
|
||||
|
||||
@@ -511,6 +512,37 @@
|
||||
and filename for the new archive that will be created. The tree will be updated to show
|
||||
the new name for the archive (the filename). The original archive file is unaffected.</P>
|
||||
</BLOCKQUOTE>
|
||||
-->
|
||||
|
||||
<H3><A name="Undo_Archive_Change"></A>Undo Unsaved Archive Change</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>The previous unsaved change made to an archive may be reverted by selecting the <B>Undo Change:...</B>
|
||||
popup menu action while that archive is selected in the data type tree.
|
||||
Each data type archive which is open for editing maintains a
|
||||
stack of unsaved changes. The next change which may be reverted is described by the archive's
|
||||
Undo Change popup menu item. If this action is used and a change is reverted it may be re-applied by using the
|
||||
<A href="#Redo_Archive_Change">Redo Change</A> action. When the data type archive is
|
||||
<A href="#Save">saved</A> or <A href="#Lock_Archive">closed for editing</A> the undo/redo stack is
|
||||
cleared.
|
||||
</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Redo_Archive_Change"></A>Redo Unsaved Archive Change</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>The previous <A href="#Undo_Archive_Change">reverted</A> unsaved archive change may be
|
||||
re-applied by selecting the <B>Redo Change:...</B> popup menu action while that archive is selected in
|
||||
the data type tree.
|
||||
The next reverted change which may be re-applied is described by the archive's
|
||||
Redo Change popup menu item. If this action is used and a change is re-applied it may again be reverted by using the
|
||||
<A href="#Undo_Archive_Change">Undo Change</A> action. When the data type archive is
|
||||
<A href="#Save">saved</A> or <A href="#Lock_Archive">closed for editing</A> the undo/redo stack is
|
||||
cleared.
|
||||
</P>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Delete_Archive"></A>Deleting a Data Type Archive</H3>
|
||||
|
||||
@@ -524,24 +556,14 @@
|
||||
|
||||
<H3><A name="Remove_Invalid_Archive"></A>Removing an Invalid Data Type Archive</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P>When an archive file fails to open (when Ghidra can't find the file in the archive path
|
||||
or encounters a permission problem) it will be displayed with the <IMG alt="" src=
|
||||
"images/closedFolderInvalid.png"> icon. If you wish to permanently remove the file path
|
||||
from the tool configuration and the current program options, you may right-click on it and
|
||||
select the <I><B>Remove Invalid
|
||||
Archive</B></I> action.</P>
|
||||
select the <I><B>Remove Invalid Archive</B></I> action.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Pack_All_Data_Types"></A>Pack All Data Types In a Program or Archive</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>Right-click on the program or data type archive where structures and unions are to be packed,
|
||||
and select the <I><B>Pack All...</B></I> action. A confirmation dialog will appear to
|
||||
make sure you want to pack all composites in the program or data type
|
||||
archive. If you continue, all non-packed composites will have default packing enabled.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="synchronizing"></A> <A name="Update"></A> Updating an Archive From a Source
|
||||
Archive</H3>
|
||||
|
||||
@@ -1000,14 +1022,7 @@
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
</BLOCKQUOTE>
|
||||
<!-- disabled feature
|
||||
<H3><A name="Align_Data_Type"></A>Aligning a Data Type</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>Right-click on the structure or union to be packed. Select the <I><B>Pack</B></I>
|
||||
action. If the data type is non-packed it will be changed to be default packed.</P>
|
||||
</BLOCKQUOTE>
|
||||
-->
|
||||
<H3><A name="Commit_To_Archive"></A>Committing Changes To Source Archive</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
|
||||
+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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user