mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GP-628 - Dialogs - test of greatly simplified parenting code
This commit is contained in:
parent
d8166ff6ec
commit
b956870432
13 changed files with 242 additions and 174 deletions
|
@ -203,7 +203,7 @@ public abstract class AbstractToolSavingTest extends AbstractGhidraHeadedIntegra
|
||||||
PluginTool[] tools = activeWorkspace.getTools();
|
PluginTool[] tools = activeWorkspace.getTools();
|
||||||
List<PluginTool> pluginToolList = new ArrayList<>(tools.length);
|
List<PluginTool> pluginToolList = new ArrayList<>(tools.length);
|
||||||
for (PluginTool tool : tools) {
|
for (PluginTool tool : tools) {
|
||||||
pluginToolList.add((PluginTool) tool);
|
pluginToolList.add(tool);
|
||||||
}
|
}
|
||||||
return pluginToolList;
|
return pluginToolList;
|
||||||
}
|
}
|
||||||
|
@ -234,13 +234,9 @@ public abstract class AbstractToolSavingTest extends AbstractGhidraHeadedIntegra
|
||||||
protected Map<String, Object> getOptionsMap(PluginTool tool) {
|
protected Map<String, Object> getOptionsMap(PluginTool tool) {
|
||||||
Map<String, Object> map = new TreeMap<>();
|
Map<String, Object> map = new TreeMap<>();
|
||||||
Options[] options = tool.getOptions();
|
Options[] options = tool.getOptions();
|
||||||
|
|
||||||
for (Options option : options) {
|
for (Options option : options) {
|
||||||
String optionsName = option.getName();
|
String optionsName = option.getName();
|
||||||
|
|
||||||
if (optionsName.equals("Key Bindings")) {
|
|
||||||
Msg.debug(this, "break");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> optionNames = option.getOptionNames();
|
List<String> optionNames = option.getOptionNames();
|
||||||
for (String name : optionNames) {
|
for (String name : optionNames) {
|
||||||
Object value = invokeInstanceMethod("getObject", option,
|
Object value = invokeInstanceMethod("getObject", option,
|
||||||
|
@ -277,7 +273,12 @@ public abstract class AbstractToolSavingTest extends AbstractGhidraHeadedIntegra
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PluginTool launchTool(String toolName) {
|
protected PluginTool launchTool(String toolName) {
|
||||||
return testEnv.launchTool(toolName, null);
|
PluginTool tool = testEnv.launchTool(toolName, null);
|
||||||
|
|
||||||
|
// There is some delayed options registration that causes sporadic test failures. Waiting
|
||||||
|
// for swing here seems to fix that.
|
||||||
|
waitForSwing();
|
||||||
|
return tool;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void dumpToolFile(String name) throws IOException {
|
protected void dumpToolFile(String name) throws IOException {
|
||||||
|
@ -341,27 +342,14 @@ public abstract class AbstractToolSavingTest extends AbstractGhidraHeadedIntegra
|
||||||
|
|
||||||
JFrame toolFrame = tool.getToolFrame();
|
JFrame toolFrame = tool.getToolFrame();
|
||||||
runSwing(() -> {
|
runSwing(() -> {
|
||||||
Msg.debug(this, "setting tool location to: " + point + "\n\ton window: " +
|
|
||||||
toolFrame.getTitle() + " (" + System.identityHashCode(toolFrame) + ")");
|
|
||||||
toolFrame.setLocation(point);
|
toolFrame.setLocation(point);
|
||||||
});
|
});
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
waitForCondition(() -> {
|
waitForCondition(() -> {
|
||||||
|
|
||||||
Msg.debug(this,
|
|
||||||
"\tattempt again - setting tool location to: " + point + "\n\ton window: " +
|
|
||||||
toolFrame.getTitle() + " (" + System.identityHashCode(toolFrame) + ")");
|
|
||||||
toolFrame.setLocation(point);
|
toolFrame.setLocation(point);
|
||||||
|
|
||||||
Msg.debug(this, "checking " + point + " against " + toolFrame.getLocation());
|
|
||||||
return point.equals(toolFrame.getLocation());
|
return point.equals(toolFrame.getLocation());
|
||||||
});
|
});
|
||||||
|
|
||||||
// debug
|
|
||||||
runSwing(() -> {
|
|
||||||
Msg.debug(this, "\ttool bounds now: " + toolFrame.getBounds());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setToolSize(PluginTool tool, final Dimension dimension) {
|
protected void setToolSize(PluginTool tool, final Dimension dimension) {
|
||||||
|
|
|
@ -1882,7 +1882,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (CancelledException e) {
|
catch (CancelledException e) {
|
||||||
// For now do nothing if user cancels, the Diff.
|
// For now do nothing if user cancels
|
||||||
}
|
}
|
||||||
|
|
||||||
monitor.setMessage("");
|
monitor.setMessage("");
|
||||||
|
|
|
@ -204,6 +204,7 @@ public class DualProgramTest extends DiffTestAdapter {
|
||||||
TreeTestUtils.selectTreeNodeByText(tree, "OtherProgram");
|
TreeTestUtils.selectTreeNodeByText(tree, "OtherProgram");
|
||||||
pressButton(win, "OK");
|
pressButton(win, "OK");
|
||||||
waitForTasks();
|
waitForTasks();
|
||||||
|
|
||||||
win = waitForWindow("No Memory In Common");
|
win = waitForWindow("No Memory In Common");
|
||||||
assertNotNull(win);
|
assertNotNull(win);
|
||||||
MultiLineLabel mll = findComponent(win, MultiLineLabel.class);
|
MultiLineLabel mll = findComponent(win, MultiLineLabel.class);
|
||||||
|
|
|
@ -52,11 +52,14 @@ public class DialogComponentProvider
|
||||||
private static final String PROGRESS = "Progress";
|
private static final String PROGRESS = "Progress";
|
||||||
private static final String DEFAULT = "No Progress";
|
private static final String DEFAULT = "No Progress";
|
||||||
|
|
||||||
protected JPanel rootPanel;
|
private static int idCounter;
|
||||||
|
|
||||||
|
private int id = ++idCounter;
|
||||||
|
|
||||||
private boolean modal;
|
private boolean modal;
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
|
protected JPanel rootPanel;
|
||||||
private JPanel mainPanel;
|
private JPanel mainPanel;
|
||||||
private JComponent workPanel;
|
private JComponent workPanel;
|
||||||
private JPanel buttonPanel;
|
private JPanel buttonPanel;
|
||||||
|
@ -189,6 +192,10 @@ public class DialogComponentProvider
|
||||||
// may be overridden by subclasses
|
// may be overridden by subclasses
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
public JComponent getComponent() {
|
public JComponent getComponent() {
|
||||||
return rootPanel;
|
return rootPanel;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,9 @@ import ghidra.util.bean.GGlassPane;
|
||||||
public class DockingDialog extends JDialog implements HelpDescriptor {
|
public class DockingDialog extends JDialog implements HelpDescriptor {
|
||||||
private static Component focusComponent; // allow only one scheduled focus component. See above.
|
private static Component focusComponent; // allow only one scheduled focus component. See above.
|
||||||
|
|
||||||
|
private static Map<String, BoundsInfo> dialogBoundsMap =
|
||||||
|
LazyMap.lazyMap(new HashMap<>(), () -> new BoundsInfo());
|
||||||
|
|
||||||
private WindowListener windowAdapter;
|
private WindowListener windowAdapter;
|
||||||
private DialogComponentProvider component;
|
private DialogComponentProvider component;
|
||||||
private boolean hasBeenFocused;
|
private boolean hasBeenFocused;
|
||||||
|
@ -47,11 +50,7 @@ public class DockingDialog extends JDialog implements HelpDescriptor {
|
||||||
hasBeenFocused = true;
|
hasBeenFocused = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private static Map<String, BoundsInfo> dialogBoundsMap =
|
|
||||||
LazyMap.lazyMap(new HashMap<>(), () -> new BoundsInfo());
|
|
||||||
private DockingWindowManager owningWindowManager;
|
private DockingWindowManager owningWindowManager;
|
||||||
|
|
||||||
private WindowAdapter modalFixWindowAdapter;
|
private WindowAdapter modalFixWindowAdapter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1664,7 +1664,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
* @param dialogComponent the DialogComponentProvider object to be shown in a dialog
|
* @param dialogComponent the DialogComponentProvider object to be shown in a dialog
|
||||||
*/
|
*/
|
||||||
public static void showDialog(DialogComponentProvider dialogComponent) {
|
public static void showDialog(DialogComponentProvider dialogComponent) {
|
||||||
showDialog(null, dialogComponent, (Component) null);
|
doShowDialog(dialogComponent, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1680,41 +1680,10 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
ComponentProvider centeredOnProvider) {
|
ComponentProvider centeredOnProvider) {
|
||||||
ComponentPlaceholder placeholder = getActivePlaceholder(centeredOnProvider);
|
ComponentPlaceholder placeholder = getActivePlaceholder(centeredOnProvider);
|
||||||
Component c = null;
|
Component c = null;
|
||||||
Window parent = null;
|
if (placeholder == null && centeredOnProvider != null) {
|
||||||
if (placeholder != null) {
|
c = centeredOnProvider.getComponent();
|
||||||
parent = root.getWindow(placeholder);
|
|
||||||
c = placeholder.getComponent();
|
|
||||||
}
|
|
||||||
showDialog(parent, dialogComponent, c);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void doShowDialog(DialogComponentProvider provider, Component parent,
|
|
||||||
Component centeredOnComponent) {
|
|
||||||
|
|
||||||
Runnable r = () -> {
|
|
||||||
if (provider.isVisible()) {
|
|
||||||
provider.toFront();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Window bestParent = getParentWindow(parent);
|
|
||||||
Component bestCenter = getCenterOnComponent(bestParent, centeredOnComponent);
|
|
||||||
|
|
||||||
// Make sure the window we have chosen to center over is related to the given parent.
|
|
||||||
// This prevents the oddness of a dialog that appears on the non-active screen.
|
|
||||||
bestParent = ensureParentHierarchy(bestParent, bestCenter);
|
|
||||||
|
|
||||||
DockingDialog dialog = DockingDialog.createDialog(bestParent, provider, bestCenter);
|
|
||||||
dialog.setVisible(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (provider.isModal()) {
|
|
||||||
Swing.runNow(r);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Swing.runIfSwingOrRunLater(r);
|
|
||||||
}
|
}
|
||||||
|
doShowDialog(dialogComponent, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1731,73 +1700,129 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
* @see #getParentWindow(Component) for parenting notes
|
* @see #getParentWindow(Component) for parenting notes
|
||||||
*/
|
*/
|
||||||
public static void showDialog(Component parent, DialogComponentProvider dialogComponent) {
|
public static void showDialog(Component parent, DialogComponentProvider dialogComponent) {
|
||||||
doShowDialog(dialogComponent, parent, null);
|
doShowDialog(dialogComponent, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the dialog using the given parent window using the optional component for
|
* Shows the dialog using the given parent window using the optional component for
|
||||||
* positioning
|
* positioning.
|
||||||
*
|
*
|
||||||
* @param parent the component whose window over which the given dialog will be shown
|
* <p>Warning: this method allows user to explicitly pass a parent window and component over
|
||||||
|
* which to be centered. There is no reason to use this method in the standard workflow.
|
||||||
|
* This method exists strictly to handle future unforeseen use cases. Use at your own
|
||||||
|
* risk of incorrectly parenting dialogs.
|
||||||
|
*
|
||||||
|
* @param parent the component whose window over which the given dialog will be shown; cannot
|
||||||
|
* be null
|
||||||
* @param dialogComponent the DialogComponentProvider object to be shown in a dialog
|
* @param dialogComponent the DialogComponentProvider object to be shown in a dialog
|
||||||
* @param centeredOnComponent the component over which the dialog will be centered if not null
|
* @param centeredOnComponent the component over which the dialog will be centered; cannot
|
||||||
|
* be null
|
||||||
*/
|
*/
|
||||||
public static void showDialog(Window parent, DialogComponentProvider dialogComponent,
|
public static void showDialog(Window parent, DialogComponentProvider dialogComponent,
|
||||||
Component centeredOnComponent) {
|
Component centeredOnComponent) {
|
||||||
|
Objects.requireNonNull(parent);
|
||||||
|
Objects.requireNonNull(centeredOnComponent);
|
||||||
doShowDialog(dialogComponent, parent, centeredOnComponent);
|
doShowDialog(dialogComponent, parent, centeredOnComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Window ensureParentHierarchy(Window parent, Component component) {
|
private static void doShowDialog(DialogComponentProvider provider,
|
||||||
if (CollectionUtils.isAllNull(parent, component)) {
|
Component centeredOnComponent) {
|
||||||
|
|
||||||
|
Runnable r = () -> {
|
||||||
|
if (provider.isVisible()) {
|
||||||
|
provider.toFront();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Component bestCenter = getJavaActiveWindow();
|
||||||
|
Window bestParent = getParentWindow(bestCenter);
|
||||||
|
|
||||||
|
if (!provider.isModal()) {
|
||||||
|
bestParent = getBestNonModalParent(provider, bestParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Note: prefer the active window; allow user's choice of center component when it is
|
||||||
|
// in the active window
|
||||||
|
//
|
||||||
|
if (centeredOnComponent != null &&
|
||||||
|
SwingUtilities.isDescendingFrom(centeredOnComponent, bestParent)) {
|
||||||
|
bestCenter = centeredOnComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
DockingDialog dialog = DockingDialog.createDialog(bestParent, provider, bestCenter);
|
||||||
|
dialog.setVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (provider.isModal()) {
|
||||||
|
Swing.runNow(r);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Swing.runIfSwingOrRunLater(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Window getBestNonModalParent(DialogComponentProvider newProvider,
|
||||||
|
Window bestParent) {
|
||||||
|
|
||||||
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
||||||
return kfm.getActiveWindow();
|
Window activeWindow = kfm.getActiveWindow();
|
||||||
|
if (!(activeWindow instanceof DockingDialog)) {
|
||||||
|
return bestParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SwingUtilities.isDescendingFrom(parent, component)) {
|
DockingDialog dialog = (DockingDialog) activeWindow;
|
||||||
return parent;
|
if (!dialog.isModal()) {
|
||||||
|
|
||||||
|
// Note: See issue 'E' described in getParentWindow()
|
||||||
|
// If we parent to a non-modal progress dialog (which is odd), when it goes away, so
|
||||||
|
// to do we. Assume that non-modal dialogs in general are long lived. We shall only
|
||||||
|
// enforce parenting to modal dialogs as defined below in order to prevent blocking of
|
||||||
|
// the non-modal dialog.
|
||||||
|
|
||||||
|
return bestParent; // not modal; assume no issues
|
||||||
}
|
}
|
||||||
|
|
||||||
return getParentWindow(component);
|
DialogComponentProvider activeProvider = dialog.getComponent();
|
||||||
|
if (activeProvider == null) {
|
||||||
|
return bestParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Component getCenterOnComponent(Window parent, Component centeredOnComponent) {
|
int activeId = activeProvider.getId();
|
||||||
|
int newId = newProvider.getId();
|
||||||
/*
|
if (newId < activeId) {
|
||||||
This method seeks to accomplish 2 goals:
|
// the new provider is actually older than the active window--do not parent the
|
||||||
1) find a suitable component over which to center, and
|
// new provider to that window
|
||||||
2) ensure that the chosen component is in the parent hierarchy
|
return bestParent;
|
||||||
|
|
||||||
*/
|
|
||||||
if (SwingUtilities.isDescendingFrom(parent, centeredOnComponent)) {
|
|
||||||
return centeredOnComponent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// By default, prefer to center over the active window
|
// The active window is modal. We must make it the non-modal dialog's parent to
|
||||||
|
// prevent blocking the non-modal.
|
||||||
//
|
//
|
||||||
Window activeWindow = getActiveNonTransientWindow();
|
return dialog;
|
||||||
if (SwingUtilities.isDescendingFrom(parent, activeWindow)) {
|
|
||||||
//
|
|
||||||
// Have an active, visible, non-transient window, which may be another dialog.
|
|
||||||
// We prefer this to be the parent.
|
|
||||||
//
|
|
||||||
return activeWindow;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
private static void doShowDialog(DialogComponentProvider provider, Window parent,
|
||||||
// The chosen component is not in the parent's hierarchy. See if there exists a
|
Component centeredOnComponent) {
|
||||||
// non-transient parent window for that component.
|
|
||||||
//
|
Runnable r = () -> {
|
||||||
Window newWindow = getParentWindow(centeredOnComponent);
|
if (provider.isVisible()) {
|
||||||
if (newWindow != null) {
|
provider.toFront();
|
||||||
// the component is safe to use; the caller of this method will validate the component
|
return;
|
||||||
// we return, updating the parent as needed
|
|
||||||
return centeredOnComponent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We were unable to find a suitable parent for the 'best' component. Just return the
|
DockingDialog dialog =
|
||||||
// parent as the thing over which to center.
|
DockingDialog.createDialog(parent, provider, centeredOnComponent);
|
||||||
return parent;
|
dialog.setVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (provider.isModal()) {
|
||||||
|
Swing.runNow(r);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Swing.runIfSwingOrRunLater(r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Window getParentWindow(Component parent) {
|
private static Window getParentWindow(Component parent) {
|
||||||
|
@ -1841,6 +1866,9 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
dialog is shown. If the non-modal dialog is parented to the modal input dialog,
|
dialog is shown. If the non-modal dialog is parented to the modal input dialog,
|
||||||
then the script progress dialog appears on top (which we do not want) and the
|
then the script progress dialog appears on top (which we do not want) and the
|
||||||
progress dialog goes away when the input dialog is closed.
|
progress dialog goes away when the input dialog is closed.
|
||||||
|
E -A long-running API shows a non-modal progress dialog. This API then shows a
|
||||||
|
results dialog which is also non-modal. We do not want to parent the new dialog
|
||||||
|
to the original dialog, since it is a progress dialog that will go away.
|
||||||
|
|
||||||
|
|
||||||
For now, the easiest mental model to use is to always prefer the active non-transient
|
For now, the easiest mental model to use is to always prefer the active non-transient
|
||||||
|
@ -1849,17 +1877,8 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//
|
|
||||||
// Due to Use Case 'C' above, prefer dialogs as parents, so that child non-modal dialogs
|
|
||||||
// do not get blocked by modal dialogs.
|
|
||||||
//
|
|
||||||
if (isNonTransientWindow(parent)) {
|
|
||||||
return (Window) parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
DockingWindowManager dwm = getActiveInstance();
|
DockingWindowManager dwm = getActiveInstance();
|
||||||
Window defaultWindow = dwm != null ? dwm.getRootFrame() : null;
|
Window defaultWindow = dwm != null ? dwm.getRootFrame() : null;
|
||||||
|
|
||||||
if (parent == null) {
|
if (parent == null) {
|
||||||
Window w = getActiveNonTransientWindow();
|
Window w = getActiveNonTransientWindow();
|
||||||
return w == null ? defaultWindow : w;
|
return w == null ? defaultWindow : w;
|
||||||
|
@ -1871,7 +1890,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
// parent of 'c' if it itself is parented to a Frame. The issue is that
|
// parent of 'c' if it itself is parented to a Frame. The issue is that
|
||||||
// Use Case 'C' above may not work correctly. If we find that to be the case,
|
// Use Case 'C' above may not work correctly. If we find that to be the case,
|
||||||
// then we can try changing 'Frame' to 'Window' here.
|
// then we can try changing 'Frame' to 'Window' here.
|
||||||
if (c instanceof Frame && isNonTransientWindow(c)) {
|
if (c instanceof Window && isNonTransientWindow(c)) {
|
||||||
return (Window) c;
|
return (Window) c;
|
||||||
}
|
}
|
||||||
c = c.getParent();
|
c = c.getParent();
|
||||||
|
@ -1896,12 +1915,21 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
||||||
return false; // we have seen this in testing
|
return false; // we have seen this in testing
|
||||||
}
|
}
|
||||||
|
|
||||||
return !provider.isTransient();
|
return !provider.isModal() && !provider.isTransient();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c instanceof Dialog) {
|
||||||
|
return !((Dialog) c).isModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (c instanceof Window);
|
return (c instanceof Window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Window getJavaActiveWindow() {
|
||||||
|
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
||||||
|
return kfm.getActiveWindow();
|
||||||
|
}
|
||||||
|
|
||||||
private static Window getActiveNonTransientWindow() {
|
private static Window getActiveNonTransientWindow() {
|
||||||
|
|
||||||
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
||||||
|
|
|
@ -199,14 +199,14 @@ public class GTableFilterPanel<ROW_OBJECT> extends JPanel {
|
||||||
String filterLabel) {
|
String filterLabel) {
|
||||||
this.table = table;
|
this.table = table;
|
||||||
|
|
||||||
|
buildPanel(filterLabel);
|
||||||
|
|
||||||
uniquePreferenceKey = createUniqueFilterPreferenceKey(table);
|
uniquePreferenceKey = createUniqueFilterPreferenceKey(table);
|
||||||
|
|
||||||
transformer = new DefaultRowFilterTransformer<>(tableModel, table.getColumnModel());
|
transformer = new DefaultRowFilterTransformer<>(tableModel, table.getColumnModel());
|
||||||
|
|
||||||
textFilterModel = installTableModel(tableModel);
|
textFilterModel = installTableModel(tableModel);
|
||||||
|
|
||||||
buildPanel(filterLabel);
|
|
||||||
|
|
||||||
TableColumnModel columnModel = table.getColumnModel();
|
TableColumnModel columnModel = table.getColumnModel();
|
||||||
columnModel.addColumnModelListener(columnModelListener);
|
columnModel.addColumnModelListener(columnModelListener);
|
||||||
|
|
||||||
|
@ -478,7 +478,8 @@ public class GTableFilterPanel<ROW_OBJECT> extends JPanel {
|
||||||
columnFilterDialog = new ColumnFilterDialog<>(this, table, tableModel);
|
columnFilterDialog = new ColumnFilterDialog<>(this, table, tableModel);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Msg.showError(this, this, "Column Filter Error", "This table contains no filterable columns!");
|
Msg.showError(this, this, "Column Filter Error",
|
||||||
|
"This table contains no filterable columns!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,7 @@ class BasicTaskMonitor implements TaskMonitor {
|
||||||
public void initialize(long maxValue) {
|
public void initialize(long maxValue) {
|
||||||
setMaximum(maxValue);
|
setMaximum(maxValue);
|
||||||
setProgress(0);
|
setProgress(0);
|
||||||
|
setIndeterminate(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -55,13 +55,47 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
||||||
|
|
||||||
public final static int DEFAULT_WIDTH = 275;
|
public final static int DEFAULT_WIDTH = 275;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: all paths of finishing should end up calling this runnable.
|
||||||
|
*
|
||||||
|
* Workflow:
|
||||||
|
*
|
||||||
|
* Dialog Close Button Pressed:
|
||||||
|
* -calls cancelCallback()
|
||||||
|
* -calls verifyCancel runnable
|
||||||
|
* -calls iternalCancel()
|
||||||
|
* -triggers taskProcessed()
|
||||||
|
* -calls closeDialog runnable
|
||||||
|
*
|
||||||
|
* Cancel Button Pressed:
|
||||||
|
* -(same as Dialog Close Button Pressed)
|
||||||
|
*
|
||||||
|
* Task Monitor Stop Button Pressed:
|
||||||
|
* -triggers taskProcessed()
|
||||||
|
* -calls closeDialog runnable
|
||||||
|
*
|
||||||
|
* Public API dispose() is Called:
|
||||||
|
* -calls iternalCancel()
|
||||||
|
* -triggers taskProcessed()
|
||||||
|
* -calls closeDialog runnable
|
||||||
|
*
|
||||||
|
* Task Monitor Cancelled by API:
|
||||||
|
* -triggers taskProcessed()
|
||||||
|
* -calls closeDialog runnable
|
||||||
|
*
|
||||||
|
* Task Finishes Normally:
|
||||||
|
* -triggers taskProcessed()
|
||||||
|
* -calls closeDialog runnable
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
private Runnable closeDialog = () -> {
|
private Runnable closeDialog = () -> {
|
||||||
close();
|
close();
|
||||||
dispose();
|
cleanup();
|
||||||
};
|
};
|
||||||
private Runnable verifyCancel = () -> {
|
private Runnable verifyCancel = () -> {
|
||||||
if (promptToVerifyCancel()) {
|
if (promptToVerifyCancel()) {
|
||||||
cancel();
|
internalCancel();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -196,6 +230,7 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void cancelCallback() {
|
protected void cancelCallback() {
|
||||||
|
// note: this is called from the cancel button and when the dialog close button is pressed
|
||||||
Swing.runLater(verifyCancel);
|
Swing.runLater(verifyCancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,11 +246,10 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called after the task has been executed
|
* Called after the task has been executed or when the task is cancelled
|
||||||
*/
|
*/
|
||||||
public void taskProcessed() {
|
public void taskProcessed() {
|
||||||
finished.countDown();
|
finished.countDown();
|
||||||
monitorComponent.notifyChangeListeners();
|
|
||||||
Swing.runLater(closeDialog);
|
Swing.runLater(closeDialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,8 +339,14 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels the task and closes this dialog
|
||||||
|
*/
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
cancel();
|
internalCancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanup() {
|
||||||
showTimer.cancel();
|
showTimer.cancel();
|
||||||
messageUpdater.dispose();
|
messageUpdater.dispose();
|
||||||
}
|
}
|
||||||
|
@ -339,17 +379,21 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
||||||
@Override
|
@Override
|
||||||
public void initialize(long max) {
|
public void initialize(long max) {
|
||||||
|
|
||||||
monitorComponent.initialize(max);
|
if (max <= 0) {
|
||||||
|
|
||||||
if (!supportsProgress) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!monitorComponent.isShowing()) {
|
monitorComponent.initialize(max);
|
||||||
|
if (!supportsProgress) {
|
||||||
|
supportsProgress = true;
|
||||||
|
setIndeterminate(false);
|
||||||
|
}
|
||||||
|
|
||||||
// Note: it is not clear why we only wish to show progress if the monitor is not
|
// Note: it is not clear why we only wish to show progress if the monitor is not
|
||||||
// visible. This seems wrong. If someone knows, please update this code.
|
// visible. This seems wrong. If someone knows, please update this code.
|
||||||
|
//if (!monitorComponent.isShowing()) {
|
||||||
installProgressMonitor();
|
installProgressMonitor();
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -391,11 +435,15 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void cancel() {
|
public synchronized void cancel() {
|
||||||
|
internalCancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void internalCancel() {
|
||||||
if (monitorComponent.isCancelled()) {
|
if (monitorComponent.isCancelled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Mark as cancelled, must be detected by task which should terminate
|
|
||||||
// and invoke setCompleted which will dismiss dialog.
|
// mark as cancelled; the task will terminate and the callback will dismiss this dialog
|
||||||
monitorComponent.cancel();
|
monitorComponent.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ import javax.swing.*;
|
||||||
import docking.widgets.EmptyBorderButton;
|
import docking.widgets.EmptyBorderButton;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import docking.widgets.label.GDHtmlLabel;
|
import docking.widgets.label.GDHtmlLabel;
|
||||||
import ghidra.util.SystemUtilities;
|
import ghidra.util.Swing;
|
||||||
import ghidra.util.datastruct.WeakDataStructureFactory;
|
import ghidra.util.datastruct.WeakDataStructureFactory;
|
||||||
import ghidra.util.datastruct.WeakSet;
|
import ghidra.util.datastruct.WeakSet;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
@ -208,7 +208,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
||||||
// a task dialog for fast background tasks.
|
// a task dialog for fast background tasks.
|
||||||
//
|
//
|
||||||
isIndeterminate.set(indeterminate);
|
isIndeterminate.set(indeterminate);
|
||||||
SystemUtilities.runIfSwingOrPostSwingLater(() -> {
|
Swing.runIfSwingOrRunLater(() -> {
|
||||||
boolean newValue = isIndeterminate.get();
|
boolean newValue = isIndeterminate.get();
|
||||||
progressBar.setIndeterminate(newValue);
|
progressBar.setIndeterminate(newValue);
|
||||||
progressBar.setStringPainted(!newValue);
|
progressBar.setStringPainted(!newValue);
|
||||||
|
@ -219,7 +219,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
||||||
public synchronized void setCancelEnabled(boolean enable) {
|
public synchronized void setCancelEnabled(boolean enable) {
|
||||||
if (cancelEnabled != enable) {
|
if (cancelEnabled != enable) {
|
||||||
cancelEnabled = enable;
|
cancelEnabled = enable;
|
||||||
SystemUtilities.runSwingLater(updateCancelButtonRunnable);
|
Swing.runLater(updateCancelButtonRunnable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,7 +237,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
||||||
isCancelled = true;
|
isCancelled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyChangeListeners();
|
notifyCancelListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -286,7 +286,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
||||||
public synchronized void showProgress(boolean show) {
|
public synchronized void showProgress(boolean show) {
|
||||||
if (show != showingProgress) {
|
if (show != showingProgress) {
|
||||||
showingProgress = show;
|
showingProgress = show;
|
||||||
SystemUtilities.runSwingLater(updateProgressPanelRunnable);
|
Swing.runLater(updateProgressPanelRunnable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,7 +298,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
||||||
*/
|
*/
|
||||||
public void setTaskName(String name) {
|
public void setTaskName(String name) {
|
||||||
taskName = name;
|
taskName = name;
|
||||||
SystemUtilities.runSwingLater(updateToolTipRunnable);
|
Swing.runLater(updateToolTipRunnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -342,16 +342,16 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
||||||
showingIcon = visible;
|
showingIcon = visible;
|
||||||
};
|
};
|
||||||
|
|
||||||
SystemUtilities.runSwingNow(r);
|
Swing.runNow(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void notifyChangeListeners() {
|
protected void notifyCancelListeners() {
|
||||||
Runnable r = () -> {
|
Runnable r = () -> {
|
||||||
for (CancelledListener mcl : listeners) {
|
for (CancelledListener mcl : listeners) {
|
||||||
mcl.cancelled();
|
mcl.cancelled();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
SwingUtilities.invokeLater(r);
|
Swing.runLater(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void startUpdateTimer() {
|
private synchronized void startUpdateTimer() {
|
||||||
|
@ -493,7 +493,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
||||||
|
|
||||||
cancelButton.setName("CANCEL_TASK");
|
cancelButton.setName("CANCEL_TASK");
|
||||||
cancelButton.setPreferredSize(new Dimension(icon.getIconWidth(), icon.getIconHeight()));
|
cancelButton.setPreferredSize(new Dimension(icon.getIconWidth(), icon.getIconHeight()));
|
||||||
cancelButton.addActionListener(e -> SwingUtilities.invokeLater(shouldCancelRunnable));
|
cancelButton.addActionListener(e -> Swing.runLater(shouldCancelRunnable));
|
||||||
cancelButton.setFocusable(false);
|
cancelButton.setFocusable(false);
|
||||||
cancelButton.setRolloverEnabled(true);
|
cancelButton.setRolloverEnabled(true);
|
||||||
|
|
||||||
|
|
|
@ -68,8 +68,14 @@ public class WrappingTaskMonitor implements TaskMonitor {
|
||||||
delegate.removeCancelledListener(l);
|
delegate.removeCancelledListener(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
newDelegate.setIndeterminate(delegate.isIndeterminate());
|
if (delegate.isIndeterminate()) {
|
||||||
|
newDelegate.setIndeterminate(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newDelegate.setIndeterminate(false);
|
||||||
newDelegate.initialize(delegate.getMaximum());
|
newDelegate.initialize(delegate.getMaximum());
|
||||||
|
}
|
||||||
|
|
||||||
newDelegate.setProgress(delegate.getProgress());
|
newDelegate.setProgress(delegate.getProgress());
|
||||||
newDelegate.setMessage(delegate.getMessage());
|
newDelegate.setMessage(delegate.getMessage());
|
||||||
newDelegate.setCancelEnabled(delegate.isCancelEnabled());
|
newDelegate.setCancelEnabled(delegate.isCancelEnabled());
|
||||||
|
|
|
@ -1446,7 +1446,7 @@ public abstract class PluginTool extends AbstractDockingTool {
|
||||||
* @param centeredOnComponent the component on which to center the dialog.
|
* @param centeredOnComponent the component on which to center the dialog.
|
||||||
*/
|
*/
|
||||||
public void showDialog(DialogComponentProvider dialogComponent, Component centeredOnComponent) {
|
public void showDialog(DialogComponentProvider dialogComponent, Component centeredOnComponent) {
|
||||||
DockingWindowManager.showDialog(getToolFrame(), dialogComponent, centeredOnComponent);
|
DockingWindowManager.showDialog(centeredOnComponent, dialogComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Window getActiveWindow() {
|
public Window getActiveWindow() {
|
||||||
|
|
|
@ -40,12 +40,12 @@ import ghidra.program.model.util.StringPropertyMap;
|
||||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||||
import ghidra.test.TestEnv;
|
import ghidra.test.TestEnv;
|
||||||
import ghidra.util.InvalidNameException;
|
import ghidra.util.InvalidNameException;
|
||||||
import ghidra.util.task.TaskMonitorAdapter;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import utilities.util.FileUtilities;
|
import utilities.util.FileUtilities;
|
||||||
|
|
||||||
public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTest {
|
public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
private static final String PROJECT_NAME = "TestProject";
|
private static final String TEST_PROJECT_NAME = "TestProject";
|
||||||
|
|
||||||
private TestEnv env;
|
private TestEnv env;
|
||||||
|
|
||||||
|
@ -64,11 +64,11 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe
|
||||||
|
|
||||||
env = new TestEnv();
|
env = new TestEnv();
|
||||||
|
|
||||||
projectLocator = new ProjectLocator(getTestDirectoryPath(), PROJECT_NAME);
|
projectLocator = new ProjectLocator(getTestDirectoryPath(), TEST_PROJECT_NAME);
|
||||||
projectLocator.getMarkerFile().delete();
|
projectLocator.getMarkerFile().delete();
|
||||||
|
|
||||||
File projectDir = new File(getTestDirectoryPath(),
|
File projectDir = new File(getTestDirectoryPath(),
|
||||||
PROJECT_NAME + ProjectLocator.getProjectDirExtension());
|
TEST_PROJECT_NAME + ProjectLocator.getProjectDirExtension());
|
||||||
if (projectDir.isDirectory()) {
|
if (projectDir.isDirectory()) {
|
||||||
if (!FileUtilities.deleteDir(projectDir)) {
|
if (!FileUtilities.deleteDir(projectDir)) {
|
||||||
Assert.fail("Cleanup of old test project failed");
|
Assert.fail("Cleanup of old test project failed");
|
||||||
|
@ -78,7 +78,7 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
closeAllWindowsAndFrames();
|
closeAllWindows();
|
||||||
env.dispose();
|
env.dispose();
|
||||||
|
|
||||||
if (project != null) {
|
if (project != null) {
|
||||||
|
@ -114,11 +114,6 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create project
|
|
||||||
* @param filesystemVersion -1: mangled, 0... indexed version
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
private void createProject(int filesystemVersion) throws Exception {
|
private void createProject(int filesystemVersion) throws Exception {
|
||||||
|
|
||||||
if (filesystemVersion < 0) {
|
if (filesystemVersion < 0) {
|
||||||
|
@ -164,11 +159,6 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create and open project in front-end and popup Project Info dialog
|
|
||||||
* @param filesystemVersion -1: mangled, 0... indexed version
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
private void openProjectAndInfo(int filesystemVersion) throws Exception {
|
private void openProjectAndInfo(int filesystemVersion) throws Exception {
|
||||||
|
|
||||||
frontEndTool = env.getFrontEndTool();
|
frontEndTool = env.getFrontEndTool();
|
||||||
|
@ -197,8 +187,7 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe
|
||||||
assertNotNull(action);
|
assertNotNull(action);
|
||||||
performAction(action, true);
|
performAction(action, true);
|
||||||
|
|
||||||
dialog = waitForDialogComponent(frontEndTool.getToolFrame(), ProjectInfoDialog.class, 2000);
|
dialog = waitForDialogComponent(ProjectInfoDialog.class);
|
||||||
assertNotNull(dialog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DomainFolder getFolder(String folderPath, boolean create) throws IOException {
|
private DomainFolder getFolder(String folderPath, boolean create) throws IOException {
|
||||||
|
@ -239,13 +228,13 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe
|
||||||
programUserData.endTransaction(txId);
|
programUserData.endTransaction(txId);
|
||||||
}
|
}
|
||||||
|
|
||||||
df = getFolder(folderPath, true).createFile(name, p, TaskMonitorAdapter.DUMMY_MONITOR);
|
df = getFolder(folderPath, true).createFile(name, p, TaskMonitor.DUMMY);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
p.release(this);
|
p.release(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
df.addToVersionControl("Initial", true, TaskMonitorAdapter.DUMMY_MONITOR);
|
df.addToVersionControl("Initial", true, TaskMonitor.DUMMY);
|
||||||
return df;
|
return df;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,7 +255,7 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe
|
||||||
assertEquals("Initial", versionHistory[0].getComment());
|
assertEquals("Initial", versionHistory[0].getComment());
|
||||||
|
|
||||||
Program p =
|
Program p =
|
||||||
(Program) df.getDomainObject(this, false, false, TaskMonitorAdapter.DUMMY_MONITOR);
|
(Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
|
||||||
try {
|
try {
|
||||||
AddressFactory addressFactory = p.getAddressFactory();
|
AddressFactory addressFactory = p.getAddressFactory();
|
||||||
ProgramUserData programUserData = p.getProgramUserData();
|
ProgramUserData programUserData = p.getProgramUserData();
|
||||||
|
@ -303,7 +292,7 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe
|
||||||
|
|
||||||
JLabel nameLabel = (JLabel) findComponentByName(dialog.getComponent(), "Project Name");
|
JLabel nameLabel = (JLabel) findComponentByName(dialog.getComponent(), "Project Name");
|
||||||
assertNotNull(nameLabel);
|
assertNotNull(nameLabel);
|
||||||
assertEquals(PROJECT_NAME, nameLabel.getText());
|
assertEquals(TEST_PROJECT_NAME, nameLabel.getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doStorageConvert(String buttonText) {
|
private void doStorageConvert(String buttonText) {
|
||||||
|
@ -314,7 +303,7 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe
|
||||||
pressButton(button, false);
|
pressButton(button, false);
|
||||||
|
|
||||||
JDialog confirmDialog =
|
JDialog confirmDialog =
|
||||||
waitForJDialog(null, "Confirm Convert/Upgrade Project Storage", 2000);
|
waitForJDialog("Confirm Convert/Upgrade Project Storage");
|
||||||
assertNotNull("Expected convert confirm dialog", confirmDialog);
|
assertNotNull("Expected convert confirm dialog", confirmDialog);
|
||||||
|
|
||||||
JButton confirmButton = findButtonByText(confirmDialog, "Convert");
|
JButton confirmButton = findButtonByText(confirmDialog, "Convert");
|
||||||
|
@ -322,7 +311,7 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe
|
||||||
|
|
||||||
waitForPostedSwingRunnables();
|
waitForPostedSwingRunnables();
|
||||||
|
|
||||||
dialog = waitForDialogComponent(frontEndTool.getToolFrame(), ProjectInfoDialog.class, 5000);
|
dialog = waitForDialogComponent(ProjectInfoDialog.class);
|
||||||
assertNotNull("Expected to find Project Info dialog after conversion completed", dialog);
|
assertNotNull("Expected to find Project Info dialog after conversion completed", dialog);
|
||||||
|
|
||||||
ProjectManager projectManager = env.getProjectManager();
|
ProjectManager projectManager = env.getProjectManager();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue