mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-628 - Dialogs - fixed issue of non-modal dialog appearing over modal
dialog; marked many input dialogs as transient
This commit is contained in:
parent
e983784753
commit
a20d77a27b
16 changed files with 67 additions and 42 deletions
|
@ -1766,41 +1766,45 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
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;
|
||||
if (SwingUtilities.isDescendingFrom(parent, centeredOnComponent)) {
|
||||
return centeredOnComponent;
|
||||
}
|
||||
|
||||
// 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;
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
|
||||
//
|
||||
// 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);
|
||||
//
|
||||
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 bestComponent;
|
||||
return centeredOnComponent;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
/*
|
||||
Note: Which window should be the parent of the dialog when the user does not specify?
|
||||
|
||||
|
||||
Some use cases; a dialog is shown from:
|
||||
1) A toolbar action
|
||||
2) A component provider's code
|
||||
|
@ -1808,7 +1812,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
4) A background thread
|
||||
5) The help window
|
||||
6) A modal password dialog appears over the splash screen
|
||||
|
||||
|
||||
It seems like the parent should be the active window for 1-2.
|
||||
Case 3 should probably use the window of the dialog provider.
|
||||
Case 4 should probably use the main tool frame, since the user may be
|
||||
|
@ -1816,12 +1820,12 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
active window, we can default to the tool's frame.
|
||||
Case 5 should use the help window.
|
||||
Case 6 should use the splash screen as the parent.
|
||||
|
||||
|
||||
We have not yet solidified how we should parent. This documentation is meant to
|
||||
move us towards clarity as we find Use Cases that don't make sense. (Once we
|
||||
finalize our understanding, we should update the javadoc to list exactly where
|
||||
the given Dialog Component will be shown.)
|
||||
|
||||
|
||||
Use Case
|
||||
A -The user presses an action on a toolbar from a window on screen 1, while the
|
||||
main tool frame is on screen 2. We want the popup window to appear on screen
|
||||
|
@ -1833,11 +1837,16 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
-modal - Java handles this correctly, allowing the new dialog to be used
|
||||
-non-modal - Java prevents the non-modal from being editing if not parented
|
||||
correctly
|
||||
|
||||
|
||||
For now, the easiest mental model to use is to always prefer the active window so
|
||||
that a dialog will appear in the user's view. If we find a case where this is
|
||||
D -The user runs a script that shows an input dialog before the non-modal script
|
||||
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.
|
||||
|
||||
|
||||
For now, the easiest mental model to use is to always prefer the active non-transient
|
||||
window so that a dialog will appear in the user's view. If we find a case where this is
|
||||
not desired, then document it here.
|
||||
|
||||
*/
|
||||
|
||||
//
|
||||
|
|
|
@ -174,6 +174,7 @@ public class OptionDialog extends DialogComponentProvider {
|
|||
protected OptionDialog(String title, String message, String option1, String option2,
|
||||
int messageType, Icon icon, boolean addCancel) {
|
||||
super(title, true, false, true, false);
|
||||
setTransient(true);
|
||||
buildMainPanel(message, messageType, icon, null);
|
||||
buildButtons(toList(option1, option2), addCancel, null);
|
||||
}
|
||||
|
@ -194,6 +195,7 @@ public class OptionDialog extends DialogComponentProvider {
|
|||
protected OptionDialog(String title, String message, String option1, String option2,
|
||||
int messageType, Icon icon, boolean addCancel, String defaultButtonName) {
|
||||
super(title, true, false, true, false);
|
||||
setTransient(true);
|
||||
buildMainPanel(message, messageType, icon, null);
|
||||
buildButtons(toList(option1, option2), addCancel, defaultButtonName);
|
||||
}
|
||||
|
@ -233,6 +235,7 @@ public class OptionDialog extends DialogComponentProvider {
|
|||
protected OptionDialog(String title, String message, String option1, String option2,
|
||||
String option3, int messageType, Icon icon, boolean addCancel) {
|
||||
super(title, true, false, true, false);
|
||||
setTransient(true);
|
||||
buildMainPanel(message, messageType, icon, null);
|
||||
buildButtons(toList(option1, option2, option3), addCancel, null);
|
||||
}
|
||||
|
@ -240,6 +243,7 @@ public class OptionDialog extends DialogComponentProvider {
|
|||
OptionDialog(String title, String message, int messageType, Icon icon, boolean addCancelButton,
|
||||
DialogRememberOption savedDialogChoice, List<String> options, String defaultOption) {
|
||||
super(title, true, false, true, false);
|
||||
setTransient(true);
|
||||
buildMainPanel(message, messageType, icon, savedDialogChoice);
|
||||
buildButtons(options, addCancelButton, defaultOption);
|
||||
}
|
||||
|
@ -256,6 +260,7 @@ public class OptionDialog extends DialogComponentProvider {
|
|||
|
||||
private void buildMainPanel(String message, int messageType, Icon icon,
|
||||
DialogRememberOption rememberOptionChoice) {
|
||||
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@ public abstract class AbstractNumberInputDialog extends DialogComponentProvider
|
|||
}
|
||||
this.max = max;
|
||||
|
||||
setTransient(true);
|
||||
addWorkPanel(buildMainPanel(prompt, showAsHex));
|
||||
addOKButton();
|
||||
addCancelButton();
|
||||
|
|
|
@ -53,7 +53,7 @@ public class InputDialog extends DialogComponentProvider {
|
|||
* @param label value to use for the label of the text field
|
||||
*/
|
||||
public InputDialog(String dialogTitle, String label) {
|
||||
this(dialogTitle, new String[] { label }, new String[] { DEFAULT_VALUE }, true, null);
|
||||
this(dialogTitle, new String[] { label }, new String[] { DEFAULT_VALUE }, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,7 +68,7 @@ public class InputDialog extends DialogComponentProvider {
|
|||
* @param initialValue initial value to use for the text field
|
||||
*/
|
||||
public InputDialog(String dialogTitle, String label, String initialValue) {
|
||||
this(dialogTitle, new String[] { label }, new String[] { initialValue }, true, null);
|
||||
this(dialogTitle, new String[] { label }, new String[] { initialValue }, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,7 +85,7 @@ public class InputDialog extends DialogComponentProvider {
|
|||
*/
|
||||
public InputDialog(String dialogTitle, String label, String initialValue,
|
||||
InputDialogListener listener) {
|
||||
this(dialogTitle, new String[] { label }, new String[] { initialValue }, true, listener);
|
||||
this(dialogTitle, new String[] { label }, new String[] { initialValue }, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -101,7 +101,7 @@ public class InputDialog extends DialogComponentProvider {
|
|||
* @param isModal whether or not the dialog is to be modal
|
||||
*/
|
||||
public InputDialog(String dialogTitle, String label, String initialValue, boolean isModal) {
|
||||
this(dialogTitle, new String[] { label }, new String[] { initialValue }, isModal, null);
|
||||
this(dialogTitle, new String[] { label }, new String[] { initialValue }, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -116,7 +116,7 @@ public class InputDialog extends DialogComponentProvider {
|
|||
* @param initialValues initial values to use for the text fields
|
||||
*/
|
||||
public InputDialog(String dialogTitle, String[] labels, String[] initialValues) {
|
||||
this(dialogTitle, labels, initialValues, true, null);
|
||||
this(dialogTitle, labels, initialValues, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -129,12 +129,11 @@ public class InputDialog extends DialogComponentProvider {
|
|||
* @param dialogTitle used as the name of the dialog's title bar
|
||||
* @param labels values to use for the labels of the text fields
|
||||
* @param initialValues initial values to use for the text fields
|
||||
* @param isModal whether or not the dialog is to be modal
|
||||
* @param listener listener that is called when the OK button is hit
|
||||
*/
|
||||
public InputDialog(String dialogTitle, String[] labels, String[] initialValues, boolean isModal,
|
||||
public InputDialog(String dialogTitle, String[] labels, String[] initialValues,
|
||||
InputDialogListener listener) {
|
||||
super(dialogTitle, isModal, (listener != null) /* status */, true /* buttons */,
|
||||
super(dialogTitle, true, (listener != null) /* status */, true /* buttons */,
|
||||
false /* no tasks */);
|
||||
this.listener = listener;
|
||||
|
||||
|
@ -152,8 +151,9 @@ public class InputDialog extends DialogComponentProvider {
|
|||
// put the rest of the dialog together
|
||||
inputLabels = labels;
|
||||
this.initialValues = initialValues;
|
||||
this.addOKButton();
|
||||
this.addCancelButton();
|
||||
setTransient(true);
|
||||
addOKButton();
|
||||
addCancelButton();
|
||||
buildMainPanel();
|
||||
|
||||
if (initialValues != null && initialValues[0] != null && initialValues[0].length() > 0) {
|
||||
|
|
|
@ -55,10 +55,11 @@ public class InputWithChoicesDialog extends DialogComponentProvider {
|
|||
|
||||
super(dialogTitle, true, false, true, false);
|
||||
|
||||
this.addOKButton();
|
||||
this.addCancelButton();
|
||||
this.setRememberSize(false);
|
||||
this.setRememberLocation(false);
|
||||
setTransient(true);
|
||||
addOKButton();
|
||||
addCancelButton();
|
||||
setRememberSize(false);
|
||||
setRememberLocation(false);
|
||||
buildMainPanel(label, optionValues, initialValue, messageIcon);
|
||||
|
||||
setFocusComponent(combo);
|
||||
|
|
|
@ -43,6 +43,7 @@ public class MultiLineInputDialog extends DialogComponentProvider {
|
|||
|
||||
setFocusComponent(inputTextArea);
|
||||
|
||||
setTransient(true);
|
||||
addOKButton();
|
||||
addCancelButton();
|
||||
}
|
||||
|
|
|
@ -148,6 +148,7 @@ public class MultiLineMessageDialog extends DialogComponentProvider {
|
|||
workPanel.add(iconLabel, BorderLayout.WEST);
|
||||
}
|
||||
|
||||
setTransient(true);
|
||||
addWorkPanel(workPanel);
|
||||
addOKButton();
|
||||
|
||||
|
|
|
@ -36,6 +36,8 @@ public class ObjectChooserDialog<T> extends DialogComponentProvider {
|
|||
this.objectClass = objectClass;
|
||||
this.choosableObjects = choosableObjects;
|
||||
this.methodsForColumns = methodsForColumns;
|
||||
|
||||
setTransient(true);
|
||||
addWorkPanel(buildWorkPanel());
|
||||
addOKButton();
|
||||
addCancelButton();
|
||||
|
|
|
@ -55,8 +55,9 @@ public class ReadTextDialog extends DialogComponentProvider {
|
|||
}
|
||||
|
||||
private void init(JPanel workPanelToInit) {
|
||||
this.addWorkPanel(workPanelToInit);
|
||||
this.addOKButton();
|
||||
setTransient(true);
|
||||
addWorkPanel(workPanelToInit);
|
||||
addOKButton();
|
||||
setRememberLocation(false);
|
||||
setRememberSize(false);
|
||||
}
|
||||
|
|
|
@ -52,6 +52,8 @@ public class SettingsDialog extends DialogComponentProvider {
|
|||
if (help != null) {
|
||||
setHelpLocation(help);
|
||||
}
|
||||
|
||||
setTransient(true);
|
||||
addWorkPanel(buildWorkPanel());
|
||||
addDismissButton();
|
||||
|
||||
|
|
|
@ -234,6 +234,7 @@ public class GhidraFileChooser extends DialogComponentProvider
|
|||
super(TITLE, true, true, true, false);
|
||||
this.parent = parent;
|
||||
|
||||
setTransient(true);
|
||||
init(model);
|
||||
loadRecentList();
|
||||
loadOptions();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue