diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/console/ConsoleComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/console/ConsoleComponentProvider.java index b295457a29..f5ee090cff 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/console/ConsoleComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/console/ConsoleComponentProvider.java @@ -83,6 +83,13 @@ public class ConsoleComponentProvider extends ComponentProviderAdapter createActions(); } + @Override + public boolean canBeParent() { + // the console window may appear and be closed often and thus is not a suitable parent when + // in a window by itself + return false; + } + void init() { stderr = new PrintWriter(new ConsoleWriter(this, true)); stdin = new PrintWriter(new ConsoleWriter(this, false)); @@ -203,7 +210,7 @@ public class ConsoleComponentProvider extends ComponentProviderAdapter return; } - // NOTE: must be case sensitive otherwise the service will report that it has + // NOTE: must be case sensitive otherwise the service will report that it has // processed the request even if there are no matches boolean found = gotoService.goToQuery(currentAddress, new QueryData(word.word, true), null, null); @@ -285,8 +292,8 @@ public class ConsoleComponentProvider extends ComponentProviderAdapter } }; scrollAction.setDescription("Scroll Lock"); - scrollAction.setToolBarData( - new ToolBarData(ResourceManager.loadImage(SCROLL_LOCK_GIF), null)); + scrollAction + .setToolBarData(new ToolBarData(ResourceManager.loadImage(SCROLL_LOCK_GIF), null)); scrollAction.setEnabled(true); scrollAction.setSelected(scrollLock); @@ -316,7 +323,7 @@ public class ConsoleComponentProvider extends ComponentProviderAdapter // // sometimes an exception will occur while printing // the stack trace on an exception. - // if that happens catch it and manually print + // if that happens catch it and manually print // some information about it. // see org.jruby.exceptions.RaiseException // diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptComponentProvider.java index c9bf4421c5..73ce3145f3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptComponentProvider.java @@ -136,6 +136,13 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter { updateTitle(); } + @Override + public boolean canBeParent() { + // the script window may be open and closed often as users run scripts and thus is not a + // suitable parent when in a window by itself + return false; + } + private void buildCategoryTree() { scriptRoot = new RootNode(); @@ -812,7 +819,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter { /* Unusual Algorithm - + The tree nodes represent categories, but do not contain nodes for individual scripts. We wish to remove any of the tree nodes that no longer represent script categories. (This can happen when a script is deleted or its category is changed.) @@ -1171,7 +1178,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter { @Override public void bundleBuilt(GhidraBundle bundle, String summary) { - // on enable, build can happen before the refresh populates the info manager with this + // on enable, build can happen before the refresh populates the info manager with this // bundle's scripts, so allow for the possibility and create the info here. if (!(bundle instanceof GhidraSourceBundle)) { return; @@ -1180,7 +1187,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter { GhidraSourceBundle sourceBundle = (GhidraSourceBundle) bundle; ResourceFile sourceDirectory = sourceBundle.getFile(); if (summary == null) { - // a null summary means the build didn't change anything, so use any errors from + // a null summary means the build didn't change anything, so use any errors from // the last build for (ResourceFile sourceFile : sourceBundle.getAllErrors().keySet()) { if (sourceFile.getParentFile().equals(sourceDirectory)) { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/ComponentProvider.java b/Ghidra/Framework/Docking/src/main/java/docking/ComponentProvider.java index 3d798d782f..408ad63a14 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/ComponentProvider.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/ComponentProvider.java @@ -30,11 +30,11 @@ import ghidra.util.exception.AssertException; import utilities.util.reflection.ReflectionUtilities; /** - * Abstract base class for creating dockable GUI components within a tool. + * Abstract base class for creating dockable GUI components within a tool. *
* The one method that must be implemented is {@link #getComponent()} which is where the top level * Swing JComponent is returned to be docked into the tool. Typically, the GUI components are - * created in the constructor along with any local actions for the provider. The getComponent() + * created in the constructor along with any local actions for the provider. The getComponent() * method then simply returns the top level component previously created by this provider. *
* There are many other methods for configuring how to dock the component, set title information, @@ -43,7 +43,7 @@ import utilities.util.reflection.ReflectionUtilities; * how the GUI component behaves within the tool, and then add the business logic that uses and reacts * to the GUI components created in this provider. *
- * To effectively use this class you merely need to create your component, add your actions to + * To effectively use this class you merely need to create your component, add your actions to * this class ({@link #addLocalAction(DockingActionIf)}) and then add this provider to the tool * ({@link #addToTool()}). *
@@ -51,7 +51,7 @@ import utilities.util.reflection.ReflectionUtilities; *
* Show Provider Action - Each provider has an action to show the provider. For - * typical, non-transient providers (see {@link #setTransient()}) the action will appear in + * typical, non-transient providers (see {@link #setTransient()}) the action will appear in * the tool's Window menu. You can have your provider also appear in the tool's toolbar * by calling {@link #addToTool()}. *
@@ -178,7 +178,7 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
* A method that allows children to set the instanceID
to a desired value (useful for
* restoring saved IDs).
*
- * Note: this can be called only once during the lifetime of the calling instance; otherwise, an + * Note: this can be called only once during the lifetime of the calling instance; otherwise, an * {@link AssertException} will be thrown. * @param newID the new ID of this provider */ @@ -220,7 +220,7 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext /** * Returns true if this provider has focus - * + * * @return true if this provider has focus */ public boolean isFocusedProvider() { @@ -319,12 +319,12 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext } /** - * A signal used when installing actions. Some actions are only added to a given window + * A signal used when installing actions. Some actions are only added to a given window * if there is a provider in that window that can work with that action. Providers can return * a context class from this method to control whether dependent actions get added. Most - * providers return null for this method, which means they will not have any dependent + * providers return null for this method, which means they will not have any dependent * actions added to windows other than the primary application window. - * + * * @return a class representing the desired context type or null; */ public Class> getContextType() { @@ -351,8 +351,8 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext * This is the callback that will happen when the user presses the 'X' button of a provider. * Transient providers will be removed from the tool completely. Non-transient providers * will merely be hidden. - * - *
Subclasses may override this method to prevent a provider from being closed; for + * + *
Subclasses may override this method to prevent a provider from being closed; for
* example, if an editor has unsaved changes, then this method could prevent the close from
* happening.
*/
@@ -380,7 +380,7 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
}
/**
- * Notifies the provider that the component is being hidden. This happens when the
+ * Notifies the provider that the component is being hidden. This happens when the
* provider is being closed.
*/
public void componentHidden() {
@@ -423,7 +423,7 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
/**
* A default method for creating an action context for this provider, using the given
* {@link ActionContext#getContextObject() context object}
- *
+ *
* @param contextObject the provider-specific context object
* @return the new context
*/
@@ -434,7 +434,7 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
/**
* A default method for creating an action context for this provider, using the given
* {@link ActionContext#getContextObject() context object} and component
- *
+ *
* @param sourceComponent the component that is the target of the context being created
* @param contextObject the provider-specific context object
* @return the new context
@@ -451,10 +451,10 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
}
/**
- * Returns the general HelpLocation for this provider. Should return null only if no
+ * Returns the general HelpLocation for this provider. Should return null only if no
* help documentation exists.
- *
- * @return the help location
+ *
+ * @return the help location
*/
public HelpLocation getHelpLocation() {
return helpLocation;
@@ -546,7 +546,7 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
/**
* Returns the optionally set text to display in the tab for a component provider. The
* text returned from {@link #getTitle()} will be used by default.
- *
+ *
* @return the optionally set text to display in the tab for a component provider.
* @see #setTabText(String)
*/
@@ -558,7 +558,7 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
/**
* Sets the default key binding that will show this provider when pressed. This value can
* be changed by the user and saved as part of the Tool options.
- *
+ *
* @param kbData the key binding
*/
protected void setKeyBinding(KeyBindingData kbData) {
@@ -596,7 +596,7 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
}
/**
- * Signals that this provider's action for showing the provider should appear in the main
+ * Signals that this provider's action for showing the provider should appear in the main
* toolbar
*/
protected void addToToolbar() {
@@ -629,9 +629,21 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
}
/**
- * A special marker that indicates this provider is a snapshot of a primary provider,
+ * Returns true if the window containing this provider can be used as a parent window when
+ * showing system windows. All providers will return true from this method by default. This
+ * method is intended for short-lived providers to signal that their window should not be made
+ * the parent of new windows.
+ *
+ * @return true if this provider can be a parent
+ */
+ public boolean canBeParent() {
+ return true;
+ }
+
+ /**
+ * A special marker that indicates this provider is a snapshot of a primary provider,
* somewhat like a picture of the primary provider.
- *
+ *
* @return true if a snapshot
*/
public boolean isSnapshot() {
@@ -667,9 +679,9 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
/**
* Sets the window menu group. If the window menu group is null, the corresponding window menu
- * item will appear in the root menu, otherwise it will appear in a
+ * item will appear in the root menu, otherwise it will appear in a
* sub-menu named group
.
- *
+ *
* @param group the name of the window's sub-menu for this provider
*/
protected void setWindowMenuGroup(String group) {
@@ -678,10 +690,10 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
/**
* The initial {@link WindowPosition} of this provider. If a {@link #getWindowGroup() window
- * group} is provided, then this position is relative to that provider. Otherwise, this
+ * group} is provided, then this position is relative to that provider. Otherwise, this
* position is relative to the tool window.
- *
- * @return The initial {@link WindowPosition} of this provider.
+ *
+ * @return The initial {@link WindowPosition} of this provider.
*/
public WindowPosition getDefaultWindowPosition() {
return defaultWindowPosition;
@@ -690,8 +702,8 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
/**
* Sets the default position of this provider when being shown for the first time. If the
* providers position in the tool has been saved before, then this value is ignored.
- *
- * @param windowPosition the position
+ *
+ * @param windowPosition the position
* @see #getDefaultWindowPosition()
*/
protected void setDefaultWindowPosition(WindowPosition windowPosition) {
@@ -701,13 +713,13 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
/**
* The position of this provider when being placed with other members of the same group. As
* an example, assume this provider is being shown for the first time while there is another
- * member of its {@link #getWindowGroup() window group} already visible. Further, assume
+ * member of its {@link #getWindowGroup() window group} already visible. Further, assume
* that this method will return {@link WindowPosition#STACK}. This provider will then be
* stacked upon the already showing provider.
*
- * To determine where this provider should be initially shown, + * To determine where this provider should be initially shown, * see {@link #getDefaultWindowPosition()}. - * + * * @return The position of this provider when being placed with other members of the same group. */ public WindowPosition getIntraGroupPosition() { @@ -716,7 +728,7 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext /** * See {@link #getIntraGroupPosition()}. - * + * * @param position the new position */ public void setIntraGroupPosition(WindowPosition position) { @@ -724,18 +736,18 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext } /** - * Returns an optional group designator that, if non-null, the docking window manager uses to + * Returns an optional group designator that, if non-null, the docking window manager uses to * determine the initial location of the new component relative to any existing instances - * of this component Provider. + * of this component Provider. *
- * The docking window manager will use {@link #getIntraGroupPosition() Intra-group Position} - * to decide where to place this provider inside of the already open instances of the + * The docking window manager will use {@link #getIntraGroupPosition() Intra-group Position} + * to decide where to place this provider inside of the already open instances of the * same group. The default position is 'stack', which results in the new instance being * stacked with other instances of this provider that have the same group unless that instance is * the active provider or is currently stacked with the active provider. (This is to prevent * new windows from covering the active window). - * - * @return the window group + * + * @return the window group */ public String getWindowGroup() { return group; @@ -743,7 +755,7 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext /** * Sets the window group. See {@link #getWindowGroup()}. - * + * * @param group the group for this provider. */ protected void setWindowGroup(String group) { @@ -808,14 +820,14 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext } /** - * Register a name and/or owner change to a provider so that old tools can restore those - * provider windows to their old position and size. Note you must supply all four - * arguments. If the name or owner did not change, use the name or owner that did not change + * Register a name and/or owner change to a provider so that old tools can restore those + * provider windows to their old position and size. Note you must supply all four + * arguments. If the name or owner did not change, use the name or owner that did not change * for both the old and new values. - * - *
Note: when you make use of this method, please signal when it is safe to remove + * + *
Note: when you make use of this method, please signal when it is safe to remove
* its usage.
- *
+ *
* @param oldName the old name of the provider.
* @param oldOwner the old owner of the provider.
* @param newName the new name of the provider. If the name did not change, use the old name here.
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java b/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java
index a89c66c022..e525d08419 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java
@@ -114,7 +114,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
/**
* Constructs a new DockingWindowManager
- *
+ *
* @param tool the tool
* @param images the images to use for windows in this window manager
*/
@@ -163,7 +163,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
/**
* Sets the help service for the all docking window managers.
- *
+ *
* @param helpSvc the help service to use.
*/
public static void setHelpService(HelpService helpSvc) {
@@ -175,7 +175,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
/**
* Returns the global help service.
- *
+ *
* @return the global help service.
*/
public static HelpService getHelpService() {
@@ -192,7 +192,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
/**
* Get the docking window manager instance which corresponds to the specified window.
- *
+ *
* @param win the window for which to find its parent docking window manager.
* @return docking window manager or null if unknown.
*/
@@ -226,7 +226,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
/**
* A convenience method for getting the window for
* 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
@@ -1890,7 +1890,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
/*
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
@@ -1898,7 +1898,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
@@ -1906,12 +1906,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
@@ -1930,12 +1930,12 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
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
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.
-
+
*/
DockingWindowManager dwm = getActiveInstance();
@@ -1966,7 +1966,14 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
}
if (c instanceof DockingFrame) {
- return !((DockingFrame) c).isTransient();
+
+ DockingFrame frame = (DockingFrame) c;
+ if (frame.isTransient()) {
+ return false;
+ }
+
+ // consider any window transient if all of its contained providers cannot be parents
+ return hasAnyParentableProvider(frame);
}
if (c instanceof DockingDialog) {
@@ -1986,6 +1993,21 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
return (c instanceof Window);
}
+ private static boolean hasAnyParentableProvider(Window window) {
+ boolean hasAnyParentableProvider = false;
+ DockingWindowManager dwm = getInstanceForWindow(window);
+ WindowNode node = dwm.root.getNodeForWindow(window);
+ List
* Our {@link #contextChanged(ComponentProvider)} method will eventually call back into this
* method after any buffering has taken place.
- *
+ *
* @param context the context
*/
void doContextChanged(ActionContext context) {
component
and then calling
* {@link #getInstanceForWindow(Window)}.
- *
+ *
* @param component The component for which to get the associated {@link DockingWindowManager}
* instance.
* @return The {@link DockingWindowManager} instance associated with component
@@ -246,7 +246,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
/**
* Returns the last active docking window manager which is visible.
- *
+ *
* @return the last active docking window manager which is visible.
*/
public static synchronized DockingWindowManager getActiveInstance() {
@@ -268,7 +268,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
/**
* Returns a new list of all DockingWindowManager instances known to exist, ordered from least
* to most-recently active.
- *
+ *
* @return a new list of all DockingWindowManager instances know to exist.
*/
public static synchronized List