From 7bc4d9e3813ef3f6f05f08e921dac64f49013215 Mon Sep 17 00:00:00 2001
From: dragonmacher <48328597+dragonmacher@users.noreply.github.com>
Date: Thu, 30 May 2019 08:44:35 -0400
Subject: [PATCH] GT-2891 - Option Dialog - Updated to not build components off
the Swing thread
---
.../ghidra/app/merge/CancelMergeDialog.java | 41 ---
.../app/merge/MergeManagerProvider.java | 40 ++-
.../analysis/AnalyzeAllOpenProgramsTask.java | 51 ++--
.../function/SetStackDepthChangeAction.java | 20 +-
.../core/references/ReferencesPlugin.java | 13 +-
.../ghidra/app/util/task/OpenProgramTask.java | 15 +-
.../java/docking/DockingErrorDisplay.java | 3 +-
.../docking/widgets/DialogRememberOption.java | 13 +-
.../main/java/docking/widgets/OkDialog.java | 93 +++++++
.../java/docking/widgets/OptionDialog.java | 255 +++++++++++-------
.../docking/widgets/OptionDialogBuilder.java | 19 +-
.../client/DefaultClientAuthenticator.java | 15 +-
.../ghidra/framework/main/FrontEndPlugin.java | 9 +-
.../ghidra/util/VersionExceptionHandler.java | 40 ++-
.../screenshot/FrontEndPluginScreenShots.java | 15 +-
.../help/screenshot/IntroScreenShots.java | 51 ++--
16 files changed, 380 insertions(+), 313 deletions(-)
delete mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/merge/CancelMergeDialog.java
create mode 100644 Ghidra/Framework/Docking/src/main/java/docking/widgets/OkDialog.java
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/CancelMergeDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/CancelMergeDialog.java
deleted file mode 100644
index 30e2080b55..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/CancelMergeDialog.java
+++ /dev/null
@@ -1,41 +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.merge;
-
-import java.awt.Component;
-
-import javax.swing.Icon;
-import javax.swing.ImageIcon;
-
-import docking.widgets.OptionDialog;
-
-public class CancelMergeDialog extends OptionDialog {
-
- public CancelMergeDialog(Icon icon) {
- super("Confirm Cancel Merge",
- "Warning! Cancel causes the entire merge process to be canceled.\n" +
- "Do you want to cancel the Merge Process?",
- "Yes", null, OptionDialog.PLAIN_MESSAGE, icon, true, "No");
- setFocusComponent(cancelButton);
- }
-
- public static int showYesNoDialog(Component parent, ImageIcon icon) {
- CancelMergeDialog dialog = new CancelMergeDialog(icon);
- dialog.show(parent);
- return dialog.getResult();
- }
-
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeManagerProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeManagerProvider.java
index 041a62937e..ce89f780b8 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeManagerProvider.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/MergeManagerProvider.java
@@ -16,7 +16,7 @@
package ghidra.app.merge;
import java.awt.*;
-import java.awt.event.*;
+import java.awt.event.MouseEvent;
import javax.swing.*;
@@ -35,7 +35,6 @@ import ghidra.framework.plugintool.ComponentProviderAdapter;
import ghidra.framework.project.tool.ToolIconURL;
import ghidra.program.util.ProgramLocation;
import ghidra.util.HelpLocation;
-import ghidra.util.UniversalIdGenerator;
import ghidra.util.layout.VerticalLayout;
import resources.ResourceManager;
@@ -60,14 +59,9 @@ class MergeManagerProvider extends ComponentProviderAdapter {
private JButton cancelButton;
private boolean wasCanceled;
- private ImageIcon WARNING_ICON = ResourceManager.loadImage("images/warning.png");
private ImageIcon MERGE_ICON = ResourceManager.loadImage("images/Merge.png");
- private long instanceID = UniversalIdGenerator.nextID().getValue();
private JPanel mainPanel;
- /**
- * Constructor
- */
public MergeManagerProvider(MergeManagerPlugin plugin, String title) {
super(plugin.getTool(), "Merge Manager", plugin.getName());
this.plugin = plugin;
@@ -157,7 +151,7 @@ class MergeManagerProvider extends ComponentProviderAdapter {
/**
* Sets the merge description at the top of the merge tool.
- * @param description
+ * @param description the description
*/
void updateMergeDescription(String description) {
nameLabel.setText(description);
@@ -186,12 +180,18 @@ class MergeManagerProvider extends ComponentProviderAdapter {
setApplyEnabled(false);
}
- /* (non-Javadoc)
- * @see ghidra.util.bean.GhidraDialog#cancelCallback()
- */
void cancelCallback(boolean force) {
- if (force ||
- CancelMergeDialog.showYesNoDialog(mainPanel, WARNING_ICON) == OptionDialog.OPTION_ONE) {
+
+ boolean cancel = force;
+ if (!force) {
+ int choice =
+ OptionDialog.showYesNoDialogWithNoAsDefaultButton(null, "Confirm Cancel Merge",
+ "Warning! Cancel causes the entire merge process to be canceled.\n" +
+ "Do you want to cancel the Merge Process?");
+ cancel = choice == OptionDialog.OPTION_ONE;
+ }
+
+ if (cancel) {
wasCanceled = true;
MergeManager mergeManager = plugin.getMergeManager();
if (mergeManager != null) {
@@ -231,22 +231,12 @@ class MergeManagerProvider extends ComponentProviderAdapter {
private JPanel createButtonPanel() {
applyButton = new JButton("Apply");
- applyButton.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- applyCallback();
- }
- });
+ applyButton.addActionListener(e -> applyCallback());
applyButton.setEnabled(false);
applyButton.setToolTipText("Apply conflict resolution");
cancelButton = new JButton("Cancel");
- cancelButton.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- cancelCallback(false);
- }
- });
+ cancelButton.addActionListener(e -> cancelCallback(false));
JPanel panel = ButtonPanelFactory.createButtonPanel(
new JButton[] { applyButton, cancelButton }, ButtonPanelFactory.X_AXIS);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalyzeAllOpenProgramsTask.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalyzeAllOpenProgramsTask.java
index a7ce599f23..7e4dfea2ff 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalyzeAllOpenProgramsTask.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/AnalyzeAllOpenProgramsTask.java
@@ -16,7 +16,6 @@
package ghidra.app.plugin.core.analysis;
import java.awt.BorderLayout;
-import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -37,7 +36,7 @@ import ghidra.program.model.lang.LanguageID;
import ghidra.program.model.listing.Program;
import ghidra.program.util.GhidraProgramUtilities;
import ghidra.util.HTMLUtilities;
-import ghidra.util.Msg;
+import ghidra.util.Swing;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.*;
@@ -171,30 +170,17 @@ class AnalyzeAllOpenProgramsTask extends Task {
}
private boolean setOptions(final Program program, AutoAnalysisManager mgr) {
- final AtomicBoolean analyze = new AtomicBoolean();
+ AtomicBoolean analyze = new AtomicBoolean();
int id = program.startTransaction("analysis");
try {
- SwingUtilities.invokeAndWait(new Runnable() {
- @Override
- public void run() {
- AnalysisOptionsDialog dialog =
- new AnalysisOptionsDialog(getValidProgramsByArchitecture());
- tool.showDialog(dialog);
- boolean shouldAnalyze = dialog.wasAnalyzeButtonSelected();
- analyze.set(shouldAnalyze);
- }
+ Swing.runNow(() -> {
+ AnalysisOptionsDialog dialog =
+ new AnalysisOptionsDialog(getValidProgramsByArchitecture());
+ tool.showDialog(dialog);
+ boolean shouldAnalyze = dialog.wasAnalyzeButtonSelected();
+ analyze.set(shouldAnalyze);
});
}
- catch (InterruptedException e) {
- // shouldn't happen
- Msg.debug(this, "Unexpected exception", e);
- return false;
- }
- catch (InvocationTargetException e) {
- // shouldn't happen
- Msg.debug(this, "Unexpected exception", e);
- return false;
- }
finally {
program.endTransaction(id, true);
}
@@ -338,10 +324,10 @@ class AnalyzeAllOpenProgramsTask extends Task {
buffy.append("");
- OptionDialog dialog = new ScrollingOptionDialog("Found Differing Architectures--Continue?",
- buffy.toString(), "Continue", OptionDialog.WARNING_MESSAGE);
- dialog.show(null);
- return dialog.getResult() == OptionDialog.OPTION_ONE;
+ return Swing.runNow(() -> {
+ ScrollingOptionDialog dialog = new ScrollingOptionDialog(buffy.toString());
+ return dialog.shouldContinue();
+ });
}
//==================================================================================================
@@ -495,9 +481,16 @@ class AnalyzeAllOpenProgramsTask extends Task {
private class ScrollingOptionDialog extends OptionDialog {
- public ScrollingOptionDialog(String title, String message, String option1,
- int messageType) {
- super(title, message, option1, messageType, null);
+ public ScrollingOptionDialog(String message) {
+ super("Found Differing Architectures", message, "Continue",
+ OptionDialog.WARNING_MESSAGE, null);
+ }
+
+ boolean shouldContinue() {
+ return Swing.runNow(() -> {
+ show(null);
+ return getResult() == OptionDialog.OPTION_ONE;
+ });
}
@Override
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/SetStackDepthChangeAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/SetStackDepthChangeAction.java
index e761d116c3..fb1783348e 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/SetStackDepthChangeAction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/SetStackDepthChangeAction.java
@@ -28,7 +28,6 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.Reference;
import ghidra.util.HelpLocation;
-import ghidra.util.SystemUtilities;
/**
* SetStackDepthChangeAction
allows the user to set a stack depth change value
@@ -172,14 +171,8 @@ class SetStackDepthChangeAction extends ListingContextAction {
currentAddress.toString() + ".";
// @formatter:on
- final OptionDialog dialog = new OptionDialog("Stack Depth Change or Function Purge?",
- message, "Local", "Global", OptionDialog.QUESTION_MESSAGE,
- OptionDialog.getIconForMessageType(OptionDialog.QUESTION_MESSAGE), true);
-
- dialog.setHelpLocation(new HelpLocation(funcPlugin.getName(), "Set_Stack_Depth_Change"));
-
- Runnable r = () -> tool.showDialog(dialog);
- SystemUtilities.runSwingNow(r);
+ StackChangeOptionDialog dialog = new StackChangeOptionDialog(message);
+ dialog.show();
return dialog.getResult();
}
@@ -198,4 +191,13 @@ class SetStackDepthChangeAction extends ListingContextAction {
return true;
}
+ private class StackChangeOptionDialog extends OptionDialog {
+
+ StackChangeOptionDialog(String message) {
+ super("Stack Depth Change or Function Purge?", message, "Local", "Global",
+ OptionDialog.QUESTION_MESSAGE, null, true);
+
+ setHelpLocation(new HelpLocation(funcPlugin.getName(), "Set_Stack_Depth_Change"));
+ }
+ }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/ReferencesPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/ReferencesPlugin.java
index 080a3003f6..ce9b613fc4 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/ReferencesPlugin.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/ReferencesPlugin.java
@@ -20,6 +20,8 @@ import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.*;
+import javax.swing.JComponent;
+
import org.jdom.Element;
import docking.ComponentProvider;
@@ -820,14 +822,11 @@ public class ReferencesPlugin extends Plugin {
curType = "Memory reference(s)";
}
- OptionDialog confirmDlg = new OptionDialog("Reference Removal Confirmation",
+ JComponent parent = editRefDialog.getComponent();
+ int choice = OptionDialog.showOptionDialog(parent, "Reference Removal Confirmation",
"Warning! existing " + curType + " will be removed.", "Continue",
- OptionDialog.WARNING_MESSAGE,
- OptionDialog.getIconForMessageType(OptionDialog.WARNING_MESSAGE));
- confirmDlg.setRememberLocation(false);
- confirmDlg.setRememberSize(false);
- tool.showDialog(confirmDlg, editRefDialog.getComponent());
- return (confirmDlg.getResult() != OptionDialog.CANCEL_OPTION);
+ OptionDialog.WARNING_MESSAGE);
+ return (choice != OptionDialog.CANCEL_OPTION);
}
@Override
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/task/OpenProgramTask.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/task/OpenProgramTask.java
index 103a2d28c3..7f2f55a5b7 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/task/OpenProgramTask.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/task/OpenProgramTask.java
@@ -18,7 +18,6 @@ package ghidra.app.util.task;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
import docking.widgets.OptionDialog;
import ghidra.app.util.dialog.CheckoutDialog;
@@ -259,16 +258,10 @@ public class OpenProgramTask extends Task {
private boolean askRecoverFile(final String filename) {
- final AtomicBoolean result = new AtomicBoolean();
-
- SystemUtilities.runSwingNow(() -> {
- int option = OptionDialog.showYesNoDialog(null, "Crash Recovery Data Found",
- "" + HTMLUtilities.escapeHTML(filename) + " has crash data.
" +
- "Would you like to recover unsaved changes?");
- result.set(option == OptionDialog.OPTION_ONE);
- });
-
- return result.get();
+ int option = OptionDialog.showYesNoDialog(null, "Crash Recovery Data Found",
+ "" + HTMLUtilities.escapeHTML(filename) + " has crash data.
" +
+ "Would you like to recover unsaved changes?");
+ return option == OptionDialog.OPTION_ONE;
}
private void performOptionalCheckout(DomainFile domainFile) {
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DockingErrorDisplay.java b/Ghidra/Framework/Docking/src/main/java/docking/DockingErrorDisplay.java
index d94fe3c850..1a12aa4974 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/DockingErrorDisplay.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/DockingErrorDisplay.java
@@ -19,6 +19,7 @@ import java.awt.Component;
import java.awt.Window;
import java.io.*;
+import docking.widgets.OkDialog;
import docking.widgets.OptionDialog;
import ghidra.util.*;
import ghidra.util.exception.MultipleCauses;
@@ -97,7 +98,7 @@ public class DockingErrorDisplay implements ErrorDisplay {
dialog = createErrorDialog(title, message, throwable, messageString);
}
else {
- dialog = new OptionDialog(title, messageString, dialogType, null);
+ dialog = new OkDialog(title, messageString, dialogType);
}
DockingWindowManager.showDialog(parent, dialog);
}
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/DialogRememberOption.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/DialogRememberOption.java
index eb17833c05..3a277696d4 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/DialogRememberOption.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/DialogRememberOption.java
@@ -32,7 +32,6 @@ public class DialogRememberOption {
* Constructs a new DialogRememberOption for use in an OptionDialog for adding an
* "Apply to all", "Remember my decision", etc. checkBox.
* @param description the checkBox text (e.g. "Apply to all")
- * @param defaultState the default state of the checkBox. (This almost always false.)
*/
public DialogRememberOption(String description) {
this.description = description;
@@ -57,8 +56,8 @@ public class DialogRememberOption {
/**
* Returns true if a previous call to the dialog was remembered (The user selected the
- * checkBox.)
- * @return
+ * checkBox)
+ * @return true if a previous call to the dialog was remembered
*/
public boolean hasRememberedResult() {
return hasRememberedResult;
@@ -72,12 +71,10 @@ public class DialogRememberOption {
* "shown", if there is a saved result, it will be returned
* instead of actually showing the dialog.
*
- * @param choice the boolean state of the checkBox.
- * @param rememberedResult the users result from the OptionDialog.
+ * @param choice the user's choice from the OptionDialog
*/
- public void rememberResult(int rememberedResult) {
+ public void rememberResult(int choice) {
this.hasRememberedResult = true;
- this.rememberedResult = rememberedResult;
+ this.rememberedResult = choice;
}
-
}
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/OkDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/OkDialog.java
new file mode 100644
index 0000000000..cd333df405
--- /dev/null
+++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/OkDialog.java
@@ -0,0 +1,93 @@
+/* ###
+ * 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 docking.widgets;
+
+import javax.swing.Icon;
+
+import ghidra.util.Swing;
+
+/**
+ * A dialog with an OK button. The client can specify the message type in the constructor.
+ */
+public class OkDialog extends OptionDialog {
+
+ /**
+ * Show a {@link OptionDialog#PLAIN_MESSAGE plain} {@link OkDialog} with the given title and message
+ * @param title the title
+ * @param message the message
+ */
+ public static void show(String title, String message) {
+ Swing.runNow(() -> {
+ new OkDialog(title, message, OptionDialog.PLAIN_MESSAGE).show();
+ });
+ }
+
+ /**
+ * Show a {@link OptionDialog#INFORMATION_MESSAGE plain} {@link OkDialog} with the given
+ * title and message
+ *
+ * @param title the title
+ * @param message the message
+ */
+ public static void showInfo(String title, String message) {
+ Swing.runNow(() -> {
+ new OkDialog(title, message, OptionDialog.INFORMATION_MESSAGE).show();
+ });
+ }
+
+ /**
+ * Show a {@link OptionDialog#ERROR_MESSAGE plain} {@link OkDialog} with the given
+ * title and message
+ *
+ * @param title the title
+ * @param message the message
+ */
+ public static void showError(String title, String message) {
+ Swing.runNow(() -> {
+ new OkDialog(title, message, OptionDialog.ERROR_MESSAGE).show();
+ });
+ }
+
+ /**
+ * Construct a simple informational dialog with a single OK button
+ *
+ * @param title The String to be placed in the dialogs title area
+ * @param message The information message to be displayed in the dialog
+ * @param messageType used to specify a default icon
+ *
** * ** The primary type of * dialog provided herein is the basic option dialog that allows the user to specify the buttons @@ -50,39 +50,53 @@ import ghidra.util.exception.AssertException; * Each of the option dialog methods will return a result, which is a number indicating the * choice made by the user. See each method for more details. *
+ *
- * The methods listed here allow the user to either enter data from the keyboard or to choose - * from a pre-populated list of data. - *
*- * {@link #showInputChoiceDialog(Component, String, String, String[], String, int)}* * *
- * {@link #showInputMultilineDialog(Component, String, String, String)}
- * {@link #showInputSingleLineDialog(Component, String, String, String)} + *+ * The methods listed here allow the user to either enter data from the keyboard or to choose + * from a pre-populated list of data. + *
+ *+ * {@link #showInputChoiceDialog(Component, String, String, String[], String, int)}*
+ * {@link #showInputMultilineDialog(Component, String, String, String)}
+ * {@link #showInputSingleLineDialog(Component, String, String, String)} + *
** * ** Finally, there are a series of methods that present Yes and No buttons in * a dialog. There are versions that do and do not have a Cancel button. *
+ *
*+ * + ** If you would like to display a simple message to the user, but do not require input from the * user, then you should use the various methods of {@link Msg}, such as * {@link Msg#showInfo(Object, Component, String, Object)}. *
- * ** Note, the user will be unable to select any text shown in the message area of the dialog. *
+ *
+ ** * @see Msg + * @see OptionDialogBuilder */ public class OptionDialog extends DialogComponentProvider { private static final String MESSAGE_COMPONENT_NAME = "MESSAGE-COMPONENT"; @@ -141,7 +155,7 @@ public class OptionDialog extends DialogComponentProvider { * @param icon allows the user to specify the icon to be used. * If non-null, this will override the messageType. */ - public OptionDialog(String title, String message, int messageType, Icon icon) { + protected OptionDialog(String title, String message, int messageType, Icon icon) { this(title, message, null, null, messageType, icon, false, null); } @@ -157,7 +171,7 @@ public class OptionDialog extends DialogComponentProvider { * this will override the messageType. * @param addCancel true means add a Cancel button */ - public OptionDialog(String title, String message, String option1, String option2, + protected OptionDialog(String title, String message, String option1, String option2, int messageType, Icon icon, boolean addCancel) { super(title, true, false, true, false); buildMainPanel(message, messageType, icon, null); @@ -175,12 +189,9 @@ public class OptionDialog extends DialogComponentProvider { * @param icon allows the user to specify the icon to be used. If non-null, * this will override the messageType. * @param addCancel true means add a Cancel button - * @param int The index of the button that should be the default button (the one that is - * executed when the user presses the Enter key):For more advanced input dialog usage, to include allowing the user to tell the dialog + * to remember a particular decision, or to apply a given choice to all future request, see + * {@link OptionDialogBuilder}. + *
* 0 is returned if the operation is cancelled * 1 for Yes * 2 for No + **/ public static int showYesNoDialog(Component parent, String title, String message) { return showOptionNoCancelDialog(parent, title, message, "&Yes", "&No", QUESTION_MESSAGE); @@ -747,14 +800,19 @@ public class OptionDialog extends DialogComponentProvider { * @param title The String to be placed in the dialogs title area. * @param message The information message to be displayed in the dialog. * @return The options selected by the user: + *
* 1 for Yes * 2 for No + **/ public static int showYesNoDialogWithNoAsDefaultButton(Component parent, String title, String message) { - OptionDialog info = - new OptionDialog(title, message, "&Yes", "&No", QUESTION_MESSAGE, null, false, "No"); - return info.show(parent); + + return Swing.runNow(() -> { + OptionDialog info = new OptionDialog(title, message, "&Yes", "&No", QUESTION_MESSAGE, + null, false, "No"); + return info.show(parent); + }); } /** @@ -768,9 +826,11 @@ public class OptionDialog extends DialogComponentProvider { * @param title The String to be placed in the dialogs title area. * @param message The information message to be displayed in the dialog. * @return The options selected by the user: + *
* 0 is returned if the operation is cancelled * 1 for the first option * 2 for the second option + **/ public static int showYesNoCancelDialog(Component parent, String title, String message) { return showOptionDialog(parent, title, message, "&Yes", "&No", QUESTION_MESSAGE); @@ -787,18 +847,22 @@ public class OptionDialog extends DialogComponentProvider { */ public static String showInputSingleLineDialog(Component parent, String title, String label, String initialValue) { - InputDialog dialog = new InputDialog(title, label, initialValue, true); - // Apply similar settings to that of the OptionDialog, for consistency - dialog.setRememberLocation(false); - dialog.setRememberSize(false); + return Swing.runNow(() -> { - DockingWindowManager.showDialog(parent, dialog); + InputDialog dialog = new InputDialog(title, label, initialValue, true); - if (dialog.isCanceled()) { - return null; - } - return dialog.getValue(); + // Apply similar settings to that of the OptionDialog, for consistency + dialog.setRememberLocation(false); + dialog.setRememberSize(false); + + DockingWindowManager.showDialog(parent, dialog); + + if (dialog.isCanceled()) { + return null; + } + return dialog.getValue(); + }); } /** @@ -812,14 +876,19 @@ public class OptionDialog extends DialogComponentProvider { */ public static String showInputMultilineDialog(Component parent, String title, String label, String initialValue) { - Icon icon = getIconForMessageType(QUESTION_MESSAGE); - MultiLineInputDialog dialog = new MultiLineInputDialog(title, label, initialValue, icon); - DockingWindowManager.showDialog(parent, dialog); - if (dialog.isCanceled()) { - return null; - } - return dialog.getValue(); + return Swing.runNow(() -> { + + Icon icon = getIconForMessageType(QUESTION_MESSAGE); + MultiLineInputDialog dialog = + new MultiLineInputDialog(title, label, initialValue, icon); + DockingWindowManager.showDialog(parent, dialog); + + if (dialog.isCanceled()) { + return null; + } + return dialog.getValue(); + }); } /** @@ -839,16 +908,19 @@ public class OptionDialog extends DialogComponentProvider { public static String showInputChoiceDialog(Component parent, String title, String label, String[] selectableValues, String initialValue, int messageType) { - Icon icon = getIconForMessageType(messageType); + return Swing.runNow(() -> { - InputWithChoicesDialog dialog = - new InputWithChoicesDialog(title, label, selectableValues, initialValue, icon); - DockingWindowManager.showDialog(parent, dialog); + Icon icon = getIconForMessageType(messageType); - if (dialog.isCanceled()) { - return null; - } - return dialog.getValue(); + InputWithChoicesDialog dialog = + new InputWithChoicesDialog(title, label, selectableValues, initialValue, icon); + DockingWindowManager.showDialog(parent, dialog); + + if (dialog.isCanceled()) { + return null; + } + return dialog.getValue(); + }); } /** @@ -871,14 +943,17 @@ public class OptionDialog extends DialogComponentProvider { Icon icon = getIconForMessageType(messageType); - InputWithChoicesDialog dialog = - new InputWithChoicesDialog(title, label, selectableValues, initialValue, true, icon); - DockingWindowManager.showDialog(parent, dialog); + return Swing.runNow(() -> { + InputWithChoicesDialog dialog = new InputWithChoicesDialog(title, label, + selectableValues, initialValue, true, icon); + DockingWindowManager.showDialog(parent, dialog); - if (dialog.isCanceled()) { - return null; - } - return dialog.getValue(); + if (dialog.isCanceled()) { + return null; + } + return dialog.getValue(); + + }); } /** diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/OptionDialogBuilder.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/OptionDialogBuilder.java index 91bd68c6cb..8b249c7020 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/OptionDialogBuilder.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/OptionDialogBuilder.java @@ -21,6 +21,8 @@ import java.util.List; import javax.swing.Icon; +import ghidra.util.Swing; + /** * Class for creating OptionDialogs using the builder pattern. * @@ -45,8 +47,8 @@ import javax.swing.Icon; * "no" as the defaultOption. * *
You can also add a Cancel button, which will return a result of 0 if pressed. Note that this
- * is different than adding an option named "Cancel" which would return a result > 0, depending
- * on where in the order it was added.
+ * is different than adding an option named "Cancel" which would return a result greater than
+ * 0
, depending on where in the order it was added.
*
*
A "Remember Option" can be added to OptionDialog to * present the user with a choice for remembering a dialog result and automatically @@ -82,9 +84,6 @@ public class OptionDialogBuilder { * this constructor is used, then both {@link #setTitle(String)} and the * {@link #setMessage(String)} methods must be called * or else the dialog will have no title or message. - * - * @param title the title of the dialog. - * @param message the main message to be displayed in the dialog. */ public OptionDialogBuilder() { this(null, null); @@ -95,8 +94,7 @@ public class OptionDialogBuilder { * this constructor is used, then the {@link #setMessage(String)} method must be called * or else the dialog will be blank. * - * @param title the title of the dialog. - * @param message the main message to be displayed in the dialog. + * @param title the title of the dialog */ public OptionDialogBuilder(String title) { this(title, null); @@ -243,8 +241,10 @@ public class OptionDialogBuilder { * @return an OptionDialog built based on the values set in this builder. */ public OptionDialog build() { - return new OptionDialog(title, message, messageType, icon, addCancelButton, - rememberOption, options, defaultOption); + return Swing.runNow(() -> { + return new OptionDialog(title, message, messageType, icon, addCancelButton, + rememberOption, options, defaultOption); + }); } /** @@ -266,6 +266,7 @@ public class OptionDialogBuilder { if (rememberOption != null && rememberOption.hasRememberedResult()) { return rememberOption.getRememberedResult(); } + OptionDialog dialog = build(); dialog.show(parent); return dialog.getResult(); diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/client/DefaultClientAuthenticator.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/client/DefaultClientAuthenticator.java index 7c335aca51..3e8e1d29d0 100644 --- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/client/DefaultClientAuthenticator.java +++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/client/DefaultClientAuthenticator.java @@ -85,19 +85,8 @@ public class DefaultClientAuthenticator extends PopupKeyStorePasswordProvider @Override public boolean promptForReconnect(final Component parent, final String message) { - final boolean[] retVal = new boolean[] { false }; - - Runnable r = () -> { - String msg = message; - if (msg != null) { - msg = msg + "\n"; - } - msg = msg + "Do you want to reconnect to the server now?"; - retVal[0] = OptionDialog.showYesNoDialog(parent, "Lost Connection to Server", - message) == OptionDialog.OPTION_ONE; - }; - SystemUtilities.runSwingNow(r); - return retVal[0]; + return OptionDialog.showYesNoDialog(parent, "Lost Connection to Server", + message) == OptionDialog.OPTION_ONE; } @Override diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndPlugin.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndPlugin.java index 98ec7244ef..ffe2f076ea 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndPlugin.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndPlugin.java @@ -31,6 +31,7 @@ import org.jdom.output.XMLOutputter; import docking.*; import docking.action.DockingAction; import docking.action.MenuData; +import docking.widgets.OkDialog; import docking.widgets.OptionDialog; import docking.widgets.dialogs.InputDialog; import docking.widgets.filechooser.GhidraFileChooser; @@ -369,23 +370,23 @@ public class FrontEndPlugin extends Plugin "\nserver may be forced to close as a result."; // @formatter:on - OptionDialog info = new OptionDialog("Ghidra Server Error", message, - OptionDialog.PLAIN_MESSAGE, DISCONNECTED_ICON); + OkDialog info = new OkDialog("Ghidra Server Error", message, DISCONNECTED_ICON); info.show(tool.getToolFrame()); } /** * Set the project manager; try to reopen the last project that was * opened. - * @param pm + * @param pm the project manager */ void setProjectManager(ProjectManager pm) { this.projectManager = pm; } /** - * sets the handle to the activeProject, as well as updating the + * Sets the handle to the activeProject, as well as updating the * active data tree to show the new active project's data + * @param project the active project */ void setActiveProject(Project project) { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/util/VersionExceptionHandler.java b/Ghidra/Framework/Project/src/main/java/ghidra/util/VersionExceptionHandler.java index 3a5bba1dfc..b4c899d8c5 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/util/VersionExceptionHandler.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/util/VersionExceptionHandler.java @@ -17,7 +17,6 @@ package ghidra.util; import java.awt.Component; -import docking.DockingWindowManager; import docking.widgets.OptionDialog; import ghidra.framework.model.DomainFile; import ghidra.util.exception.VersionException; @@ -57,16 +56,14 @@ public class VersionExceptionHandler { private static void showNeedExclusiveCheckoutDialog(final Component parent, String filename, String contentType, String actionName) { - final OptionDialog dialog = new OptionDialog(actionName + " Failed!", + + Msg.showError(VersionExceptionHandler.class, parent, actionName + " Failed!", "Unable to " + actionName + " " + contentType + ": " + filename + "\n \n" + "An upgrade of the " + contentType + " data is required, however, you must have an exclusive checkout\n" + "to upgrade a shared file!\n \n" + "NOTE: If you are unable to obtain an exclusive checkout, you may be able to " + - actionName + "\nthe file with an older version of Ghidra.", - OptionDialog.ERROR_MESSAGE, - OptionDialog.getIconForMessageType(OptionDialog.ERROR_MESSAGE)); - DockingWindowManager.showDialog(parent, dialog); + actionName + "\nthe file with an older version of Ghidra."); } private static int showUpgradeDialog(final Component parent, VersionException ve, @@ -74,28 +71,23 @@ public class VersionExceptionHandler { final String detailMessage = ve.getDetailMessage() == null ? "" : "\n" + ve.getDetailMessage(); - OptionDialog dialog = new OptionDialog("Upgrade " + contentType + " Data? " + filename, - "The " + contentType + " file you are attempting to " + actionName + - " is an older version." + detailMessage + "\n \n" + - "Would you like to Upgrade it now?", - "Upgrade", "Cancel", OptionDialog.QUESTION_MESSAGE, - OptionDialog.getIconForMessageType(OptionDialog.QUESTION_MESSAGE), false); - DockingWindowManager.showDialog(parent, dialog); - return dialog.getResult(); + String title = "Upgrade " + contentType + " Data? " + filename; + String message = "The " + contentType + " file you are attempting to " + actionName + + " is an older version." + detailMessage + "\n \n" + "Would you like to Upgrade it now?"; + return OptionDialog.showOptionDialog(parent, title, message, "Upgrade", + OptionDialog.QUESTION_MESSAGE); } private static int showWarningDialog(final Component parent, String filename, String contentType, String actionName) { - final OptionDialog dialog = new OptionDialog( - "Upgrade Shared " + contentType + " Data? " + filename, - "This " + contentType + - " file is shared with other users. If you upgrade this file,\n" + - "other users will not be able to read the new version until they upgrade to \n" + - "the same version of Ghidra. Do you want to continue?", - "Upgrade", "Cancel", OptionDialog.WARNING_MESSAGE, - OptionDialog.getIconForMessageType(OptionDialog.WARNING_MESSAGE), false); - DockingWindowManager.showDialog(parent, dialog); - return dialog.getResult(); + + String title = "Upgrade Shared " + contentType + " Data? " + filename; + String message = "This " + contentType + + " file is shared with other users. If you upgrade this file,\n" + + "other users will not be able to read the new version until they upgrade to \n" + + "the same version of Ghidra. Do you want to continue?"; + return OptionDialog.showOptionDialog(parent, title, message, "Upgrade", + OptionDialog.WARNING_MESSAGE); } public static void showVersionError(final Component parent, final String filename, diff --git a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/FrontEndPluginScreenShots.java b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/FrontEndPluginScreenShots.java index 2dc70930c9..83cba824ee 100644 --- a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/FrontEndPluginScreenShots.java +++ b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/FrontEndPluginScreenShots.java @@ -28,8 +28,7 @@ import org.junit.Test; import docking.DialogComponentProvider; import docking.DockingDialog; -import docking.widgets.OptionDialog; -import docking.widgets.PasswordChangeDialog; +import docking.widgets.*; import docking.widgets.filechooser.GhidraFileChooser; import docking.widgets.table.GTable; import docking.wizard.WizardManager; @@ -120,8 +119,7 @@ public class FrontEndPluginScreenShots extends GhidraScreenShotGenerator { new PasswordChangeDialog("Change Password", "Repository Server", "server1", "user-1"); runSwing(() -> tool.showDialog(pcd), false); - PasswordChangeDialog dialog = - waitForDialogComponent(null, PasswordChangeDialog.class, DEFAULT_WINDOW_TIMEOUT); + PasswordChangeDialog dialog = waitForDialogComponent(PasswordChangeDialog.class); captureDialog(dialog); } @@ -353,11 +351,8 @@ public class FrontEndPluginScreenShots extends GhidraScreenShotGenerator { @Test public void testProjectExists() { - final OptionDialog dialog = new OptionDialog("Project Exists", - "Cannot restore project because project named " + "TestPrj" + " already exists.", - OptionDialog.PLAIN_MESSAGE, null); - runSwing(() -> tool.showDialog(dialog), false); - + OkDialog.show("Project Exists", + "Cannot restore project because project named TestPrj already exists."); captureDialog(); } @@ -689,7 +684,7 @@ public class FrontEndPluginScreenShots extends GhidraScreenShotGenerator { } private void waitForVMMemoryInitialilzed() { - Window w = waitForWindow("VM Memory Usage", 2000); + Window w = waitForWindow("VM Memory Usage"); DialogComponentProvider dc = ((DockingDialog) w).getDialogComponent(); Boolean initialized = (Boolean) invokeInstanceMethod("isInitialized", dc); diff --git a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/IntroScreenShots.java b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/IntroScreenShots.java index 8b4c9a9ec1..7c0a5dd59d 100644 --- a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/IntroScreenShots.java +++ b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/IntroScreenShots.java @@ -21,13 +21,13 @@ import org.junit.Test; import docking.DockingWindowManager; import docking.ErrLogDialog; -import docking.widgets.OptionDialog; +import docking.widgets.OkDialog; import ghidra.framework.model.Project; import ghidra.framework.model.ProjectData; import ghidra.util.InvalidNameException; import ghidra.util.Msg; import ghidra.util.exception.CancelledException; -import ghidra.util.task.TaskMonitorAdapter; +import ghidra.util.task.TaskMonitor; public class IntroScreenShots extends GhidraScreenShotGenerator { @@ -45,55 +45,42 @@ public class IntroScreenShots extends GhidraScreenShotGenerator { // don't need to load a program } -@Test - public void testEmpty_ghidra() { + @Test + public void testEmpty_ghidra() { performAction("Close Project", "FrontEndPlugin", true); Msg.info("RecoverySnapshotMgrPlugin", "Recovery snapshot timer set to 5 minute(s)"); captureToolWindow(600, 500); } -@Test - public void testErr_Dialog() { - runSwing(new Runnable() { - @Override - public void run() { - ErrLogDialog dialog = - ErrLogDialog.createLogMessageDialog("Unexpected Error", - "Oops, this is really bad!", ""); - DockingWindowManager.showDialog(null, dialog); - } + @Test + public void testErr_Dialog() { + runSwing(() -> { + ErrLogDialog dialog = ErrLogDialog.createLogMessageDialog("Unexpected Error", + "Oops, this is really bad!", ""); + DockingWindowManager.showDialog(null, dialog); }, false); waitForSwing(); captureDialog(); } -@Test - public void testOpen_ghidra() throws InvalidNameException, CancelledException, IOException { + @Test + public void testOpen_ghidra() throws InvalidNameException, CancelledException, IOException { program = env.getProgram("WinHelloCPP.exe"); Project project = env.getProject(); ProjectData projectData = project.getProjectData(); - projectData.getRootFolder().createFile("WinHelloCpp.exe", program, - TaskMonitorAdapter.DUMMY_MONITOR); - projectData.getRootFolder().createFile("AnotherProgram.exe", program, - TaskMonitorAdapter.DUMMY_MONITOR); + projectData.getRootFolder().createFile("WinHelloCpp.exe", program, TaskMonitor.DUMMY); + projectData.getRootFolder().createFile("AnotherProgram.exe", program, TaskMonitor.DUMMY); waitForSwing(); Msg.info("ProjectImpl", "Opening project: " + tool.getProject().getName()); captureToolWindow(600, 500); } -@Test - public void testSimple_err_dialog() { - runSwing(new Runnable() { - @Override - public void run() { - OptionDialog dialog = - new OptionDialog("Some Resonable Error", - "Your operation did not complete because... (i.e File Not Found)", - OptionDialog.ERROR_MESSAGE, null); - DockingWindowManager.showDialog(null, dialog); - } - }, false); + @Test + public void testSimple_err_dialog() { + + OkDialog.showError("Some Resonable Error", + "Your operation did not complete because... (i.e File Not Found)"); captureDialog(); }