GP-1699 - Updated script 'ask' methods to place widget building on the Swing thread

This commit is contained in:
dragonmacher
2022-01-25 11:17:50 -05:00
parent 073c726885
commit 0d32b3a2b7
7 changed files with 124 additions and 207 deletions
@@ -17,14 +17,10 @@ package ghidra.app.script;
import java.awt.Color; import java.awt.Color;
import java.io.*; import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.rmi.ConnectException; import java.rmi.ConnectException;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.SwingUtilities;
import docking.DockingWindowManager;
import docking.widgets.OptionDialog; import docking.widgets.OptionDialog;
import docking.widgets.dialogs.MultiLineMessageDialog; import docking.widgets.dialogs.MultiLineMessageDialog;
import docking.widgets.filechooser.GhidraFileChooser; import docking.widgets.filechooser.GhidraFileChooser;
@@ -87,12 +83,12 @@ import ghidra.util.task.TaskMonitor;
* When you create a new script using the script manager, * When you create a new script using the script manager,
* you will automatically receive a source code stub (as shown below). * you will automatically receive a source code stub (as shown below).
* <pre> * <pre>
* //TODO write a description for this script * // TODO write a description for this script
* *
* public class NewScript extends GhidraScript { * public class NewScript extends GhidraScript {
* *
* public void run() throws Exception { * public void run() throws Exception {
* //TODO Add User Code Here * // TODO Add User Code Here
* } * }
* } * }
* </pre> * </pre>
@@ -565,7 +561,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
// only change client authenticator in headless mode // only change client authenticator in headless mode
try { try {
HeadlessClientAuthenticator HeadlessClientAuthenticator
.installHeadlessClientAuthenticator(ClientUtil.getUserName(), null, false); .installHeadlessClientAuthenticator(ClientUtil.getUserName(), null, false);
} }
catch (IOException e) { catch (IOException e) {
throw new RuntimeException("Unexpected Exception", e); throw new RuntimeException("Unexpected Exception", e);
@@ -1340,10 +1336,9 @@ public abstract class GhidraScript extends FlatProgramAPI {
Msg.error(this, errorBuffer.toString()); Msg.error(this, errorBuffer.toString());
} }
else { else {
MultiLineMessageDialog dialog = new MultiLineMessageDialog("Analysis Options", MultiLineMessageDialog.showMessageDialog(null, "Analysis Options",
"Ghidra encountered error(s) when attempting to set analysis options.", "Ghidra encountered error(s) when attempting to set analysis options.",
errorBuffer.toString(), MultiLineMessageDialog.WARNING_MESSAGE, false); errorBuffer.toString(), MultiLineMessageDialog.WARNING_MESSAGE);
DockingWindowManager.showDialog(null, dialog);
} }
} }
} }
@@ -1366,10 +1361,9 @@ public abstract class GhidraScript extends FlatProgramAPI {
Msg.error(this, errorMsg); Msg.error(this, errorMsg);
} }
else { else {
MultiLineMessageDialog dialog = new MultiLineMessageDialog("Analysis Options", MultiLineMessageDialog.showMessageDialog(null, "Analysis Options",
"Ghidra encountered error(s) when attempting to set analysis options.", "Ghidra encountered error(s) when attempting to set analysis options.",
errorMsg, MultiLineMessageDialog.WARNING_MESSAGE, false); errorMsg, MultiLineMessageDialog.WARNING_MESSAGE);
DockingWindowManager.showDialog(null, dialog);
} }
} }
} }
@@ -1796,23 +1790,8 @@ public abstract class GhidraScript extends FlatProgramAPI {
Msg.info(this, message); Msg.info(this, message);
} }
else { else {
String name = getClass().getName();
final String name = getClass().getName(); Msg.showInfo(getClass(), null, name, message);
if (SwingUtilities.isEventDispatchThread()) {
Msg.showInfo(getClass(), null, name, message);
}
else {
try {
SwingUtilities
.invokeAndWait(() -> Msg.showInfo(getClass(), null, name, message));
}
catch (InterruptedException e) {
// shouldn't happen
}
catch (InvocationTargetException e) {
// shouldn't happen
}
}
} }
} }
@@ -1981,7 +1960,7 @@ public abstract class GhidraScript extends FlatProgramAPI {
T lastValue = (mappedValue != null) ? mappedValue : defaultValue; T lastValue = (mappedValue != null) ? mappedValue : defaultValue;
T newValue = asker.apply(lastValue); // may be cancelled T newValue = swing(asker, lastValue); // may be cancelled
map.put(clazz, newValue); map.put(clazz, newValue);
return newValue; return newValue;
@@ -2039,22 +2018,17 @@ public abstract class GhidraScript extends FlatProgramAPI {
File choice = doAsk(File.class, title, approveButtonText, existingValue, lastValue -> { File choice = doAsk(File.class, title, approveButtonText, existingValue, lastValue -> {
GhidraFileChooser chooser = new GhidraFileChooser(null); GhidraFileChooser chooser = new GhidraFileChooser(null);
AtomicReference<File> ref = new AtomicReference<>(); chooser.setSelectedFile(lastValue);
chooser.setTitle(title);
Runnable r = () -> { chooser.setApproveButtonText(approveButtonText);
chooser.setSelectedFile(lastValue); chooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY);
chooser.setTitle(title); File file = chooser.getSelectedFile();
chooser.setApproveButtonText(approveButtonText);
chooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY);
ref.set(chooser.getSelectedFile());
};
Swing.runNow(r);
if (chooser.wasCancelled()) { if (chooser.wasCancelled()) {
throw new CancelledException(); throw new CancelledException();
} }
return ref.get(); return file;
}); });
return choice; return choice;
@@ -2121,22 +2095,17 @@ public abstract class GhidraScript extends FlatProgramAPI {
File choice = doAsk(DIRECTORY.class, title, approveButtonText, existingValue, lastValue -> { File choice = doAsk(DIRECTORY.class, title, approveButtonText, existingValue, lastValue -> {
GhidraFileChooser chooser = new GhidraFileChooser(null); GhidraFileChooser chooser = new GhidraFileChooser(null);
AtomicReference<File> ref = new AtomicReference<>(); chooser.setSelectedFile(lastValue);
chooser.setTitle(title);
Runnable r = () -> { chooser.setApproveButtonText(approveButtonText);
chooser.setSelectedFile(lastValue); chooser.setFileSelectionMode(GhidraFileChooserMode.DIRECTORIES_ONLY);
chooser.setTitle(title); File file = chooser.getSelectedFile();
chooser.setApproveButtonText(approveButtonText);
chooser.setFileSelectionMode(GhidraFileChooserMode.DIRECTORIES_ONLY);
ref.set(chooser.getSelectedFile());
};
Swing.runNow(r);
if (chooser.wasCancelled()) { if (chooser.wasCancelled()) {
throw new CancelledException(); throw new CancelledException();
} }
return ref.get(); return file;
}); });
return choice; return choice;
@@ -2230,19 +2199,13 @@ public abstract class GhidraScript extends FlatProgramAPI {
doAsk(clazz, title, approveButtonText, existingValue, lastValue -> { doAsk(clazz, title, approveButtonText, existingValue, lastValue -> {
SelectLanguageDialog dialog = new SelectLanguageDialog(title, approveButtonText); SelectLanguageDialog dialog = new SelectLanguageDialog(title, approveButtonText);
AtomicReference<LanguageCompilerSpecPair> ref = new AtomicReference<>(); dialog.setSelectedLanguage(lastValue);
dialog.show();
Runnable r = () -> {
dialog.setSelectedLanguage(lastValue);
ref.set(dialog.getSelectedLanguage());
};
Swing.runNow(r);
if (dialog.wasCancelled()) { if (dialog.wasCancelled()) {
throw new CancelledException(); throw new CancelledException();
} }
return ref.get(); return dialog.getSelectedLanguage();
}); });
return choice; return choice;
@@ -2309,21 +2272,12 @@ public abstract class GhidraScript extends FlatProgramAPI {
DomainFolder choice = doAsk(Program.class, title, "", existingValue, lastValue -> { DomainFolder choice = doAsk(Program.class, title, "", existingValue, lastValue -> {
DataTreeDialog dtd = new DataTreeDialog(null, title, DataTreeDialog.CHOOSE_FOLDER); DataTreeDialog dtd = new DataTreeDialog(null, title, DataTreeDialog.CHOOSE_FOLDER);
AtomicReference<DomainFolder> ref = new AtomicReference<>(); dtd.show();
dtd.addOkActionListener(e -> {
ref.set(dtd.getDomainFolder());
dtd.close();
});
Runnable r = () -> dtd.showComponent();
Swing.runNow(r);
if (dtd.wasCancelled()) { if (dtd.wasCancelled()) {
throw new CancelledException(); throw new CancelledException();
} }
return ref.get(); return dtd.getDomainFolder();
}); });
return choice; return choice;
@@ -2676,21 +2630,12 @@ public abstract class GhidraScript extends FlatProgramAPI {
DomainFile choice = doAsk(Program.class, title, "", existingValue, lastValue -> { DomainFile choice = doAsk(Program.class, title, "", existingValue, lastValue -> {
DataTreeDialog dtd = new DataTreeDialog(null, title, DataTreeDialog.OPEN); DataTreeDialog dtd = new DataTreeDialog(null, title, DataTreeDialog.OPEN);
AtomicReference<DomainFile> ref = new AtomicReference<>(); dtd.show();
dtd.addOkActionListener(e -> {
ref.set(dtd.getDomainFile());
dtd.close();
});
Runnable r = () -> dtd.showComponent();
Swing.runNow(r);
if (dtd.wasCancelled()) { if (dtd.wasCancelled()) {
throw new CancelledException(); throw new CancelledException();
} }
return ref.get(); return dtd.getDomainFile();
}); });
if (choice == null) { if (choice == null) {
@@ -2768,21 +2713,12 @@ public abstract class GhidraScript extends FlatProgramAPI {
DomainFile choice = doAsk(DomainFile.class, title, message, existingValue, lastValue -> { DomainFile choice = doAsk(DomainFile.class, title, message, existingValue, lastValue -> {
DataTreeDialog dtd = new DataTreeDialog(null, title, DataTreeDialog.OPEN); DataTreeDialog dtd = new DataTreeDialog(null, title, DataTreeDialog.OPEN);
AtomicReference<DomainFile> ref = new AtomicReference<>(); dtd.show();
dtd.addOkActionListener(e -> {
ref.set(dtd.getDomainFile());
dtd.close();
});
Runnable r = () -> dtd.showComponent();
Swing.runNow(r);
if (dtd.wasCancelled()) { if (dtd.wasCancelled()) {
throw new CancelledException(); throw new CancelledException();
} }
return ref.get(); return dtd.getDomainFile();
}); });
return choice; return choice;
@@ -3170,18 +3106,14 @@ public abstract class GhidraScript extends FlatProgramAPI {
Class<?> clazz = choices.get(0).getClass(); Class<?> clazz = choices.get(0).getClass();
List<T> choice = doAsk(clazz, title, message, existingValue, lastValue -> { List<T> choice = doAsk(clazz, title, message, existingValue, lastValue -> {
AtomicReference<List<T>> reference = new AtomicReference<>();
MultipleOptionsDialog<T> dialog = MultipleOptionsDialog<T> dialog =
new MultipleOptionsDialog<>(title, message, choices, true); new MultipleOptionsDialog<>(title, message, choices, true);
dialog.show();
Runnable r = () -> reference.set(dialog.getUserChoices());
Swing.runNow(r);
if (dialog.isCanceled()) { if (dialog.isCanceled()) {
throw new CancelledException(); throw new CancelledException();
} }
return reference.get(); return dialog.getUserChoices();
}); });
return choice; return choice;
@@ -3247,18 +3179,14 @@ public abstract class GhidraScript extends FlatProgramAPI {
Class<?> clazz = choices.get(0).getClass(); Class<?> clazz = choices.get(0).getClass();
List<T> choice = doAsk(clazz, title, message, existingValue, lastValue -> { List<T> choice = doAsk(clazz, title, message, existingValue, lastValue -> {
AtomicReference<List<T>> reference = new AtomicReference<>();
MultipleOptionsDialog<T> dialog = MultipleOptionsDialog<T> dialog =
new MultipleOptionsDialog<>(title, message, choices, choiceLabels, true); new MultipleOptionsDialog<>(title, message, choices, choiceLabels, true);
dialog.show();
Runnable r = () -> reference.set(dialog.getUserChoices());
Swing.runNow(r);
if (dialog.isCanceled()) { if (dialog.isCanceled()) {
throw new CancelledException(); throw new CancelledException();
} }
return reference.get(); return dialog.getUserChoices();
}); });
return choice; return choice;
@@ -3742,22 +3670,20 @@ public abstract class GhidraScript extends FlatProgramAPI {
Swing.runLater(runnable); Swing.runLater(runnable);
} }
private void show(final String title, final TableService table, private void show(String title, TableService table, AddressSetView addresses) {
final AddressSetView addresses) {
PluginTool tool = state.getTool(); PluginTool tool = state.getTool();
if (tool == null) { if (tool == null) {
println("Couldn't show table!"); println("Couldn't show table!");
return; return;
} }
Runnable runnable = () -> { Swing.runLater(() -> {
AddressSetTableModel model = AddressSetTableModel model =
new AddressSetTableModel(title, state.getTool(), currentProgram, addresses, null); new AddressSetTableModel(title, state.getTool(), currentProgram, addresses, null);
TableComponentProvider<Address> tableProvider = table.showTableWithMarkers(title, TableComponentProvider<Address> tableProvider = table.showTableWithMarkers(title,
"GhidraScript", model, Color.GREEN, null, "Script Results", null); "GhidraScript", model, Color.GREEN, null, "Script Results", null);
tableProvider.installRemoveItemsAction(); tableProvider.installRemoveItemsAction();
}; });
Swing.runLater(runnable);
} }
private Map<Class<?>, Object> getScriptMap(String title, String message) { private Map<Class<?>, Object> getScriptMap(String title, String message) {
@@ -3780,4 +3706,26 @@ public abstract class GhidraScript extends FlatProgramAPI {
} }
return buffer.toString(); return buffer.toString();
} }
private static <T> T swing(CancellableFunction<T, T> f, T t) throws CancelledException {
AtomicBoolean wasCancelled = new AtomicBoolean();
T result = Swing.runNow(() -> {
try {
return f.apply(t);
}
catch (CancelledException e) {
wasCancelled.set(true);
return null;
}
});
if (wasCancelled.get()) {
throw new CancelledException();
}
return result;
}
} }
@@ -28,7 +28,6 @@ import docking.DialogComponentProvider;
import docking.DockingWindowManager; import docking.DockingWindowManager;
import docking.widgets.checkbox.GCheckBox; import docking.widgets.checkbox.GCheckBox;
import docking.widgets.label.GLabel; import docking.widgets.label.GLabel;
import ghidra.util.Msg;
public class MultipleOptionsDialog<T> extends DialogComponentProvider { public class MultipleOptionsDialog<T> extends DialogComponentProvider {
@@ -104,21 +103,10 @@ public class MultipleOptionsDialog<T> extends DialogComponentProvider {
addWorkPanel(panel); addWorkPanel(panel);
addOKButton(); addOKButton();
addCancelButton(); addCancelButton();
}
if (SwingUtilities.isEventDispatchThread()) { public void show() {
DockingWindowManager.showDialog(null, this); DockingWindowManager.showDialog(null, this);
}
else {
try {
SwingUtilities.invokeAndWait(
() -> DockingWindowManager.showDialog(null, MultipleOptionsDialog.this));
}
catch (Exception e) {
Msg.error(this, "Unable to get choices from the user; error showing dialog - " +
e.getMessage());
}
}
} }
@Override @Override
@@ -19,12 +19,11 @@ import docking.DialogComponentProvider;
import docking.DockingWindowManager; import docking.DockingWindowManager;
import ghidra.plugin.importer.NewLanguagePanel; import ghidra.plugin.importer.NewLanguagePanel;
import ghidra.program.model.lang.LanguageCompilerSpecPair; import ghidra.program.model.lang.LanguageCompilerSpecPair;
import ghidra.util.SystemUtilities; import ghidra.util.Swing;
public class SelectLanguageDialog extends DialogComponentProvider { public class SelectLanguageDialog extends DialogComponentProvider {
private NewLanguagePanel languagePanel; private NewLanguagePanel languagePanel;
private boolean actionComplete = false;
private LanguageCompilerSpecPair selectedLcsPair; private LanguageCompilerSpecPair selectedLcsPair;
private boolean wasCancelled = false; private boolean wasCancelled = false;
@@ -47,7 +46,6 @@ public class SelectLanguageDialog extends DialogComponentProvider {
@Override @Override
protected void okCallback() { protected void okCallback() {
if (checkInput()) { if (checkInput()) {
actionComplete = true;
selectedLcsPair = languagePanel.getSelectedLcsPair(); selectedLcsPair = languagePanel.getSelectedLcsPair();
close(); close();
} }
@@ -74,18 +72,14 @@ public class SelectLanguageDialog extends DialogComponentProvider {
} }
void setSelectedLanguage(LanguageCompilerSpecPair language) { void setSelectedLanguage(LanguageCompilerSpecPair language) {
SystemUtilities.runSwingNow(() -> languagePanel.setSelectedLcsPair(language)); Swing.runNow(() -> languagePanel.setSelectedLcsPair(language));
} }
public LanguageCompilerSpecPair getSelectedLanguage() { public LanguageCompilerSpecPair getSelectedLanguage() {
SystemUtilities.runSwingNow(() -> showDialog());
return selectedLcsPair; return selectedLcsPair;
} }
private void showDialog() { public void show() {
selectedLcsPair = null;
actionComplete = false;
DockingWindowManager.showDialog(null, this); DockingWindowManager.showDialog(null, this);
} }
} }
@@ -32,10 +32,12 @@ import docking.widgets.label.GDLabel;
import docking.widgets.label.GLabel; import docking.widgets.label.GLabel;
import docking.widgets.tree.support.GTreeSelectionEvent; import docking.widgets.tree.support.GTreeSelectionEvent;
import docking.widgets.tree.support.GTreeSelectionListener; import docking.widgets.tree.support.GTreeSelectionListener;
import ghidra.framework.main.datatree.DialogProjectTreeContext;
import ghidra.framework.main.datatree.ProjectDataTreePanel; import ghidra.framework.main.datatree.ProjectDataTreePanel;
import ghidra.framework.main.projectdata.actions.*; import ghidra.framework.main.projectdata.actions.*;
import ghidra.framework.model.*; import ghidra.framework.model.*;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.Swing;
import ghidra.util.exception.AssertException; import ghidra.util.exception.AssertException;
import ghidra.util.layout.PairLayout; import ghidra.util.layout.PairLayout;
@@ -56,8 +58,7 @@ public class DataTreeDialog extends DialogComponentProvider
/** /**
* Dialog type for choosing a user folder. * Dialog type for choosing a user folder.
*/ */
public final static int CHOOSE_FOLDER = 2; // choose only a public final static int CHOOSE_FOLDER = 2;
// folder owned by the user
/** /**
* Dialog type for creating domain data files. * Dialog type for creating domain data files.
*/ */
@@ -85,9 +86,9 @@ public class DataTreeDialog extends DialogComponentProvider
private String pendingNameText; private String pendingNameText;
private DomainFolder pendingDomainFolder; private DomainFolder pendingDomainFolder;
private ProjectDataExpandAction expandAction; private ProjectDataExpandAction<DialogProjectTreeContext> expandAction;
private ProjectDataCollapseAction collapseAction; private ProjectDataCollapseAction<DialogProjectTreeContext> collapseAction;
private ProjectDataNewFolderAction newFolderAction; private ProjectDataNewFolderAction<DialogProjectTreeContext> newFolderAction;
private Integer treeSelectionMode; private Integer treeSelectionMode;
@@ -188,15 +189,22 @@ public class DataTreeDialog extends DialogComponentProvider
return treePanel.getActionContext(null, event); return treePanel.getActionContext(null, event);
} }
public void showComponent() { public void show() {
doSetup(); doSetup();
DockingWindowManager.showDialog(parent, this); DockingWindowManager.showDialog(parent, this);
} }
/**
* Shows this dialog. The preferred show method is {@link #show()}, as it is the preferred
* nomenclature.
*/
public void showComponent() {
show();
}
@Override @Override
protected void dialogShown() { protected void dialogShown() {
if (!comboModelInitialized) { if (!comboModelInitialized) {
// make sure the combo box model has been populated
doSetup(); doSetup();
} }
} }
@@ -255,9 +263,6 @@ public class DataTreeDialog extends DialogComponentProvider
} }
} }
/**
* Get the name from the name field.
*/
public String getNameText() { public String getNameText() {
return nameField.getText(); return nameField.getText();
} }
@@ -275,7 +280,16 @@ public class DataTreeDialog extends DialogComponentProvider
* @return null if there was no domain file selected * @return null if there was no domain file selected
*/ */
public DomainFile getDomainFile() { public DomainFile getDomainFile() {
if (domainFile == null && !cancelled) {
if (domainFile != null) {
return domainFile;
}
if (cancelled) {
return null;
}
if (treePanel != null) {
domainFile = treePanel.getSelectedDomainFile(); domainFile = treePanel.getSelectedDomainFile();
} }
return domainFile; return domainFile;
@@ -293,8 +307,7 @@ public class DataTreeDialog extends DialogComponentProvider
} }
/** /**
* TreeSelectionListener method that is called whenever the value of the * TreeSelectionListener method that is called whenever the value of the selection changes.
* selection changes.
* @param e the event that characterizes the change. * @param e the event that characterizes the change.
*/ */
@Override @Override
@@ -364,31 +377,23 @@ public class DataTreeDialog extends DialogComponentProvider
setOkEnabled((text != null) && !text.isEmpty()); setOkEnabled((text != null) && !text.isEmpty());
} }
/**
* Action listener for the project combo box.
* @param e event generated when a selection is made in the combo box
*/
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent event) {
int index = projectComboBox.getSelectedIndex(); int index = projectComboBox.getSelectedIndex();
if (index < 0) { if (index < 0) {
return; return;
} }
Project project = AppInfo.getActiveProject();
try {
ProjectData pd = project.getProjectData(projectLocators[index]);
if (pd == null) { Project project = AppInfo.getActiveProject();
Msg.showError(getClass(), getComponent(), "Error Getting Project Data", ProjectLocator projectLocator = projectLocators[index];
"Could not get project data for " + projectLocators[index].getName()); ProjectData pd = project.getProjectData(projectLocator);
} String projectName = projectLocator.getName();
else { if (pd == null) {
treePanel.setProjectData(projectLocators[index].getName(), pd); Msg.showError(this, getComponent(), "Error Getting Project Data",
} "Could not get project data for " + projectName);
} }
catch (Exception exc) { else {
Msg.showError(getClass(), getComponent(), "Error Getting Project Data", exc.toString(), treePanel.setProjectData(projectName, pd);
exc);
} }
} }
@@ -396,19 +401,17 @@ public class DataTreeDialog extends DialogComponentProvider
* Select the root folder in the tree. * Select the root folder in the tree.
*/ */
public void selectRootDataFolder() { public void selectRootDataFolder() {
SwingUtilities.invokeLater(() -> treePanel.selectRootDataFolder()); Swing.runLater(() -> treePanel.selectRootDataFolder());
} }
/** /**
* Select the node that corresponds to the given domain file. * Select the node that corresponds to the given domain file.
* @param file the file
*/ */
public void selectDomainFile(final DomainFile file) { public void selectDomainFile(DomainFile file) {
SwingUtilities.invokeLater(() -> treePanel.selectDomainFile(file)); Swing.runLater(() -> treePanel.selectDomainFile(file));
} }
/* (non-Javadoc)
* @see docking.DialogComponentProvider#close()
*/
@Override @Override
public void close() { public void close() {
super.close(); super.close();
@@ -420,10 +423,6 @@ public class DataTreeDialog extends DialogComponentProvider
comboModelInitialized = false; comboModelInitialized = false;
} }
/**
* Define the Main panel for the dialog here.
* @return JPanel the completed <CODE>Main Panel</CODE>
*/
protected JPanel buildMainPanel() { protected JPanel buildMainPanel() {
JPanel panel = new JPanel(); JPanel panel = new JPanel();
@@ -445,9 +444,6 @@ public class DataTreeDialog extends DialogComponentProvider
return panel; return panel;
} }
/**
* Gets called when the user clicks on the OK Action for the dialog.
*/
@Override @Override
protected void okCallback() { protected void okCallback() {
cancelled = false; cancelled = false;
@@ -463,17 +459,12 @@ public class DataTreeDialog extends DialogComponentProvider
return cancelled; return cancelled;
} }
/**
* Called when user hits the cancel button.
*/
@Override @Override
protected void cancelCallback() { protected void cancelCallback() {
cancelled = true; cancelled = true;
close(); close();
} }
/////////////////////////////////////////////////////////////////////
/** /**
* Create the data tree panel. * Create the data tree panel.
*/ */
@@ -653,13 +644,10 @@ public class DataTreeDialog extends DialogComponentProvider
searchString = string; searchString = string;
} }
/////////////////////////////////////////////////////////////////////
private class FieldKeyListener extends KeyAdapter { private class FieldKeyListener extends KeyAdapter {
@Override @Override
public void keyPressed(KeyEvent e) { public void keyPressed(KeyEvent e) {
clearStatusText(); clearStatusText();
} }
} }
} }
@@ -98,12 +98,10 @@ public class GhidraScriptAskMethodsTest extends AbstractGhidraHeadedIntegrationT
// if we get here, then no exception happened--good! // if we get here, then no exception happened--good!
} }
/** /*
* Test that askBytes method auto-populates dialog with value in .properties file. * Test that askBytes method auto-populates dialog with value in .properties file.
* *
* Also test that subsequent calls to the dialog show the last-used value. * Also test that subsequent calls to the dialog show the last-used value.
*
* @throws Exception
*/ */
@Test @Test
public void testAskBytes() throws Exception { public void testAskBytes() throws Exception {
@@ -309,12 +307,10 @@ public class GhidraScriptAskMethodsTest extends AbstractGhidraHeadedIntegrationT
assertEquals(anotherTempFile, myFile[0]); assertEquals(anotherTempFile, myFile[0]);
} }
/** /*
* Test that askDirectory method auto-populates dialog with value in .properties file. * Test that askDirectory method auto-populates dialog with value in .properties file.
* *
* Also test that subsequent calls to the dialog show the last-used value. * Also test that subsequent calls to the dialog show the last-used value.
*
* @throws Exception
*/ */
@Test @Test
public void testAskDirectory() throws Exception { public void testAskDirectory() throws Exception {
@@ -416,12 +412,10 @@ public class GhidraScriptAskMethodsTest extends AbstractGhidraHeadedIntegrationT
FileUtilities.deleteDir(anotherTempSubDir); FileUtilities.deleteDir(anotherTempSubDir);
} }
/** /*
* Test that askLanguage method auto-populates dialog with value in .properties file. * Test that askLanguage method auto-populates dialog with value in .properties file.
* *
* Also test that subsequent calls to the dialog show the last-used value. * Also test that subsequent calls to the dialog show the last-used value.
*
* @throws Exception
*/ */
@Test @Test
public void testAskLanguage() throws Exception { public void testAskLanguage() throws Exception {
@@ -662,11 +656,9 @@ public class GhidraScriptAskMethodsTest extends AbstractGhidraHeadedIntegrationT
assertEquals(choice_eenie, chosen); assertEquals(choice_eenie, chosen);
} }
/** /*
* Test that askChoice method auto-populates dialog with user-supplied default value (in the * Test that askChoice method auto-populates dialog with user-supplied default value (in the
* absence of a .properties file). * absence of a .properties file).
*
* @throws Exception
*/ */
@Test @Test
public void testAskChoiceDefaultValue() throws Exception { public void testAskChoiceDefaultValue() throws Exception {
@@ -171,6 +171,7 @@ public class PopulateFidDialog extends DialogComponentProvider {
browseButton.addActionListener(e -> { browseButton.addActionListener(e -> {
SelectLanguageDialog selectLanguageDialog = SelectLanguageDialog selectLanguageDialog =
new SelectLanguageDialog("Select Language", "Ok"); new SelectLanguageDialog("Select Language", "Ok");
selectLanguageDialog.show();
LanguageCompilerSpecPair selectedLanguage = selectLanguageDialog.getSelectedLanguage(); LanguageCompilerSpecPair selectedLanguage = selectLanguageDialog.getSelectedLanguage();
if (selectedLanguage != null) { if (selectedLanguage != null) {
languageIdField.setText(selectedLanguage.languageID.toString()); languageIdField.setText(selectedLanguage.languageID.toString());
@@ -28,6 +28,7 @@ import docking.widgets.OptionDialog;
import docking.widgets.label.GIconLabel; import docking.widgets.label.GIconLabel;
import docking.widgets.label.GLabel; import docking.widgets.label.GLabel;
import ghidra.util.HTMLUtilities; import ghidra.util.HTMLUtilities;
import ghidra.util.Swing;
public class MultiLineMessageDialog extends DialogComponentProvider { public class MultiLineMessageDialog extends DialogComponentProvider {
/** Used for error messages. */ /** Used for error messages. */
@@ -61,16 +62,21 @@ public class MultiLineMessageDialog extends DialogComponentProvider {
*/ */
public static void showModalMessageDialog(Component parent, String title, String shortMessage, public static void showModalMessageDialog(Component parent, String title, String shortMessage,
String detailedMessage, int messageType) { String detailedMessage, int messageType) {
MultiLineMessageDialog mlmd = Swing.runNow(() -> {
new MultiLineMessageDialog(title, shortMessage, detailedMessage, messageType, true); MultiLineMessageDialog dialog =
DockingWindowManager.showDialog(parent, mlmd); new MultiLineMessageDialog(title, shortMessage, detailedMessage, messageType, true);
DockingWindowManager.showDialog(parent, dialog);
});
} }
public static void showMessageDialog(Component parent, String title, String shortMessage, public static void showMessageDialog(Component parent, String title, String shortMessage,
String detailedMessage, int messageType) { String detailedMessage, int messageType) {
MultiLineMessageDialog mlmd = Swing.runNow(() -> {
new MultiLineMessageDialog(title, shortMessage, detailedMessage, messageType, false); MultiLineMessageDialog dialog =
DockingWindowManager.showDialog(parent, mlmd); new MultiLineMessageDialog(title, shortMessage, detailedMessage, messageType,
false);
DockingWindowManager.showDialog(parent, dialog);
});
} }
/** /**