From 90c831483748651896d58fcab0c2f286d95143a6 Mon Sep 17 00:00:00 2001
From: dragonmacher <48328597+dragonmacher@users.noreply.github.com>
Date: Tue, 27 Jul 2021 18:43:28 -0400
Subject: [PATCH] GP-1162 - Fixed 'Enter' key in Set Equates dialog to choose
the selected table row; Updated the Function Signature Editor dialog to allow
the 'Cancel' key to close the dialog when the focus is in the top text
editor.
Closes #3235
---
.../function/editor/FunctionEditorDialog.java | 44 ++++++++++++++++---
.../function/editor/FunctionEditorModel.java | 36 +++++----------
.../ghidra/app/util/bean/SetEquateDialog.java | 31 +++++++++----
3 files changed, 69 insertions(+), 42 deletions(-)
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialog.java
index a8d85b1a9e..79e622a132 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorDialog.java
@@ -27,6 +27,8 @@ import javax.swing.border.CompoundBorder;
import javax.swing.event.*;
import javax.swing.table.TableCellEditor;
+import org.apache.commons.lang3.StringUtils;
+
import docking.*;
import docking.widgets.OptionDialog;
import docking.widgets.checkbox.GCheckBox;
@@ -248,7 +250,22 @@ public class FunctionEditorDialog extends DialogComponentProvider implements Mod
signatureTextField.setFont(font.deriveFont(18.0f));
panel.add(signatureTextField);
- signatureTextField.setEscapeListener(e -> model.resetSignatureTextField());
+ signatureTextField.setEscapeListener(e -> {
+
+ if (!model.hasChanges()) {
+ // no changes; user wish to close the dialog
+ cancelCallback();
+ return;
+ }
+
+ // editor has changes, see if they wish to cancel editing
+ if (!promptToAbortChanges()) {
+ return; // keep editing
+ }
+
+ // abort changes confirmed
+ model.resetSignatureTextField();
+ });
signatureTextField.setActionListener(e -> {
try {
@@ -297,18 +314,31 @@ public class FunctionEditorDialog extends DialogComponentProvider implements Mod
message = details;
}
- message = HTMLUtilities.wrapAsHTML(
- message + "
Do you want to continue editing or " +
- "abort your changes?");
- int result = OptionDialog.showOptionNoCancelDialog(rootPanel, "Invalid Function Signature",
- message, "Continue Editing", "Abort Changes", OptionDialog.ERROR_MESSAGE);
- if (result == OptionDialog.OPTION_TWO) {
+ if (doPromptToAbortChanges(message)) {
model.resetSignatureTextField();
return true;
}
return false;
}
+ private boolean promptToAbortChanges() {
+ return doPromptToAbortChanges("");
+ }
+
+ private boolean doPromptToAbortChanges(String message) {
+
+ if (!StringUtils.isBlank(message)) {
+ message += "
";
+ }
+
+ message = HTMLUtilities.wrapAsHTML(
+ message + "Do you want to continue editing or " +
+ "abort your changes?");
+ int result = OptionDialog.showOptionNoCancelDialog(rootPanel, "Invalid Function Signature",
+ message, "Continue Editing", "Abort Changes", OptionDialog.ERROR_MESSAGE);
+ return result == OptionDialog.OPTION_TWO; // Option 2 is to abort
+ }
+
private Component buildAttributePanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(0, 5, 15, 15));
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorModel.java
index dc46d07bd9..4bb56cd1cd 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorModel.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorModel.java
@@ -17,8 +17,6 @@ package ghidra.app.plugin.core.function.editor;
import java.util.*;
-import javax.swing.SwingUtilities;
-
import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.cparser.C.ParseException;
import ghidra.app.util.parser.FunctionSignatureParser;
@@ -30,8 +28,7 @@ import ghidra.program.model.listing.Function.FunctionUpdateType;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.SymbolUtilities;
-import ghidra.util.Msg;
-import ghidra.util.SystemUtilities;
+import ghidra.util.*;
import ghidra.util.exception.*;
public class FunctionEditorModel {
@@ -85,14 +82,6 @@ public class FunctionEditorModel {
this.listener = listener;
}
-// public FunctionEditorModel(DataTypeManagerService service, Function function,
-// ModelChangeListener listener, FunctionDefinitionDataType functionDef,
-// String callingConv) {
-// this(service, function, listener);
-// callingConventionName = callingConv;
-// setFunctionData(functionDef);
-// }
-
// Returns the current calling convention or the default calling convention if current unknown
private PrototypeModel getEffectiveCallingConvention() {
PrototypeModel effectiveCallingConvention =
@@ -193,19 +182,10 @@ public class FunctionEditorModel {
this.modelChanged |= functionDataChanged;
validate();
if (listener != null) {
- SwingUtilities.invokeLater(() -> listener.dataChanged());
+ Swing.runLater(() -> listener.dataChanged());
}
}
-// private void notifyParsingModeChanged() {
-// SwingUtilities.invokeLater(new Runnable() {
-// @Override
-// public void run() {
-// listener.parsingModeChanged();
-// }
-// });
-// }
-
private void validate() {
statusText = "";
if (signatureTransformed) {
@@ -237,7 +217,7 @@ public class FunctionEditorModel {
returnType = ((TypeDef) returnType).getBaseDataType();
}
if (storageSize > 0 && (returnType instanceof AbstractFloatDataType)) {
- return true; // dont constrain float storage size
+ return true; // don't constrain float storage size
}
int returnDataTypeSize = returnType.getLength();
@@ -406,7 +386,7 @@ public class FunctionEditorModel {
}
public String getFunctionSignatureTextFromModel() {
- StringBuffer buf = new StringBuffer();
+ StringBuilder buf = new StringBuilder();
buf.append(returnInfo.getFormalDataType().getName()).append(" ");
buf.append(getNameString());
buf.append(" (");
@@ -495,7 +475,6 @@ public class FunctionEditorModel {
* Get the effective function to which changes will be made. This
* will be the same as function unless it is a thunk in which case
* the returned function will be the ultimate non-thunk function.
- * @param function
* @return non-thunk function
*/
private Function getAffectiveFunction() {
@@ -663,7 +642,8 @@ public class FunctionEditorModel {
try {
if (autoParamCount < oldAutoCount) {
if (oldParams.get(
- autoParamCount).getStorage().getAutoParameterType() != storage.getAutoParameterType()) {
+ autoParamCount).getStorage().getAutoParameterType() != storage
+ .getAutoParameterType()) {
adjustSelectionForRowRemoved(i);
}
}
@@ -1180,6 +1160,10 @@ public class FunctionEditorModel {
setSignatureFieldText(getFunctionSignatureTextFromModel());
}
+ public boolean hasChanges() {
+ return !Objects.equals(getFunctionSignatureTextFromModel(), signatureFieldText);
+ }
+
public void parseSignatureFieldText() throws ParseException, CancelledException {
FunctionSignatureParser parser =
new FunctionSignatureParser(program.getDataTypeManager(), dataTypeManagerService);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bean/SetEquateDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bean/SetEquateDialog.java
index b42a1e404d..02b1a0e326 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bean/SetEquateDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bean/SetEquateDialog.java
@@ -16,8 +16,7 @@
package ghidra.app.util.bean;
import java.awt.*;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
+import java.awt.event.*;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
@@ -28,6 +27,7 @@ import javax.swing.table.TableColumnModel;
import org.apache.commons.lang3.StringUtils;
import docking.DialogComponentProvider;
+import docking.actions.KeyBindingUtils;
import docking.widgets.button.GRadioButton;
import docking.widgets.checkbox.GCheckBox;
import docking.widgets.filter.FilterListener;
@@ -220,7 +220,7 @@ public class SetEquateDialog extends DialogComponentProvider {
return entries;
}
- /**
+ /*
* Builds the main panel of the dialog and returns it.
*/
protected JPanel buildMainPanel() {
@@ -274,10 +274,18 @@ public class SetEquateDialog extends DialogComponentProvider {
suggestedEquatesTable = new GhidraTable(model);
suggestedEquatesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- JPanel tablePanel = new JPanel(new BorderLayout());
- JScrollPane scrollPane = new JScrollPane(suggestedEquatesTable);
- tablePanel.add(scrollPane);
+ // allows users to press enter in the table to accept the current selection
+ KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
+ AbstractAction action = new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ okCallback();
+ }
+ };
+ KeyBindingUtils.registerAction(suggestedEquatesTable, enter, action,
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+ // allows users to double-click a row to accept the item
suggestedEquatesTable.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
@@ -289,6 +297,10 @@ public class SetEquateDialog extends DialogComponentProvider {
}
}
});
+
+ JPanel tablePanel = new JPanel(new BorderLayout());
+ JScrollPane scrollPane = new JScrollPane(suggestedEquatesTable);
+ tablePanel.add(scrollPane);
tablePanel.setBorder(BorderFactory.createEmptyBorder(2, 5, 5, 5));
filterPanel =
@@ -378,7 +390,7 @@ public class SetEquateDialog extends DialogComponentProvider {
return result;
}
- /**
+ /*
* Get the Equate Name entered or chosen by the user.
*/
public String getEquateName() {
@@ -441,7 +453,7 @@ public class SetEquateDialog extends DialogComponentProvider {
/**
* Returns the type of selection the user has chosen.
*
- * @return
+ * @return the selection type
*/
public SelectionType getSelectionType() {
if (applyToAll.isSelected()) {
@@ -458,7 +470,7 @@ public class SetEquateDialog extends DialogComponentProvider {
/**
* Returns true if the user has chosen to overwrite any existing equate rules.
*
- * @return
+ * @return true if the user has chosen to overwrite any existing equate rules.
*/
public boolean getOverwriteExisting() {
return overwriteExistingEquates.isSelected();
@@ -492,6 +504,7 @@ public class SetEquateDialog extends DialogComponentProvider {
/**
* Sets the dialogs status display to the given message.
+ * @param text the text
*/
void setStatus(String text) {
this.setStatusText(text);