GP-224 - Modal Dialogs - fixed modal dialogs not being parented to

active window in default case
This commit is contained in:
dragonmacher 2020-10-06 11:09:28 -04:00
parent 2b08598dba
commit 9dd458e9e1
24 changed files with 182 additions and 217 deletions

View file

@ -35,10 +35,10 @@ import ghidra.framework.project.DefaultProjectManager;
import ghidra.framework.remote.InetNameLookup; import ghidra.framework.remote.InetNameLookup;
import ghidra.framework.store.LockException; import ghidra.framework.store.LockException;
import ghidra.program.database.ProgramDB; import ghidra.program.database.ProgramDB;
import ghidra.util.Msg; import ghidra.util.*;
import ghidra.util.SystemUtilities;
import ghidra.util.exception.UsrException; import ghidra.util.exception.UsrException;
import ghidra.util.task.*; import ghidra.util.task.TaskLauncher;
import ghidra.util.task.TaskMonitorAdapter;
/** /**
* Main Ghidra application class. Creates * Main Ghidra application class. Creates
@ -64,7 +64,6 @@ import ghidra.util.task.*;
* @see ghidra.GhidraLauncher * @see ghidra.GhidraLauncher
*/ */
public class GhidraRun implements GhidraLaunchable { public class GhidraRun implements GhidraLaunchable {
private final String MASTER_HELP_SET_HS = "Base_HelpSet.hs";
private Logger log; // intentionally load later, after initialization private Logger log; // intentionally load later, after initialization
@ -179,14 +178,12 @@ public class GhidraRun implements GhidraLaunchable {
} }
} }
private void openProject(final FrontEndTool tool, final ProjectLocator projectLocator, private void openProject(FrontEndTool tool, ProjectLocator projectLocator, boolean reopen) {
final boolean reopen) {
SplashScreen.updateSplashScreenStatus( SplashScreen.updateSplashScreenStatus(
(reopen ? "Reopening" : "Opening") + " project: " + projectLocator.getName()); (reopen ? "Reopening" : "Opening") + " project: " + projectLocator.getName());
final Runnable r = () -> doOpenProject(tool, projectLocator, reopen);
InvokeInSwingTask task = new InvokeInSwingTask("Opening Project", r); Runnable r = () -> doOpenProject(tool, projectLocator, reopen);
new TaskLauncher(task, tool.getToolFrame(), 0); TaskLauncher.launchModal("Opening Project", () -> Swing.runNow(r));
} }
private void doOpenProject(FrontEndTool tool, ProjectLocator projectLocator, boolean reopen) { private void doOpenProject(FrontEndTool tool, ProjectLocator projectLocator, boolean reopen) {

View file

@ -16,9 +16,6 @@
package ghidra.app.plugin.core.compositeeditor; package ghidra.app.plugin.core.compositeeditor;
import java.awt.Component; import java.awt.Component;
import java.awt.Window;
import javax.swing.SwingUtilities;
import docking.ActionContext; import docking.ActionContext;
import docking.DockingWindowManager; import docking.DockingWindowManager;
@ -59,9 +56,7 @@ public class AddBitFieldAction extends CompositeEditorTableAction {
new BitFieldEditorDialog(editorModel.viewComposite, provider.dtmService, new BitFieldEditorDialog(editorModel.viewComposite, provider.dtmService,
-(rowIndex + 1), ordinal -> refreshTableAndSelection(editorModel, ordinal)); -(rowIndex + 1), ordinal -> refreshTableAndSelection(editorModel, ordinal));
Component c = provider.getComponent(); Component c = provider.getComponent();
Window w = SwingUtilities.windowForComponent(c); DockingWindowManager.showDialog(c, dlg);
DockingWindowManager.showDialog(w, dlg, c);
requestTableFocus(); requestTableFocus();
} }

View file

@ -165,8 +165,7 @@ public abstract class CompositeEditorPanel extends JPanel
model.notifyCompositeChanged(); model.notifyCompositeChanged();
}); });
Component c = provider.getComponent(); Component c = provider.getComponent();
Window w = SwingUtilities.windowForComponent(c); DockingWindowManager.showDialog(c, dlg);
DockingWindowManager.showDialog(w, dlg, c);
return true; return true;
} }
} }

View file

@ -16,10 +16,8 @@
package ghidra.app.plugin.core.compositeeditor; package ghidra.app.plugin.core.compositeeditor;
import java.awt.Component; import java.awt.Component;
import java.awt.Window;
import javax.swing.JTable; import javax.swing.JTable;
import javax.swing.SwingUtilities;
import docking.ActionContext; import docking.ActionContext;
import docking.DockingWindowManager; import docking.DockingWindowManager;
@ -77,8 +75,7 @@ public class EditBitFieldAction extends CompositeEditorTableAction {
provider.dtmService, dtComponent.getOrdinal(), provider.dtmService, dtComponent.getOrdinal(),
ordinal -> refreshTableAndSelection(editorModel, ordinal)); ordinal -> refreshTableAndSelection(editorModel, ordinal));
Component c = provider.getComponent(); Component c = provider.getComponent();
Window w = SwingUtilities.windowForComponent(c); DockingWindowManager.showDialog(c, dlg);
DockingWindowManager.showDialog(w, dlg, c);
requestTableFocus(); requestTableFocus();
} }

View file

@ -15,7 +15,6 @@
*/ */
package ghidra.app.plugin.core.datamgr.actions; package ghidra.app.plugin.core.datamgr.actions;
import java.awt.Component;
import java.io.*; import java.io.*;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.util.*; import java.util.*;
@ -138,7 +137,7 @@ public class ExportToHeaderAction extends DockingAction {
if (!list.isEmpty()) { if (!list.isEmpty()) {
list.add(0, new DefaultAnnotationHandler()); list.add(0, new DefaultAnnotationHandler());
AnnotationHandlerDialog dlg = new AnnotationHandlerDialog(list); AnnotationHandlerDialog dlg = new AnnotationHandlerDialog(list);
plugin.getTool().showDialog(dlg, (Component) null); plugin.getTool().showDialog(dlg);
if (!dlg.wasSuccessful()) { if (!dlg.wasSuccessful()) {
return; return;
} }
@ -210,8 +209,7 @@ public class ExportToHeaderAction extends DockingAction {
finally { finally {
writer.close(); writer.close();
} }
plugin.getTool() plugin.getTool().setStatusInfo(
.setStatusInfo(
"Successfully exported data type(s) to " + file.getAbsolutePath()); "Successfully exported data type(s) to " + file.getAbsolutePath());
} }
catch (CancelledException e) { catch (CancelledException e) {

View file

@ -35,7 +35,7 @@ import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.util.HelpTopics; import ghidra.app.util.HelpTopics;
import ghidra.framework.main.FrontEndable; import ghidra.framework.main.FrontEndable;
import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.*; import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.util.DefaultLanguageService; import ghidra.program.util.DefaultLanguageService;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
@ -102,7 +102,7 @@ public class ProcessorListPlugin extends Plugin implements FrontEndable {
if (dialogProvider == null) { if (dialogProvider == null) {
dialogProvider = new ProcessorListDialogProvider(); dialogProvider = new ProcessorListDialogProvider();
} }
tool.showDialog(dialogProvider, tool.getToolFrame()); tool.showDialog(dialogProvider);
} }
private void copy(boolean asHtml) { private void copy(boolean asHtml) {

View file

@ -15,7 +15,6 @@
*/ */
package ghidra.app.plugin.core.register; package ghidra.app.plugin.core.register;
import java.awt.Component;
import java.awt.event.*; import java.awt.event.*;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
@ -290,7 +289,7 @@ public class RegisterPlugin extends ProgramPlugin {
SetRegisterValueDialog dialog = SetRegisterValueDialog dialog =
new SetRegisterValueDialog(context.getProgram(), registers, register, addrSet, false); new SetRegisterValueDialog(context.getProgram(), registers, register, addrSet, false);
tool.showDialog(dialog, (Component) null); tool.showDialog(dialog);
Register selectedRegister = dialog.getSelectRegister(); Register selectedRegister = dialog.getSelectRegister();
if (selectedRegister != null) { if (selectedRegister != null) {
@ -304,7 +303,7 @@ public class RegisterPlugin extends ProgramPlugin {
SetRegisterValueDialog dialog = SetRegisterValueDialog dialog =
new SetRegisterValueDialog(context.getProgram(), registers, register, addrSet, true); new SetRegisterValueDialog(context.getProgram(), registers, register, addrSet, true);
tool.showDialog(dialog, (Component) null); tool.showDialog(dialog);
BigInteger value = dialog.getRegisterValue(); BigInteger value = dialog.getRegisterValue();
Register selectedRegister = dialog.getSelectRegister(); Register selectedRegister = dialog.getSelectRegister();

View file

@ -24,7 +24,8 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.swing.*; import javax.swing.*;
import javax.swing.table.TableCellRenderer; import javax.swing.table.TableCellRenderer;
import docking.*; import docking.ActionContext;
import docking.DialogComponentProvider;
import docking.action.DockingAction; import docking.action.DockingAction;
import docking.widgets.table.*; import docking.widgets.table.*;
import docking.widgets.table.threaded.ThreadedTableModel; import docking.widgets.table.threaded.ThreadedTableModel;
@ -181,8 +182,7 @@ public class TableChooserDialog extends DialogComponentProvider
} }
public void show() { public void show() {
DockingWindowManager manager = DockingWindowManager.getActiveInstance(); tool.showDialog(this);
tool.showDialog(this, manager.getMainWindow());
} }
@Override @Override

View file

@ -358,7 +358,7 @@ public class SetEquateDialog extends DialogComponentProvider {
result = CANCELED; result = CANCELED;
overwriteExistingEquates.setVisible(true); overwriteExistingEquates.setVisible(true);
setTitle("Set Equate"); setTitle("Set Equate");
tool.showDialog(this, (Component) null); tool.showDialog(this);
return result; return result;
} }
@ -374,7 +374,7 @@ public class SetEquateDialog extends DialogComponentProvider {
overwriteExistingEquates.setVisible(false); overwriteExistingEquates.setVisible(false);
overwriteExistingEquates.setEnabled(false); overwriteExistingEquates.setEnabled(false);
setTitle("Rename Equate"); setTitle("Rename Equate");
tool.showDialog(this, (Component) null); tool.showDialog(this);
return result; return result;
} }

View file

@ -37,7 +37,7 @@ public class TutorialScreenShotGenerator extends AbstractScreenShotGenerator {
@Deprecated @Deprecated
public void showImage() { public void showImage() {
ImageDialogProvider dialog = new ImageDialogProvider(null, null, image); ImageDialogProvider dialog = new ImageDialogProvider(null, null, image);
tool.showDialog(dialog, tool.getToolFrame()); tool.showDialog(dialog);
} }
protected void saveToFile(String absolutePathToImage) { protected void saveToFile(String absolutePathToImage) {

View file

@ -332,8 +332,7 @@ public class FGController implements ProgramLocationListener, ProgramSelectionLi
} }
private boolean shouldSaveVertexChanges() { private boolean shouldSaveVertexChanges() {
return functionGraphOptions return functionGraphOptions.getNavigationHistoryChoice() == NavigationHistoryChoices.VERTEX_CHANGES;
.getNavigationHistoryChoice() == NavigationHistoryChoices.VERTEX_CHANGES;
} }
@Override @Override
@ -694,14 +693,16 @@ public class FGController implements ProgramLocationListener, ProgramSelectionLi
vertex = view.getEntryPointVertex(); vertex = view.getEntryPointVertex();
} }
PluginTool tool = plugin.getTool();
SetFormatDialogComponentProvider setFormatDialog = SetFormatDialogComponentProvider setFormatDialog =
new SetFormatDialogComponentProvider(getDefaultFormatManager(), minimalFormatManager, new SetFormatDialogComponentProvider(getDefaultFormatManager(), minimalFormatManager,
plugin.getTool(), provider.getProgram(), vertex.getAddresses()); tool, provider.getProgram(), vertex.getAddresses());
plugin.getTool().showDialogOnActiveWindow(setFormatDialog); tool.showDialog(setFormatDialog);
FormatManager newFormatManager = setFormatDialog.getNewFormatManager(); FormatManager newFormatManager = setFormatDialog.getNewFormatManager();
if (newFormatManager == null) { if (newFormatManager == null) {
return; return;
} }
SaveState saveState = new SaveState(); SaveState saveState = new SaveState();
newFormatManager.saveState(saveState); newFormatManager.saveState(saveState);
minimalFormatManager.readState(saveState); minimalFormatManager.readState(saveState);

View file

@ -32,7 +32,7 @@ public class DiffApply2Test extends DiffApplyTestAdapter {
@Test @Test
public void testApplyDiffsNextActionFirst() throws Exception { public void testApplyDiffsNextActionFirst() throws Exception {
openDiff(diffTestP1, diffTestP2); openDiff(diffTestP1, diffTestP2);
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Memory Differs", 2000); JDialog dialog = waitForJDialog("Memory Differs");
pressButtonByText(dialog, "OK"); pressButtonByText(dialog, "OK");
waitForPostedSwingRunnables(); waitForPostedSwingRunnables();
showApplySettings(); showApplySettings();
@ -55,7 +55,7 @@ public class DiffApply2Test extends DiffApplyTestAdapter {
@Test @Test
public void testApplyDiffsNextActionMiddle() throws Exception { public void testApplyDiffsNextActionMiddle() throws Exception {
openDiff(diffTestP1, diffTestP2); openDiff(diffTestP1, diffTestP2);
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Memory Differs", 2000); JDialog dialog = waitForJDialog("Memory Differs");
pressButtonByText(dialog, "OK"); pressButtonByText(dialog, "OK");
waitForPostedSwingRunnables(); waitForPostedSwingRunnables();
showApplySettings(); showApplySettings();
@ -79,7 +79,7 @@ public class DiffApply2Test extends DiffApplyTestAdapter {
@Test @Test
public void testApplyDiffsNextActionLast() throws Exception { public void testApplyDiffsNextActionLast() throws Exception {
openDiff(diffTestP1, diffTestP2); openDiff(diffTestP1, diffTestP2);
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Memory Differs", 2000); JDialog dialog = waitForJDialog("Memory Differs");
pressButtonByText(dialog, "OK"); pressButtonByText(dialog, "OK");
waitForPostedSwingRunnables(); waitForPostedSwingRunnables();
showApplySettings(); showApplySettings();
@ -93,7 +93,7 @@ public class DiffApply2Test extends DiffApplyTestAdapter {
@Test @Test
public void testIgnoreEntireBlock() throws Exception { public void testIgnoreEntireBlock() throws Exception {
openDiff(diffTestP1, diffTestP2); openDiff(diffTestP1, diffTestP2);
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Memory Differs", 2000); JDialog dialog = waitForJDialog("Memory Differs");
pressButtonByText(dialog, "OK"); pressButtonByText(dialog, "OK");
waitForPostedSwingRunnables(); waitForPostedSwingRunnables();
showApplySettings(); showApplySettings();
@ -136,7 +136,7 @@ public class DiffApply2Test extends DiffApplyTestAdapter {
@Test @Test
public void testIgnorePartialBlock() throws Exception { public void testIgnorePartialBlock() throws Exception {
openDiff(diffTestP1, diffTestP2); openDiff(diffTestP1, diffTestP2);
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Memory Differs", 2000); JDialog dialog = waitForJDialog("Memory Differs");
pressButtonByText(dialog, "OK"); pressButtonByText(dialog, "OK");
waitForPostedSwingRunnables(); waitForPostedSwingRunnables();
showApplySettings(); showApplySettings();
@ -163,7 +163,7 @@ public class DiffApply2Test extends DiffApplyTestAdapter {
@Test @Test
public void testUndoRedo() throws Exception { public void testUndoRedo() throws Exception {
openDiff(diffTestP1, diffTestP2); openDiff(diffTestP1, diffTestP2);
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Memory Differs", 2000); JDialog dialog = waitForJDialog("Memory Differs");
pressButtonByText(dialog, "OK"); pressButtonByText(dialog, "OK");
waitForPostedSwingRunnables(); waitForPostedSwingRunnables();
showApplySettings(); showApplySettings();

View file

@ -361,6 +361,17 @@ class DetachedWindowNode extends WindowNode {
} }
}); });
adjustBounds();
window.setBounds(bounds);
window.setVisible(true);
}
/**
* Ensures the bounds of this window have a valid location and size
*/
private void adjustBounds() {
if (bounds.height == 0 || bounds.width == 0) { if (bounds.height == 0 || bounds.width == 0) {
window.pack(); window.pack();
Dimension d = window.getSize(); Dimension d = window.getSize();
@ -368,9 +379,14 @@ class DetachedWindowNode extends WindowNode {
bounds.width = d.width; bounds.width = d.width;
} }
WindowUtilities.ensureOnScreen(winMgr.getRootFrame(), bounds); Window activeWindow = winMgr.getActiveWindow();
window.setBounds(bounds); Point p = bounds.getLocation();
window.setVisible(true); if (p.x == 0 && p.y == 0) {
p = WindowUtilities.centerOnScreen(activeWindow, bounds.getSize());
bounds.setLocation(p);
}
WindowUtilities.ensureOnScreen(activeWindow, bounds);
} }
private JFrame createFrame() { private JFrame createFrame() {
@ -455,10 +471,6 @@ class DetachedWindowNode extends WindowNode {
((RootNode) parent).notifyWindowChanged(this); ((RootNode) parent).notifyWindowChanged(this);
} }
/**
* Releases all resources and makes this node unusable.
*
*/
@Override @Override
void dispose() { void dispose() {
if (dropTargetHandler != null) { if (dropTargetHandler != null) {
@ -516,10 +528,8 @@ class DetachedWindowNode extends WindowNode {
if (window != null) { if (window != null) {
bounds = window.getBounds(); bounds = window.getBounds();
} }
Element root = new Element("WINDOW_NODE"); Element root = new Element("WINDOW_NODE");
// if (title != null) {
// root.setAttribute("TITLE", title);
// }
root.setAttribute("X_POS", "" + bounds.x); root.setAttribute("X_POS", "" + bounds.x);
root.setAttribute("Y_POS", "" + bounds.y); root.setAttribute("Y_POS", "" + bounds.y);
root.setAttribute("WIDTH", "" + bounds.width); root.setAttribute("WIDTH", "" + bounds.width);
@ -539,7 +549,7 @@ class DetachedWindowNode extends WindowNode {
/** /**
* Set the status text * Set the status text
* @param text * @param text the text
*/ */
public void setStatusText(String text) { public void setStatusText(String text) {
if (statusBar != null) { if (statusBar != null) {

View file

@ -20,25 +20,38 @@ import javax.swing.JFrame;
import ghidra.util.bean.GGlassPane; import ghidra.util.bean.GGlassPane;
/** /**
* Base JFrame to be used by the root window and detached windows if they are using frames * Base frame used by the root window and detached windows
*
* Also fixed:
* <ol>
* <li>Swing problem of setting bounds before the frame is visible causes slow paints
* if the bounds position is not on the primary display, </li>
* </ol>
*/ */
public class DockingFrame extends JFrame { public class DockingFrame extends JFrame {
private boolean isTransient;
public DockingFrame(String name) { public DockingFrame(String name) {
super(name); super(name);
GGlassPane ghidraGlassPane = new GGlassPane(); GGlassPane ghidraGlassPane = new GGlassPane();
setGlassPane(ghidraGlassPane); setGlassPane(ghidraGlassPane);
ghidraGlassPane.setVisible(true); ghidraGlassPane.setVisible(true);
} }
/**
* Marks this frame as transient. A transient frame is one that is show temporarily.
*/
public void setTransient() {
this.isTransient = true;
}
/**
* REturns whether this frame is transient. A transient frame is one that is show temporarily.
* @return true if transient
*/
public boolean isTransient() {
return isTransient;
}
@Override @Override
public String toString() { public String toString() {
return getTitle(); return getTitle() + (isTransient ? " - transient" : "") + " (" +
System.identityHashCode(this) + ")";
} }
} }

View file

@ -131,8 +131,8 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
* @param hasStatusBar if true a status bar will be created for the main window * @param hasStatusBar if true a status bar will be created for the main window
* @param factory the drop target factory * @param factory the drop target factory
*/ */
public DockingWindowManager(Tool tool, List<Image> images, boolean modal, public DockingWindowManager(Tool tool, List<Image> images, boolean modal, boolean isDocking,
boolean isDocking, boolean hasStatusBar, DropTargetFactory factory) { boolean hasStatusBar, DropTargetFactory factory) {
KeyBindingOverrideKeyEventDispatcher.install(); KeyBindingOverrideKeyEventDispatcher.install();
@ -1189,8 +1189,8 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
for (ComponentPlaceholder placeholder : placeholders) { for (ComponentPlaceholder placeholder : placeholders) {
ComponentProvider provider = placeholder.getProvider(); ComponentProvider provider = placeholder.getProvider();
boolean isTransient = provider.isTransient(); boolean isTransient = provider.isTransient();
actionList.add( actionList
new ShowComponentAction(this, placeholder, subMenuName, isTransient)); .add(new ShowComponentAction(this, placeholder, subMenuName, isTransient));
} }
if (subMenuName != null) { if (subMenuName != null) {
@ -1649,44 +1649,13 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
return false; return false;
} }
/**
* Shows the dialog using the tool's currently active window as a parent
*
* @param dialogComponent the DialogComponentProvider object to be shown in a dialog
*/
public static void showDialogOnActiveWindow(DialogComponentProvider dialogComponent) {
showDialog(null, dialogComponent, (Component) null);
}
/** /**
* Shows the dialog using the tool's currently active window as a parent * Shows the dialog using the tool's currently active window as a parent
* *
* @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) {
showDialogOnActiveWindow(dialogComponent); showDialog(null, dialogComponent, (Component) null);
}
/**
* Shows the dialog using the given component's parent frame, centering the dialog
* on the given component
*
* @param dialogComponent the DialogComponentProvider object to be shown in a dialog.
* @param centeredOnComponent the component on which to center the dialog.
*/
public static void showDialog(DialogComponentProvider dialogComponent,
Component centeredOnComponent) {
Window parent = null;
Component c = centeredOnComponent;
while (c != null) {
if ((c instanceof Frame) || (c instanceof Dialog)) {
parent = (Window) c;
break;
}
c = c.getParent();
}
showDialog(parent, dialogComponent, centeredOnComponent);
} }
/** /**
@ -1720,10 +1689,14 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
return; return;
} }
Window updatedParent = getParentWindow(parent); Window bestParent = getParentWindow(parent);
Component updatedCenter = getCenterOnComponent(centeredOnComponent); Component bestCenter = getCenterOnComponent(bestParent, centeredOnComponent);
DockingDialog dialog =
DockingDialog.createDialog(updatedParent, provider, updatedCenter); // 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); dialog.setVisible(true);
}; };
@ -1735,17 +1708,6 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
} }
} }
private static Component getCenterOnComponent(Component centeredOnComponent) {
if (centeredOnComponent != null) {
return centeredOnComponent;
}
// by default, prefer to center over the active window
Window activeWindow = getActiveNonTransientWindow();
return activeWindow;
}
/** /**
* Shows the dialog using the given parent component to find a parent window and to * Shows the dialog using the given parent component to find a parent window and to
* position the dialog. If a Window can be found containing the given component, it * position the dialog. If a Window can be found containing the given component, it
@ -1773,10 +1735,53 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
*/ */
public static void showDialog(Window parent, DialogComponentProvider dialogComponent, public static void showDialog(Window parent, DialogComponentProvider dialogComponent,
Component centeredOnComponent) { Component centeredOnComponent) {
doShowDialog(dialogComponent, parent, centeredOnComponent); doShowDialog(dialogComponent, parent, centeredOnComponent);
} }
private static Window ensureParentHierarchy(Window parent, Component component) {
if (SwingUtilities.isDescendingFrom(parent, component)) {
return parent;
}
return getParentWindow(component);
}
private static Component getCenterOnComponent(Window parent, Component centeredOnComponent) {
/*
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
*/
Component bestComponent = centeredOnComponent;
if (SwingUtilities.isDescendingFrom(parent, bestComponent)) {
return bestComponent;
}
// by default, prefer to center over the active window
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
Window activeWindow = kfm.getActiveWindow();
bestComponent = activeWindow;
if (SwingUtilities.isDescendingFrom(parent, bestComponent)) {
return bestComponent;
}
// 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(parent);
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 bestComponent;
}
// 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 Window getParentWindow(Component parent) { private static Window getParentWindow(Component parent) {
/* /*
@ -1841,7 +1846,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) { if (c instanceof Frame && isNonTransientWindow(c)) {
return (Window) c; return (Window) c;
} }
c = c.getParent(); c = c.getParent();
@ -1850,6 +1855,15 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
} }
private static boolean isNonTransientWindow(Component c) { private static boolean isNonTransientWindow(Component c) {
if (c == null || !c.isShowing()) {
return false;
}
if (c instanceof DockingFrame) {
return !((DockingFrame) c).isTransient();
}
if (c instanceof DockingDialog) { if (c instanceof DockingDialog) {
DockingDialog d = (DockingDialog) c; DockingDialog d = (DockingDialog) c;
DialogComponentProvider provider = d.getComponent(); DialogComponentProvider provider = d.getComponent();
@ -1857,9 +1871,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
return false; // we have seen this in testing return false; // we have seen this in testing
} }
if (provider.isTransient()) { return !provider.isTransient();
return false;
}
} }
return (c instanceof Window); return (c instanceof Window);
@ -1868,23 +1880,22 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
private static Window getActiveNonTransientWindow() { private static Window getActiveNonTransientWindow() {
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
Window activeWindow = kfm.getActiveWindow(); Window bestWindow = kfm.getActiveWindow();
if (!(activeWindow instanceof DockingDialog)) { if (bestWindow instanceof DockingDialog) {
return activeWindow;
}
// We do not want Task Dialogs becoming parents, as they will get closed when the // We do not want Task Dialogs becoming parents, as they will get closed when the
// task is finished, closing any other child dialogs, which means that dialogs such // task is finished, closing any other child dialogs, which means that dialogs such
// as message dialogs will too be closed // as message dialogs will too be closed
DockingDialog d = (DockingDialog) activeWindow; DockingDialog d = (DockingDialog) bestWindow;
Window ancestor = SwingUtilities.getWindowAncestor(d); if (isNonTransientWindow(d)) {
if (d.isShowing() && isNonTransientWindow(d)) {
return d; return d;
} }
// The active window is not a suitable parent; try its parent // The active window is not a suitable parent; try its parent
if (ancestor.isShowing() && isNonTransientWindow(ancestor)) { bestWindow = SwingUtilities.getWindowAncestor(d);
return ancestor; }
if (isNonTransientWindow(bestWindow)) {
return bestWindow;
} }
return null; return null;

View file

@ -40,7 +40,7 @@ public class SplashScreen extends JWindow {
private static final Color DEFAULT_BACKGROUND_COLOR = new Color(243, 250, 255); private static final Color DEFAULT_BACKGROUND_COLOR = new Color(243, 250, 255);
private static SplashScreen splashWindow; // splash window displayed while ghidra is coming up private static SplashScreen splashWindow; // splash window displayed while ghidra is coming up
private static JFrame hiddenFrame; private static DockingFrame hiddenFrame;
private static JLabel statusLabel; private static JLabel statusLabel;
private static Timer hideSplashWindowTimer; private static Timer hideSplashWindowTimer;
@ -250,6 +250,7 @@ public class SplashScreen extends JWindow {
List<Image> list = ApplicationInformationDisplayFactory.getWindowIcons(); List<Image> list = ApplicationInformationDisplayFactory.getWindowIcons();
hiddenFrame.setIconImages(list); hiddenFrame.setIconImages(list);
hiddenFrame.setUndecorated(true); hiddenFrame.setUndecorated(true);
hiddenFrame.setTransient();
} }
return hiddenFrame; return hiddenFrame;
} }
@ -279,10 +280,6 @@ public class SplashScreen extends JWindow {
updateStatus(status); updateStatus(status);
} }
/**
* Update the status label on the splash screen window.
* @param status
*/
private static void updateStatus(String status) { private static void updateStatus(String status) {
statusLabel.setText(status); statusLabel.setText(status);
} }

View file

@ -125,8 +125,8 @@ public class TaskLauncher {
* A convenience method to directly run a {@link Runnable} in a separate * A convenience method to directly run a {@link Runnable} in a separate
* thread as a {@link Task}, displaying a non-modal progress dialog. * thread as a {@link Task}, displaying a non-modal progress dialog.
* *
* <p>This modal will be launched immediately, without delay. Typically this launcher will * <p>This modal will be launched immediately, without delay. Typically the launcher will
* delay showing the modal dialog in order to prevent the dialog from being show, just * delay showing the modal dialog in order to prevent the dialog from being shown, just
* to have it immediately go away. If you desire this default behavior, then do not use * to have it immediately go away. If you desire this default behavior, then do not use
* this convenience method. * this convenience method.
* *

View file

@ -1,50 +0,0 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.util.task;
import ghidra.util.Msg;
import java.lang.reflect.InvocationTargetException;
import javax.swing.SwingUtilities;
/**
* A task that will simply invoke the given runnable later in the Swing thread. This class is
* useful for executing long running tasks in the swing thread while using the
* {@link TaskLauncher} to show a modal dialog.
*/
public class InvokeInSwingTask extends Task {
private final Runnable runnable;
public InvokeInSwingTask( String title, Runnable runnable ) {
super( title, false, false, true );
this.runnable = runnable;
}
@Override
public void run( TaskMonitor monitor ) {
try {
SwingUtilities.invokeAndWait( runnable );
} catch (InterruptedException e) {
Msg.showError(runnable, null, "Task Error", "Task interrupted: " + getTaskTitle(), e);
} catch (InvocationTargetException e) {
Msg.showError(runnable, null, "Task Error", "Unexpected task exception: " + getTaskTitle(), e);
}
}
}

View file

@ -37,7 +37,6 @@ import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.store.LockException; import ghidra.framework.store.LockException;
import ghidra.util.*; import ghidra.util.*;
import ghidra.util.exception.NotFoundException; import ghidra.util.exception.NotFoundException;
import ghidra.util.task.InvokeInSwingTask;
import ghidra.util.task.TaskLauncher; import ghidra.util.task.TaskLauncher;
import resources.ResourceManager; import resources.ResourceManager;
@ -280,8 +279,7 @@ class FileActionManager {
*/ */
final boolean openProject(ProjectLocator projectLocator) { final boolean openProject(ProjectLocator projectLocator) {
OpenTaskRunnable openRunnable = new OpenTaskRunnable(projectLocator); OpenTaskRunnable openRunnable = new OpenTaskRunnable(projectLocator);
InvokeInSwingTask task = new InvokeInSwingTask("Opening Project", openRunnable); TaskLauncher.launchModal("Opening Project", () -> Swing.runNow(openRunnable));
new TaskLauncher(task, tool.getToolFrame(), 0);
return openRunnable.getResult(); return openRunnable.getResult();
} }

View file

@ -765,7 +765,7 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
if (logProvider == null) { if (logProvider == null) {
logProvider = new LogComponentProvider(this, logFile); logProvider = new LogComponentProvider(this, logFile);
showDialog(logProvider, getToolFrame()); showDialog(logProvider);
return; return;
} }

View file

@ -287,7 +287,7 @@ class RepositoryChooser extends DialogComponentProvider {
init(initURL); init(initURL);
tool.showDialog(this, tool.getToolFrame()); tool.showDialog(this);
if (!okPressed) { if (!okPressed) {
return null; return null;

View file

@ -25,7 +25,6 @@ import javax.swing.*;
import javax.swing.border.TitledBorder; import javax.swing.border.TitledBorder;
import docking.DialogComponentProvider; import docking.DialogComponentProvider;
import docking.DockingWindowManager;
import docking.options.editor.ButtonPanelFactory; import docking.options.editor.ButtonPanelFactory;
import docking.widgets.checkbox.GCheckBox; import docking.widgets.checkbox.GCheckBox;
import docking.widgets.list.ListPanel; import docking.widgets.list.ListPanel;
@ -120,7 +119,7 @@ public class SaveDataDialog extends DialogComponentProvider {
initList(); initList();
if (!files.isEmpty()) { if (!files.isEmpty()) {
tool.showDialog(this, DockingWindowManager.getActiveInstance().getActiveComponent()); tool.showDialog(this);
} }
else { else {
operationCompleted = true; operationCompleted = true;
@ -238,8 +237,8 @@ public class SaveDataDialog extends DialogComponentProvider {
*/ */
private void deselectAll() { private void deselectAll() {
clearStatusText(); clearStatusText();
for (int i = 0; i < checkboxes.length; i++) { for (GCheckBox checkboxe : checkboxes) {
checkboxes[i].setSelected(false); checkboxe.setSelected(false);
} }
listPanel.repaint(); listPanel.repaint();
} }
@ -359,13 +358,13 @@ public class SaveDataDialog extends DialogComponentProvider {
@Override @Override
public void run(TaskMonitor monitor) { public void run(TaskMonitor monitor) {
try { try {
for (int i = 0; i < domainFiles.length; i++) { for (DomainFile domainFile : domainFiles) {
if (monitor.isCancelled()) { if (monitor.isCancelled()) {
break; break;
} }
monitor.setProgress(0); monitor.setProgress(0);
monitor.setMessage("Saving " + domainFiles[i].getName()); monitor.setMessage("Saving " + domainFile.getName());
domainFiles[i].save(monitor); domainFile.save(monitor);
} }
operationCompleted = !monitor.isCancelled(); operationCompleted = !monitor.isCancelled();

View file

@ -267,7 +267,7 @@ class WorkspacePanel extends JPanel implements WorkspaceChangeListener {
// query the user for the name of the workspace // query the user for the name of the workspace
InputDialog nameDialog = new InputDialog("Create New Workspace", "Workspace Name", InputDialog nameDialog = new InputDialog("Create New Workspace", "Workspace Name",
ToolManager.DEFAULT_WORKSPACE_NAME); ToolManager.DEFAULT_WORKSPACE_NAME);
plugin.getTool().showDialog(nameDialog, (Component) null); plugin.getTool().showDialog(nameDialog);
if (nameDialog.isCanceled()) { if (nameDialog.isCanceled()) {
return; // user canceled return; // user canceled
} }
@ -342,7 +342,7 @@ class WorkspacePanel extends JPanel implements WorkspaceChangeListener {
String workspaceName = activeWorkspace.getName(); String workspaceName = activeWorkspace.getName();
InputDialog nameDialog = InputDialog nameDialog =
new InputDialog("Rename Workspace", "Workspace Name", workspaceName); new InputDialog("Rename Workspace", "Workspace Name", workspaceName);
plugin.getTool().showDialog(nameDialog, (Component) null); plugin.getTool().showDialog(nameDialog);
if (nameDialog.isCanceled()) { if (nameDialog.isCanceled()) {
return; return;
} }

View file

@ -36,7 +36,6 @@ import docking.actions.PopupActionProvider;
import docking.actions.ToolActions; import docking.actions.ToolActions;
import docking.framework.AboutDialog; import docking.framework.AboutDialog;
import docking.framework.ApplicationInformationDisplayFactory; import docking.framework.ApplicationInformationDisplayFactory;
import docking.framework.SplashScreen;
import docking.help.Help; import docking.help.Help;
import docking.help.HelpService; import docking.help.HelpService;
import docking.tool.ToolConstants; import docking.tool.ToolConstants;
@ -552,7 +551,6 @@ public abstract class PluginTool extends AbstractDockingTool {
else { else {
fullName = toolName + "(" + instanceName + ")"; fullName = toolName + "(" + instanceName + ")";
} }
SplashScreen.updateSplashScreenStatus("Loading " + fullName + " ...");
restoreOptionsFromXml(root); restoreOptionsFromXml(root);
setDefaultOptionValues(); setDefaultOptionValues();
@ -968,8 +966,8 @@ public abstract class PluginTool extends AbstractDockingTool {
saveAsAction.setMenuBarData(menuData); saveAsAction.setMenuBarData(menuData);
saveAsAction.setEnabled(true); saveAsAction.setEnabled(true);
saveAsAction saveAsAction.setHelpLocation(
.setHelpLocation(new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Tool_Changes")); new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Tool_Changes"));
addAction(saveAction); addAction(saveAction);
addAction(saveAsAction); addAction(saveAsAction);
@ -994,8 +992,8 @@ public abstract class PluginTool extends AbstractDockingTool {
new String[] { ToolConstants.MENU_FILE, exportPullright, "Export Tool..." }); new String[] { ToolConstants.MENU_FILE, exportPullright, "Export Tool..." });
menuData.setMenuSubGroup(Integer.toString(subGroup++)); menuData.setMenuSubGroup(Integer.toString(subGroup++));
exportToolAction.setMenuBarData(menuData); exportToolAction.setMenuBarData(menuData);
exportToolAction exportToolAction.setHelpLocation(
.setHelpLocation(new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Export_Tool")); new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Export_Tool"));
addAction(exportToolAction); addAction(exportToolAction);
DockingAction exportDefautToolAction = DockingAction exportDefautToolAction =
@ -1418,9 +1416,12 @@ public abstract class PluginTool extends AbstractDockingTool {
* time the dialog is shown. * time the dialog is shown.
* *
* @param dialogComponent the DialogComponentProvider object to be shown in a dialog. * @param dialogComponent the DialogComponentProvider object to be shown in a dialog.
*
* @deprecated dialogs are now always shown over the active window when possible
*/ */
@Deprecated
public void showDialogOnActiveWindow(DialogComponentProvider dialogComponent) { public void showDialogOnActiveWindow(DialogComponentProvider dialogComponent) {
DockingWindowManager.showDialogOnActiveWindow(dialogComponent); DockingWindowManager.showDialog(dialogComponent);
} }
/** /**