diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/project/tool/AbstractToolSavingTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/project/tool/AbstractToolSavingTest.java index db9cae750b..801220afeb 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/project/tool/AbstractToolSavingTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/project/tool/AbstractToolSavingTest.java @@ -203,7 +203,7 @@ public abstract class AbstractToolSavingTest extends AbstractGhidraHeadedIntegra PluginTool[] tools = activeWorkspace.getTools(); List pluginToolList = new ArrayList<>(tools.length); for (PluginTool tool : tools) { - pluginToolList.add((PluginTool) tool); + pluginToolList.add(tool); } return pluginToolList; } @@ -234,13 +234,9 @@ public abstract class AbstractToolSavingTest extends AbstractGhidraHeadedIntegra protected Map getOptionsMap(PluginTool tool) { Map map = new TreeMap<>(); Options[] options = tool.getOptions(); + for (Options option : options) { String optionsName = option.getName(); - - if (optionsName.equals("Key Bindings")) { - Msg.debug(this, "break"); - } - List optionNames = option.getOptionNames(); for (String name : optionNames) { Object value = invokeInstanceMethod("getObject", option, @@ -277,7 +273,12 @@ public abstract class AbstractToolSavingTest extends AbstractGhidraHeadedIntegra } 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 { @@ -341,27 +342,14 @@ public abstract class AbstractToolSavingTest extends AbstractGhidraHeadedIntegra JFrame toolFrame = tool.getToolFrame(); runSwing(() -> { - Msg.debug(this, "setting tool location to: " + point + "\n\ton window: " + - toolFrame.getTitle() + " (" + System.identityHashCode(toolFrame) + ")"); toolFrame.setLocation(point); }); waitForSwing(); waitForCondition(() -> { - - Msg.debug(this, - "\tattempt again - setting tool location to: " + point + "\n\ton window: " + - toolFrame.getTitle() + " (" + System.identityHashCode(toolFrame) + ")"); toolFrame.setLocation(point); - - Msg.debug(this, "checking " + point + " against " + 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) { diff --git a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java index 04183ab7cd..c640013eab 100644 --- a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java +++ b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java @@ -190,7 +190,7 @@ public class ProgramDiffPlugin extends ProgramPlugin ProgramLocation p1Loc = p2Loc; if (p2LocationAddress.getAddressSpace().isOverlaySpace()) { ProgramLocation equivalentP1Loc = DiffUtility - .getCompatibleProgramLocation(secondaryDiffProgram, p2Loc, primaryProgram); + .getCompatibleProgramLocation(secondaryDiffProgram, p2Loc, primaryProgram); if (equivalentP1Loc != null) { AddressSpace p2Space = p2LocationAddress.getAddressSpace(); AddressSpace p1Space = equivalentP1Loc.getAddress().getAddressSpace(); @@ -465,7 +465,7 @@ public class ProgramDiffPlugin extends ProgramPlugin diffControl.setLocation(previousP1Location.getAddress()); } ProgramLocation previousP1LocationAsP2 = DiffUtility - .getCompatibleProgramLocation(primaryProgram, location, secondaryDiffProgram); + .getCompatibleProgramLocation(primaryProgram, location, secondaryDiffProgram); if (previousP1LocationAsP2 != null) { diffListingPanel.setCursorPosition(previousP1LocationAsP2); } @@ -804,8 +804,8 @@ public class ProgramDiffPlugin extends ProgramPlugin AddressSet p2SelectionAsP1 = DiffUtility.getCompatibleAddressSet(p2Selection, primaryProgram); AddressSet p1ApplySet = p2SelectionAsP1.intersect(p1ViewAddrSet) - .subtract(addressesOnlyInP1) - .subtract(compatibleOnlyInP2); + .subtract(addressesOnlyInP1) + .subtract(compatibleOnlyInP2); if (p1ApplySet.isEmpty()) { Msg.showInfo(getClass(), tool.getToolFrame(), "Apply Differences", (p2Selection.isEmpty()) ? "No diff selection in the current view." @@ -1882,7 +1882,7 @@ public class ProgramDiffPlugin extends ProgramPlugin } } catch (CancelledException e) { - // For now do nothing if user cancels, the Diff. + // For now do nothing if user cancels } monitor.setMessage(""); diff --git a/Ghidra/Features/ProgramDiff/src/test.slow/java/ghidra/app/plugin/core/diff/DualProgramTest.java b/Ghidra/Features/ProgramDiff/src/test.slow/java/ghidra/app/plugin/core/diff/DualProgramTest.java index f3a18f55b4..fdbadb2c22 100644 --- a/Ghidra/Features/ProgramDiff/src/test.slow/java/ghidra/app/plugin/core/diff/DualProgramTest.java +++ b/Ghidra/Features/ProgramDiff/src/test.slow/java/ghidra/app/plugin/core/diff/DualProgramTest.java @@ -204,6 +204,7 @@ public class DualProgramTest extends DiffTestAdapter { TreeTestUtils.selectTreeNodeByText(tree, "OtherProgram"); pressButton(win, "OK"); waitForTasks(); + win = waitForWindow("No Memory In Common"); assertNotNull(win); MultiLineLabel mll = findComponent(win, MultiLineLabel.class); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java b/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java index 4f1d9569e2..24f7964841 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java @@ -52,11 +52,14 @@ public class DialogComponentProvider private static final String PROGRESS = "Progress"; private static final String DEFAULT = "No Progress"; - protected JPanel rootPanel; + private static int idCounter; + + private int id = ++idCounter; private boolean modal; private String title; + protected JPanel rootPanel; private JPanel mainPanel; private JComponent workPanel; private JPanel buttonPanel; @@ -189,6 +192,10 @@ public class DialogComponentProvider // may be overridden by subclasses } + public int getId() { + return id; + } + public JComponent getComponent() { return rootPanel; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DockingDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/DockingDialog.java index 3647e8f41b..16203eb0b3 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DockingDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DockingDialog.java @@ -38,6 +38,9 @@ import ghidra.util.bean.GGlassPane; public class DockingDialog extends JDialog implements HelpDescriptor { private static Component focusComponent; // allow only one scheduled focus component. See above. + private static Map dialogBoundsMap = + LazyMap.lazyMap(new HashMap<>(), () -> new BoundsInfo()); + private WindowListener windowAdapter; private DialogComponentProvider component; private boolean hasBeenFocused; @@ -47,11 +50,7 @@ public class DockingDialog extends JDialog implements HelpDescriptor { hasBeenFocused = true; } }; - - private static Map dialogBoundsMap = - LazyMap.lazyMap(new HashMap<>(), () -> new BoundsInfo()); private DockingWindowManager owningWindowManager; - private WindowAdapter modalFixWindowAdapter; /** diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java b/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java index 65e5792860..0f5687979b 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java @@ -1664,7 +1664,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder * @param dialogComponent the DialogComponentProvider object to be shown in a dialog */ 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) { ComponentPlaceholder placeholder = getActivePlaceholder(centeredOnProvider); Component c = null; - Window parent = null; - if (placeholder != null) { - 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); + if (placeholder == null && centeredOnProvider != null) { + c = centeredOnProvider.getComponent(); } + doShowDialog(dialogComponent, c); } /** @@ -1731,73 +1700,129 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder * @see #getParentWindow(Component) for parenting notes */ 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 - * positioning + * positioning. + * + *

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 + * @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 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, Component centeredOnComponent) { + Objects.requireNonNull(parent); + Objects.requireNonNull(centeredOnComponent); doShowDialog(dialogComponent, parent, centeredOnComponent); } - private static Window ensureParentHierarchy(Window parent, Component component) { - if (CollectionUtils.isAllNull(parent, component)) { - KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); - return kfm.getActiveWindow(); - } + private static void doShowDialog(DialogComponentProvider provider, + Component centeredOnComponent) { - if (SwingUtilities.isDescendingFrom(parent, component)) { - return parent; - } + Runnable r = () -> { + if (provider.isVisible()) { + provider.toFront(); + return; + } - return getParentWindow(component); + 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 Component getCenterOnComponent(Window parent, Component centeredOnComponent) { + private static Window getBestNonModalParent(DialogComponentProvider newProvider, + Window bestParent) { - /* - This method seeks to accomplish 2 goals: - 1) find a suitable component over which to center, and - 2) ensure that the chosen component is in the parent hierarchy - - */ - if (SwingUtilities.isDescendingFrom(parent, centeredOnComponent)) { - return centeredOnComponent; + KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + Window activeWindow = kfm.getActiveWindow(); + if (!(activeWindow instanceof DockingDialog)) { + return bestParent; } - // - // By default, prefer to center over the active window - // - Window activeWindow = getActiveNonTransientWindow(); - 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; + DockingDialog dialog = (DockingDialog) activeWindow; + 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 + } + + DialogComponentProvider activeProvider = dialog.getComponent(); + if (activeProvider == null) { + return bestParent; + } + + int activeId = activeProvider.getId(); + int newId = newProvider.getId(); + if (newId < activeId) { + // the new provider is actually older than the active window--do not parent the + // new provider to that window + return bestParent; } // - // The chosen component is not in the parent's hierarchy. See if there exists a - // non-transient parent window for that component. - // - Window newWindow = getParentWindow(centeredOnComponent); - if (newWindow != null) { - // the component is safe to use; the caller of this method will validate the component - // we return, updating the parent as needed - return centeredOnComponent; - } + // The active window is modal. We must make it the non-modal dialog's parent to + // prevent blocking the non-modal. + // + return dialog; + } - // We were unable to find a suitable parent for the 'best' component. Just return the - // parent as the thing over which to center. - return parent; + private static void doShowDialog(DialogComponentProvider provider, Window parent, + Component centeredOnComponent) { + + Runnable r = () -> { + if (provider.isVisible()) { + provider.toFront(); + return; + } + + DockingDialog dialog = + DockingDialog.createDialog(parent, provider, centeredOnComponent); + dialog.setVisible(true); + }; + + if (provider.isModal()) { + Swing.runNow(r); + } + else { + Swing.runIfSwingOrRunLater(r); + } } 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, 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. + 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 @@ -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(); Window defaultWindow = dwm != null ? dwm.getRootFrame() : null; - if (parent == null) { Window w = getActiveNonTransientWindow(); 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 // 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. - if (c instanceof Frame && isNonTransientWindow(c)) { + if (c instanceof Window && isNonTransientWindow(c)) { return (Window) c; } c = c.getParent(); @@ -1896,12 +1915,21 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder 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); } + private static Window getJavaActiveWindow() { + KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + return kfm.getActiveWindow(); + } + private static Window getActiveNonTransientWindow() { KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableFilterPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableFilterPanel.java index c86c520a0e..e2d7a6a936 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableFilterPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableFilterPanel.java @@ -199,14 +199,14 @@ public class GTableFilterPanel extends JPanel { String filterLabel) { this.table = table; + buildPanel(filterLabel); + uniquePreferenceKey = createUniqueFilterPreferenceKey(table); transformer = new DefaultRowFilterTransformer<>(tableModel, table.getColumnModel()); textFilterModel = installTableModel(tableModel); - buildPanel(filterLabel); - TableColumnModel columnModel = table.getColumnModel(); columnModel.addColumnModelListener(columnModelListener); @@ -478,10 +478,11 @@ public class GTableFilterPanel extends JPanel { columnFilterDialog = new ColumnFilterDialog<>(this, table, tableModel); } 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; } - + } columnFilterDialog.setCloseCallback(() -> { diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/BasicTaskMonitor.java b/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/BasicTaskMonitor.java index 783a9c79d9..23fc33c7ae 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/BasicTaskMonitor.java +++ b/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/BasicTaskMonitor.java @@ -96,6 +96,7 @@ class BasicTaskMonitor implements TaskMonitor { public void initialize(long maxValue) { setMaximum(maxValue); setProgress(0); + setIndeterminate(false); } @Override diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/TaskDialog.java b/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/TaskDialog.java index 704ff2efdf..3f2bd197dd 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/TaskDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/TaskDialog.java @@ -55,13 +55,47 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor { 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 = () -> { close(); - dispose(); + cleanup(); }; private Runnable verifyCancel = () -> { if (promptToVerifyCancel()) { - cancel(); + internalCancel(); } }; @@ -196,6 +230,7 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor { @Override protected void cancelCallback() { + // note: this is called from the cancel button and when the dialog close button is pressed 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() { finished.countDown(); - monitorComponent.notifyChangeListeners(); Swing.runLater(closeDialog); } @@ -305,8 +339,14 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor { } } + /** + * Cancels the task and closes this dialog + */ public void dispose() { - cancel(); + internalCancel(); + } + + private void cleanup() { showTimer.cancel(); messageUpdater.dispose(); } @@ -339,17 +379,21 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor { @Override public void initialize(long max) { - monitorComponent.initialize(max); - - if (!supportsProgress) { + if (max <= 0) { return; } - if (!monitorComponent.isShowing()) { - // 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. - installProgressMonitor(); + 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 + // visible. This seems wrong. If someone knows, please update this code. + //if (!monitorComponent.isShowing()) { + installProgressMonitor(); + //} } @Override @@ -391,11 +435,15 @@ public class TaskDialog extends DialogComponentProvider implements TaskMonitor { @Override public synchronized void cancel() { + internalCancel(); + } + + private void internalCancel() { if (monitorComponent.isCancelled()) { 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(); } diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/TaskMonitorComponent.java b/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/TaskMonitorComponent.java index 9899abe20b..e18ec1a446 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/TaskMonitorComponent.java +++ b/Ghidra/Framework/Docking/src/main/java/ghidra/util/task/TaskMonitorComponent.java @@ -26,7 +26,7 @@ import javax.swing.*; import docking.widgets.EmptyBorderButton; import docking.widgets.OptionDialog; import docking.widgets.label.GDHtmlLabel; -import ghidra.util.SystemUtilities; +import ghidra.util.Swing; import ghidra.util.datastruct.WeakDataStructureFactory; import ghidra.util.datastruct.WeakSet; import ghidra.util.exception.CancelledException; @@ -208,7 +208,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor { // a task dialog for fast background tasks. // isIndeterminate.set(indeterminate); - SystemUtilities.runIfSwingOrPostSwingLater(() -> { + Swing.runIfSwingOrRunLater(() -> { boolean newValue = isIndeterminate.get(); progressBar.setIndeterminate(newValue); progressBar.setStringPainted(!newValue); @@ -219,7 +219,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor { public synchronized void setCancelEnabled(boolean enable) { if (cancelEnabled != enable) { cancelEnabled = enable; - SystemUtilities.runSwingLater(updateCancelButtonRunnable); + Swing.runLater(updateCancelButtonRunnable); } } @@ -237,7 +237,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor { isCancelled = true; } - notifyChangeListeners(); + notifyCancelListeners(); } @Override @@ -286,7 +286,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor { public synchronized void showProgress(boolean show) { if (show != showingProgress) { showingProgress = show; - SystemUtilities.runSwingLater(updateProgressPanelRunnable); + Swing.runLater(updateProgressPanelRunnable); } } @@ -298,7 +298,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor { */ public void setTaskName(String name) { taskName = name; - SystemUtilities.runSwingLater(updateToolTipRunnable); + Swing.runLater(updateToolTipRunnable); } /** @@ -342,16 +342,16 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor { showingIcon = visible; }; - SystemUtilities.runSwingNow(r); + Swing.runNow(r); } - protected void notifyChangeListeners() { + protected void notifyCancelListeners() { Runnable r = () -> { for (CancelledListener mcl : listeners) { mcl.cancelled(); } }; - SwingUtilities.invokeLater(r); + Swing.runLater(r); } private synchronized void startUpdateTimer() { @@ -493,7 +493,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor { cancelButton.setName("CANCEL_TASK"); cancelButton.setPreferredSize(new Dimension(icon.getIconWidth(), icon.getIconHeight())); - cancelButton.addActionListener(e -> SwingUtilities.invokeLater(shouldCancelRunnable)); + cancelButton.addActionListener(e -> Swing.runLater(shouldCancelRunnable)); cancelButton.setFocusable(false); cancelButton.setRolloverEnabled(true); diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/task/WrappingTaskMonitor.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/task/WrappingTaskMonitor.java index 434116fd58..6b91079d6e 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/task/WrappingTaskMonitor.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/task/WrappingTaskMonitor.java @@ -68,8 +68,14 @@ public class WrappingTaskMonitor implements TaskMonitor { delegate.removeCancelledListener(l); } - newDelegate.setIndeterminate(delegate.isIndeterminate()); - newDelegate.initialize(delegate.getMaximum()); + if (delegate.isIndeterminate()) { + newDelegate.setIndeterminate(true); + } + else { + newDelegate.setIndeterminate(false); + newDelegate.initialize(delegate.getMaximum()); + } + newDelegate.setProgress(delegate.getProgress()); newDelegate.setMessage(delegate.getMessage()); newDelegate.setCancelEnabled(delegate.isCancelEnabled()); diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java index a53fd7c263..07f0f5ad7f 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java @@ -1446,7 +1446,7 @@ public abstract class PluginTool extends AbstractDockingTool { * @param centeredOnComponent the component on which to center the dialog. */ public void showDialog(DialogComponentProvider dialogComponent, Component centeredOnComponent) { - DockingWindowManager.showDialog(getToolFrame(), dialogComponent, centeredOnComponent); + DockingWindowManager.showDialog(centeredOnComponent, dialogComponent); } public Window getActiveWindow() { diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/main/ProjectInfoFilesystemTest.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/main/ProjectInfoFilesystemTest.java index 23fcea02f3..b9877e6450 100644 --- a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/main/ProjectInfoFilesystemTest.java +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/main/ProjectInfoFilesystemTest.java @@ -40,12 +40,12 @@ import ghidra.program.model.util.StringPropertyMap; import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.TestEnv; import ghidra.util.InvalidNameException; -import ghidra.util.task.TaskMonitorAdapter; +import ghidra.util.task.TaskMonitor; import utilities.util.FileUtilities; public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTest { - private static final String PROJECT_NAME = "TestProject"; + private static final String TEST_PROJECT_NAME = "TestProject"; private TestEnv env; @@ -64,11 +64,11 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe env = new TestEnv(); - projectLocator = new ProjectLocator(getTestDirectoryPath(), PROJECT_NAME); + projectLocator = new ProjectLocator(getTestDirectoryPath(), TEST_PROJECT_NAME); projectLocator.getMarkerFile().delete(); File projectDir = new File(getTestDirectoryPath(), - PROJECT_NAME + ProjectLocator.getProjectDirExtension()); + TEST_PROJECT_NAME + ProjectLocator.getProjectDirExtension()); if (projectDir.isDirectory()) { if (!FileUtilities.deleteDir(projectDir)) { Assert.fail("Cleanup of old test project failed"); @@ -78,7 +78,7 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe @After public void tearDown() throws Exception { - closeAllWindowsAndFrames(); + closeAllWindows(); env.dispose(); 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 { if (filesystemVersion < 0) { @@ -164,11 +159,6 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe 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 { frontEndTool = env.getFrontEndTool(); @@ -197,8 +187,7 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe assertNotNull(action); performAction(action, true); - dialog = waitForDialogComponent(frontEndTool.getToolFrame(), ProjectInfoDialog.class, 2000); - assertNotNull(dialog); + dialog = waitForDialogComponent(ProjectInfoDialog.class); } private DomainFolder getFolder(String folderPath, boolean create) throws IOException { @@ -239,13 +228,13 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe programUserData.endTransaction(txId); } - df = getFolder(folderPath, true).createFile(name, p, TaskMonitorAdapter.DUMMY_MONITOR); + df = getFolder(folderPath, true).createFile(name, p, TaskMonitor.DUMMY); } finally { p.release(this); } - df.addToVersionControl("Initial", true, TaskMonitorAdapter.DUMMY_MONITOR); + df.addToVersionControl("Initial", true, TaskMonitor.DUMMY); return df; } @@ -266,7 +255,7 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe assertEquals("Initial", versionHistory[0].getComment()); Program p = - (Program) df.getDomainObject(this, false, false, TaskMonitorAdapter.DUMMY_MONITOR); + (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY); try { AddressFactory addressFactory = p.getAddressFactory(); ProgramUserData programUserData = p.getProgramUserData(); @@ -303,7 +292,7 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe JLabel nameLabel = (JLabel) findComponentByName(dialog.getComponent(), "Project Name"); assertNotNull(nameLabel); - assertEquals(PROJECT_NAME, nameLabel.getText()); + assertEquals(TEST_PROJECT_NAME, nameLabel.getText()); } private void doStorageConvert(String buttonText) { @@ -314,7 +303,7 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe pressButton(button, false); JDialog confirmDialog = - waitForJDialog(null, "Confirm Convert/Upgrade Project Storage", 2000); + waitForJDialog("Confirm Convert/Upgrade Project Storage"); assertNotNull("Expected convert confirm dialog", confirmDialog); JButton confirmButton = findButtonByText(confirmDialog, "Convert"); @@ -322,7 +311,7 @@ public class ProjectInfoFilesystemTest extends AbstractGhidraHeadedIntegrationTe waitForPostedSwingRunnables(); - dialog = waitForDialogComponent(frontEndTool.getToolFrame(), ProjectInfoDialog.class, 5000); + dialog = waitForDialogComponent(ProjectInfoDialog.class); assertNotNull("Expected to find Project Info dialog after conversion completed", dialog); ProjectManager projectManager = env.getProjectManager();