mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
GP-5326 adding "Add Date" and "Add Address" to edit data field dialog
This commit is contained in:
parent
69a66e0eec
commit
b7a23cacd4
7 changed files with 222 additions and 13 deletions
|
@ -1376,6 +1376,10 @@
|
|||
<LI><B>Comment</B>: The comment for the field can be entered or changed here.</LI>
|
||||
<LI><B>DataType</B>: The data can be changed here. The text field is read only so you must
|
||||
press the ... button to bring up the datatype chooser to change the datatype.</LI>
|
||||
<LI><B>Add Current Address</B>: If selected, the current address where this field is edited
|
||||
will be added to the datatype's field comment if not already there.</LI>
|
||||
<LI><B>Add Today's Date</B>: If selected, the current date will be added to the datatype's
|
||||
field comment if not already there.</LI>
|
||||
<P><IMG src="help/shared/note.png"> If a default field (a field with an undefined
|
||||
datatype (??)) is named or given a comment, the datatype will be set to <B>undefined1</B> if
|
||||
no specific datatype is set. This is because undefined fields are not stored and therefore
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 8.2 KiB |
|
@ -109,6 +109,8 @@ public class DataPlugin extends Plugin implements DataService {
|
|||
private DataTypeManagerChangeListenerAdapter adapter;
|
||||
|
||||
private SwingUpdateManager favoritesUpdateManager;
|
||||
private boolean addAddress;
|
||||
private boolean addDate;
|
||||
|
||||
public DataPlugin(PluginTool tool) {
|
||||
super(tool);
|
||||
|
@ -855,8 +857,10 @@ public class DataPlugin extends Plugin implements DataService {
|
|||
DataTypeComponent component = DataTypeUtils.getDataTypeComponent(program, address, path);
|
||||
if (component != null) {
|
||||
EditDataFieldDialog dialog =
|
||||
new EditDataFieldDialog(tool, dtmService, location, component);
|
||||
new EditDataFieldDialog(tool, dtmService, location, component, addAddress, addDate);
|
||||
tool.showDialog(dialog);
|
||||
addAddress = dialog.isAddAddressSelected();
|
||||
addDate = dialog.isAddDateSelected();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
package ghidra.app.plugin.core.data;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
|
@ -32,8 +35,7 @@ import ghidra.program.model.address.Address;
|
|||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.MessageType;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.layout.PairLayout;
|
||||
|
||||
|
@ -51,6 +53,8 @@ public class EditDataFieldDialog extends DialogComponentProvider {
|
|||
private DataType newDataType;
|
||||
private ProgramLocation programLocation;
|
||||
private DataTypeManagerService dtmService;
|
||||
private JCheckBox addressCheckBox;
|
||||
private JCheckBox dateCheckBox;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -58,9 +62,12 @@ public class EditDataFieldDialog extends DialogComponentProvider {
|
|||
* @param dtmService the DataTypeManagerService used for choosing datatypes
|
||||
* @param location the location of the field being edited
|
||||
* @param dataTypeComponent the component of the field being edited
|
||||
* @param addDate selects the addDate checkbox
|
||||
* @param addAddress selects the addDate checkbox
|
||||
*/
|
||||
public EditDataFieldDialog(PluginTool tool, DataTypeManagerService dtmService,
|
||||
ProgramLocation location, DataTypeComponent dataTypeComponent) {
|
||||
ProgramLocation location, DataTypeComponent dataTypeComponent, boolean addAddress,
|
||||
boolean addDate) {
|
||||
super("Edit Field Dialog", true, true, true, false);
|
||||
this.tool = tool;
|
||||
this.dtmService = dtmService;
|
||||
|
@ -69,7 +76,7 @@ public class EditDataFieldDialog extends DialogComponentProvider {
|
|||
setTitle(generateTitle());
|
||||
|
||||
addWorkPanel(buildMainPanel());
|
||||
initializeFields();
|
||||
initializeFields(addAddress, addDate);
|
||||
setFocusComponent(nameField);
|
||||
setHelpLocation(new HelpLocation("DataPlugin", "Edit_Field_Dialog"));
|
||||
|
||||
|
@ -135,14 +142,43 @@ public class EditDataFieldDialog extends DialogComponentProvider {
|
|||
updateDataTypeTextField();
|
||||
}
|
||||
|
||||
private void initializeFields() {
|
||||
/**
|
||||
* Returns true if the Add Address checkbox is selected.
|
||||
* @return true if the Add Address checkbox is selected
|
||||
*/
|
||||
public boolean isAddAddressSelected() {
|
||||
return addressCheckBox.isSelected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the Add Date checkbox is selected.
|
||||
* @return true if the Add Address checkbox is selected
|
||||
*/
|
||||
public boolean isAddDateSelected() {
|
||||
return dateCheckBox.isSelected();
|
||||
}
|
||||
|
||||
private void initializeFields(boolean addAddress, boolean addDate) {
|
||||
String name = component.getFieldName();
|
||||
if (StringUtils.isBlank(name)) {
|
||||
name = "";
|
||||
}
|
||||
nameField.setText(name);
|
||||
commentField.setText(component.getComment());
|
||||
String comment = component.getComment();
|
||||
if (comment == null) {
|
||||
comment = "";
|
||||
}
|
||||
commentField.setText(comment);
|
||||
dataTypeTextField.setText(component.getDataType().getDisplayName());
|
||||
|
||||
if (addAddress) {
|
||||
addressCheckBox.setSelected(true);
|
||||
addTextToComment(getCurrentAddressString());
|
||||
}
|
||||
if (addDate) {
|
||||
dateCheckBox.setSelected(true);
|
||||
addTextToComment(getTodaysDate());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -202,6 +238,27 @@ public class EditDataFieldDialog extends DialogComponentProvider {
|
|||
}
|
||||
|
||||
private JPanel buildMainPanel() {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.add(buildNameValuePanel(), BorderLayout.NORTH);
|
||||
panel.add(buildCheckboxPanel(), BorderLayout.SOUTH);
|
||||
return panel;
|
||||
}
|
||||
|
||||
private JPanel buildCheckboxPanel() {
|
||||
JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 30, 0));
|
||||
|
||||
addressCheckBox = new JCheckBox("Add Current Address");
|
||||
addressCheckBox.addActionListener(this::addressCheckBoxChanged);
|
||||
|
||||
dateCheckBox = new JCheckBox("Add Today's Date");
|
||||
dateCheckBox.addActionListener(this::dateCheckBoxChanged);
|
||||
|
||||
panel.add(addressCheckBox);
|
||||
panel.add(dateCheckBox);
|
||||
return panel;
|
||||
}
|
||||
|
||||
private JPanel buildNameValuePanel() {
|
||||
JPanel panel = new JPanel(new PairLayout(10, 10));
|
||||
panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
|
||||
|
||||
|
@ -214,10 +271,10 @@ public class EditDataFieldDialog extends DialogComponentProvider {
|
|||
|
||||
panel.add(new JLabel("Field Name:", SwingConstants.LEFT));
|
||||
panel.add(nameField);
|
||||
panel.add(new JLabel("Comment:", SwingConstants.LEFT));
|
||||
panel.add(commentField);
|
||||
panel.add(new JLabel("Datatype:", SwingConstants.LEFT));
|
||||
panel.add(buildDataTypeChooserPanel());
|
||||
panel.add(new JLabel("Comment:", SwingConstants.LEFT));
|
||||
panel.add(commentField);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
@ -256,6 +313,58 @@ public class EditDataFieldDialog extends DialogComponentProvider {
|
|||
return "Edit " + compositeName + ", Field " + component.getOrdinal();
|
||||
}
|
||||
|
||||
private void dateCheckBoxChanged(ActionEvent e) {
|
||||
String today = getTodaysDate();
|
||||
if (dateCheckBox.isSelected()) {
|
||||
addTextToComment(today);
|
||||
}
|
||||
else {
|
||||
removeTextFromComment(today);
|
||||
}
|
||||
}
|
||||
|
||||
private void addressCheckBoxChanged(ActionEvent e) {
|
||||
String address = getCurrentAddressString();
|
||||
if (addressCheckBox.isSelected()) {
|
||||
addTextToComment(address);
|
||||
}
|
||||
else {
|
||||
removeTextFromComment(address);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeTextFromComment(String text) {
|
||||
String comment = commentField.getText().trim();
|
||||
int index = comment.indexOf(text);
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove the given text and any spaces that follow it.
|
||||
comment = comment.replaceAll(text + "\\s*", "");
|
||||
commentField.setText(comment.trim());
|
||||
}
|
||||
|
||||
private String getTodaysDate() {
|
||||
return DateUtils.formatCompactDate(new Date());
|
||||
}
|
||||
|
||||
private String getCurrentAddressString() {
|
||||
return programLocation.getAddress().toString();
|
||||
}
|
||||
|
||||
private void addTextToComment(String text) {
|
||||
String comment = commentField.getText().trim();
|
||||
if (comment.contains(text)) {
|
||||
return;
|
||||
}
|
||||
if (!comment.isBlank()) {
|
||||
comment += " ";
|
||||
}
|
||||
comment += text;
|
||||
commentField.setText(comment.trim());
|
||||
}
|
||||
|
||||
public String getDataTypeText() {
|
||||
return dataTypeTextField.getText();
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ package ghidra.app.plugin.core.data;
|
|||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import docking.action.DockingActionIf;
|
||||
|
@ -27,6 +29,7 @@ import ghidra.program.model.data.*;
|
|||
import ghidra.program.model.listing.Data;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.test.*;
|
||||
import ghidra.util.DateUtils;
|
||||
|
||||
public class EditFieldDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
private TestEnv env;
|
||||
|
@ -162,6 +165,49 @@ public class EditFieldDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals("byte", structure.getComponent(1).getDataType().getDisplayName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddAddressCheckbox() {
|
||||
goTo(0x101);
|
||||
showFieldEditDialog();
|
||||
assertEquals("", getCommentText());
|
||||
pressButtonByText(dialog.getComponent(), "Add Current Address");
|
||||
assertEquals("00000101", getCommentText());
|
||||
|
||||
pressOk();
|
||||
waitForTasks();
|
||||
assertEquals("00000101", structure.getComponent(1).getComment());
|
||||
|
||||
showFieldEditDialog();
|
||||
assertEquals("00000101", getCommentText());
|
||||
pressButtonByText(dialog.getComponent(), "Add Current Address");
|
||||
assertEquals("", getCommentText());
|
||||
|
||||
pressOk();
|
||||
assertNull(structure.getComponent(1).getComment());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddDateCheckbox() {
|
||||
String today = DateUtils.formatCompactDate(new Date());
|
||||
goTo(0x101);
|
||||
showFieldEditDialog();
|
||||
assertEquals("", getCommentText());
|
||||
pressButtonByText(dialog.getComponent(), "Add Today's Date");
|
||||
assertEquals(today, getCommentText());
|
||||
|
||||
pressOk();
|
||||
waitForTasks();
|
||||
assertEquals(today, structure.getComponent(1).getComment());
|
||||
|
||||
showFieldEditDialog();
|
||||
assertEquals(today, getCommentText());
|
||||
pressButtonByText(dialog.getComponent(), "Add Today's Date");
|
||||
assertEquals("", getCommentText());
|
||||
|
||||
pressOk();
|
||||
assertNull(structure.getComponent(1).getComment());
|
||||
}
|
||||
|
||||
private boolean isDialogVisible() {
|
||||
return runSwing(() -> dialog.isVisible());
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ public class DateUtils {
|
|||
/** Example: Oct 31, 2019 03:24 PM */
|
||||
private static final String DATE_TIME_FORMAT_STRING = "MMM dd, yyyy hh:mm a";
|
||||
private static final String DATE_FORMAT_STRING = "MM/dd/yyyy";
|
||||
private static final String COMPACT_DATE_FORMAT_STRING = "MM/dd/yy";
|
||||
private static final String TIME_FORMAT_STRING = "h:mm";
|
||||
|
||||
private static final DateTimeFormatter DATE_TIME_FORMATTER =
|
||||
|
@ -39,6 +40,8 @@ public class DateUtils {
|
|||
DateTimeFormatter.ofPattern(DATE_FORMAT_STRING);
|
||||
private static final DateTimeFormatter TIME_FORMATTER =
|
||||
DateTimeFormatter.ofPattern(TIME_FORMAT_STRING);
|
||||
private static final DateTimeFormatter COMPACT_DATE_FORMATTER =
|
||||
DateTimeFormatter.ofPattern(COMPACT_DATE_FORMAT_STRING);
|
||||
|
||||
public static final long MS_PER_SEC = 1000;
|
||||
public static final long MS_PER_MIN = MS_PER_SEC * 60;
|
||||
|
@ -227,6 +230,16 @@ public class DateUtils {
|
|||
return DATE_FORMATTER.format(toLocalDate(date));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given date into a compact date string (mm/dd/yy).
|
||||
*
|
||||
* @param date the date to format
|
||||
* @return the date string
|
||||
*/
|
||||
public static String formatCompactDate(Date date) {
|
||||
return COMPACT_DATE_FORMATTER.format(toLocalDate(date));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given date into a string that contains the date and time. This is in
|
||||
* contrast to {@link #formatDate(Date)}, which only returns a date string.
|
||||
|
|
|
@ -15,11 +15,16 @@
|
|||
*/
|
||||
package help.screenshot;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.JRadioButton;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import docking.DialogComponentProvider;
|
||||
import docking.*;
|
||||
import docking.action.DockingActionIf;
|
||||
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
|
||||
import ghidra.util.table.GhidraTable;
|
||||
|
||||
public class DataPluginScreenShots extends GhidraScreenShotGenerator {
|
||||
|
@ -75,7 +80,10 @@ public class DataPluginScreenShots extends GhidraScreenShotGenerator {
|
|||
@Test
|
||||
public void testDefaultSettings() {
|
||||
positionListingTop(0x40d3a4);
|
||||
performAction("Default Data Settings", "DataPlugin", false);
|
||||
ComponentProvider componentProvider = getProvider(CodeViewerProvider.class);
|
||||
ActionContext actionContext = componentProvider.getActionContext(null);
|
||||
DockingActionIf action = getAction("Default Settings", actionContext);
|
||||
performAction(action, actionContext, false);
|
||||
captureDialog();
|
||||
}
|
||||
|
||||
|
@ -86,4 +94,29 @@ public class DataPluginScreenShots extends GhidraScreenShotGenerator {
|
|||
captureDialog();
|
||||
}
|
||||
|
||||
private DockingActionIf getAction(String name, ActionContext context) {
|
||||
Set<DockingActionIf> actions = getDataPluginActions(context);
|
||||
for (DockingActionIf element : actions) {
|
||||
String actionName = element.getName();
|
||||
int pos = actionName.indexOf(" (");
|
||||
if (pos > 0) {
|
||||
actionName = actionName.substring(0, pos);
|
||||
}
|
||||
if (actionName.equals(name)) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Set<DockingActionIf> getDataPluginActions(ActionContext context) {
|
||||
Set<DockingActionIf> actions = getActionsByOwner(tool, "DataPlugin");
|
||||
if (context == null) {
|
||||
return actions;
|
||||
}
|
||||
// assumes returned set may be modified
|
||||
return actions.stream()
|
||||
.filter(a -> a.isValidContext(context))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue