diff --git a/swing/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java b/swing/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java index c244e4ccd..bd15b1b90 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/ComponentConfigDialog.java @@ -1,18 +1,24 @@ package net.sf.openrocket.gui.configdialog; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Rectangle; import java.awt.Window; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; import java.util.List; import javax.swing.JDialog; import net.sf.openrocket.document.OpenRocketDocument; +import net.sf.openrocket.gui.main.BasicFrame; import net.sf.openrocket.gui.util.GUIUtil; import net.sf.openrocket.gui.util.SwingPreferences; +import net.sf.openrocket.gui.util.WindowLocationUtil; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.rocketcomponent.AxialStage; import net.sf.openrocket.rocketcomponent.ComponentChangeEvent; @@ -257,6 +263,9 @@ public class ComponentConfigDialog extends JDialog implements ComponentChangeLis dialog = new ComponentConfigDialog(parent, document, component); dialog.setVisible(true); + if (parent instanceof BasicFrame && BasicFrame.getStartupFrame() == parent) { + WindowLocationUtil.moveIfOutsideOfParentMonitor(dialog, parent); + } ////Modify if (includeUndoModify) { diff --git a/swing/src/net/sf/openrocket/gui/main/BasicFrame.java b/swing/src/net/sf/openrocket/gui/main/BasicFrame.java index b5304eba3..04fdf9bf3 100644 --- a/swing/src/net/sf/openrocket/gui/main/BasicFrame.java +++ b/swing/src/net/sf/openrocket/gui/main/BasicFrame.java @@ -118,6 +118,7 @@ public class BasicFrame extends JFrame { * it is time to exit the application. */ private static final ArrayList frames = new ArrayList(); + private static BasicFrame startupFrame = null; // the frame that was created at startup /** @@ -1231,6 +1232,19 @@ public class BasicFrame extends JFrame { return menu; } + /** + * Return the frame that was created at the application's startup. + */ + public static BasicFrame getStartupFrame() { + return startupFrame; + } + + /** + * Set the frame that is created at the application's startup. + */ + public static void setStartupFrame(BasicFrame startupFrame) { + BasicFrame.startupFrame = startupFrame; + } /** * Select the tab on the main pane. @@ -1273,7 +1287,7 @@ public class BasicFrame extends JFrame { for (File file : files) { log.info("Opening file: " + file); - if (open(file, parent)) { + if (open(file, parent) != null) { MRUDesignFile opts = MRUDesignFile.getInstance(); opts.addFile(file.getAbsolutePath()); } @@ -1303,7 +1317,7 @@ public class BasicFrame extends JFrame { for (File file : files) { log.info("Opening file: " + file); - if (open(file, this)) { + if (open(file, this) != null) { MRUDesignFile opts = MRUDesignFile.getInstance(); opts.addFile(file.getAbsolutePath()); } @@ -1373,9 +1387,9 @@ public class BasicFrame extends JFrame { * * @param file the file to open. * @param parent the parent component for which a progress dialog is opened. - * @return whether the file was successfully loaded and opened. + * @return the BasicFrame that was created, or null if not created successfully. */ - public static boolean open(File file, Window parent) { + public static BasicFrame open(File file, Window parent) { OpenFileWorker worker = new OpenFileWorker(file); return open(worker, file.getName(), parent, false); } @@ -1388,15 +1402,15 @@ public class BasicFrame extends JFrame { * @param displayName the file name to display in dialogs. * @param parent * @param openRocketConfigDialog if true, will open the configuration dialog of the rocket. This is useful for examples. - * @return + * @return the BasicFrame that was created, or null if not created successfully. */ - private static boolean open(OpenFileWorker worker, String displayName, Window parent, boolean openRocketConfigDialog) { + private static BasicFrame open(OpenFileWorker worker, String displayName, Window parent, boolean openRocketConfigDialog) { //// Open the file in a Swing worker thread log.info("Starting OpenFileWorker"); if (!SwingWorkerDialog.runWorker(parent, "Opening file", "Reading " + displayName + "...", worker)) { // // User cancelled the operation log.info("User cancelled the OpenFileWorker"); - return false; + return null; } //// Handle the document @@ -1415,7 +1429,7 @@ public class BasicFrame extends JFrame { JOptionPane.showMessageDialog(parent, "File not found: " + displayName, "Error opening file", JOptionPane.ERROR_MESSAGE); - return false; + return null; } else if (cause instanceof RocketLoadException) { @@ -1424,7 +1438,7 @@ public class BasicFrame extends JFrame { "Unable to open file '" + displayName + "': " + cause.getMessage(), "Error opening file", JOptionPane.ERROR_MESSAGE); - return false; + return null; } else { @@ -1468,7 +1482,7 @@ public class BasicFrame extends JFrame { ComponentConfigDialog.showDialog(frame, doc, doc.getRocket()); } - return true; + return frame; } @@ -1774,24 +1788,27 @@ public class BasicFrame extends JFrame { /** * Opens a new design file or the last design file, if set in the preferences. * Can be used for reopening the application or opening it the first time. + * @return the BasicFrame that was created */ - public static void reopen() { + public static BasicFrame reopen() { if (!Application.getPreferences().isAutoOpenLastDesignOnStartupEnabled()) { - BasicFrame.newAction(); + return BasicFrame.newAction(); } else { String lastFile = MRUDesignFile.getInstance().getLastEditedDesignFile(); if (lastFile != null) { log.info("Opening last design file: " + lastFile); - if (!BasicFrame.open(new File(lastFile), null)) { + BasicFrame frame = BasicFrame.open(new File(lastFile), null); + if (frame == null) { MRUDesignFile.getInstance().removeFile(lastFile); - BasicFrame.newAction(); + return BasicFrame.newAction(); } else { MRUDesignFile.getInstance().addFile(lastFile); + return frame; } } else { - BasicFrame.newAction(); + return BasicFrame.newAction(); } } } @@ -1799,8 +1816,9 @@ public class BasicFrame extends JFrame { /** * Open a new design window with a basic rocket+stage. + * @return the BasicFrame that was created */ - public static void newAction() { + public static BasicFrame newAction() { log.info("New action initiated"); OpenRocketDocument doc = OpenRocketDocumentFactory.createNewRocket(); @@ -1808,6 +1826,7 @@ public class BasicFrame extends JFrame { BasicFrame frame = new BasicFrame(doc); frame.replaceable = true; frame.setVisible(true); + return frame; } diff --git a/swing/src/net/sf/openrocket/gui/main/MRUDesignFileAction.java b/swing/src/net/sf/openrocket/gui/main/MRUDesignFileAction.java index 5582e4fca..3ff152d82 100644 --- a/swing/src/net/sf/openrocket/gui/main/MRUDesignFileAction.java +++ b/swing/src/net/sf/openrocket/gui/main/MRUDesignFileAction.java @@ -73,7 +73,7 @@ public final class MRUDesignFileAction extends JMenu { @Override public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); - if (BasicFrame.open(new File(command), parent)) { + if (BasicFrame.open(new File(command), parent) != null) { MRUDesignFile.getInstance().addFile(command); } else { diff --git a/swing/src/net/sf/openrocket/gui/util/WindowLocationUtil.java b/swing/src/net/sf/openrocket/gui/util/WindowLocationUtil.java new file mode 100644 index 000000000..d4443954c --- /dev/null +++ b/swing/src/net/sf/openrocket/gui/util/WindowLocationUtil.java @@ -0,0 +1,74 @@ +package net.sf.openrocket.gui.util; + +import java.awt.GraphicsDevice; +import java.awt.Window; + +/** + * Helper class for setting the location of a Swing window. E.g. to check when the window is outside the screen and + * recenter it if so. + * + * @author Sibo Van Gool + */ +public abstract class WindowLocationUtil { + /** + * Sets the location of the window, but don't go outside the screen. + * @param window the window to move + * @param x the target x position on the screen + * @param y the target y position on the screen + */ + public static void setLocationWithinScreen(Window window, int x, int y) { + java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); + java.awt.Dimension windowSize = window.getSize(); + int screenWidth = screenSize.width; + int screenHeight = screenSize.height; + int windowWidth = windowSize.width; + int windowHeight = windowSize.height; + int xPos = x; + int yPos = y; + if (xPos + windowWidth > screenWidth) { + xPos = screenWidth - windowWidth; + } + if (yPos + windowHeight > screenHeight) { + yPos = screenHeight - windowHeight; + } + window.setLocation(xPos, yPos); + } + + /** + * Moves the window to the center of the screen if its location is outside the boundary of the screen. + * @param window window to move + */ + public static void moveIfOutsideOfMonitor(Window window) { + GraphicsDevice currentDevice = window.getGraphicsConfiguration().getDevice(); + if (currentDevice != null && window.isVisible() && + !currentDevice.getDefaultConfiguration().getBounds().contains(window.getLocationOnScreen())) { + int width = currentDevice.getDefaultConfiguration().getBounds().width; + int height = currentDevice.getDefaultConfiguration().getBounds().height; + window.setLocation( + ((width / 2) - (window.getSize().width / 2)) + currentDevice.getDefaultConfiguration().getBounds().x, + ((height / 2) - (window.getSize().height / 2)) + currentDevice.getDefaultConfiguration().getBounds().y + ); + } + } + + /** + * Moves the window to the center of the screen if it is on another monitor as the parent window, or if its location + * is outside the boundary of the parent's monitor screen. + * @param window window to move + * @param parent parent window + */ + public static void moveIfOutsideOfParentMonitor(Window window, Window parent) { + GraphicsDevice parentDevice = parent.getGraphicsConfiguration().getDevice(); + GraphicsDevice currentDevice = window.getGraphicsConfiguration().getDevice(); + if (parentDevice != null && (currentDevice == null || currentDevice != parentDevice || + (window.isVisible() && !parentDevice.getDefaultConfiguration().getBounds().contains( + window.getLocationOnScreen())))) { + int width = parentDevice.getDefaultConfiguration().getBounds().width; + int height = parentDevice.getDefaultConfiguration().getBounds().height; + window.setLocation( + ((width / 2) - (window.getSize().width / 2)) + parentDevice.getDefaultConfiguration().getBounds().x, + ((height / 2) - (window.getSize().height / 2)) + parentDevice.getDefaultConfiguration().getBounds().y + ); + } + } +} diff --git a/swing/src/net/sf/openrocket/startup/SwingStartup.java b/swing/src/net/sf/openrocket/startup/SwingStartup.java index 5d6ff3386..462549e11 100644 --- a/swing/src/net/sf/openrocket/startup/SwingStartup.java +++ b/swing/src/net/sf/openrocket/startup/SwingStartup.java @@ -223,7 +223,8 @@ public class SwingStartup { // Starting action (load files or open new document) log.info("Opening main application window"); if (!handleCommandLine(args)) { - BasicFrame.reopen(); + BasicFrame startupFrame = BasicFrame.reopen(); + BasicFrame.setStartupFrame(startupFrame); } // Check whether update info has been fetched or whether it needs more time @@ -298,7 +299,7 @@ public class SwingStartup { // Check command-line for files boolean opened = false; for (String file : args) { - if (BasicFrame.open(new File(file), null)) { + if (BasicFrame.open(new File(file), null) != null) { opened = true; } }