updates for 0.9.3
[debian/openrocket] / src / net / sf / openrocket / gui / main / BasicFrame.java
index ebd86276b885925d47cc072030eaeb102f357ca9..5357b3290add757453d6fc4dd93ad400c6d08eb7 100644 (file)
@@ -17,9 +17,14 @@ import java.awt.event.WindowEvent;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
 import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLDecoder;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.concurrent.ExecutionException;
 
 import javax.swing.Action;
@@ -53,7 +58,7 @@ import javax.swing.tree.TreePath;
 import javax.swing.tree.TreeSelectionModel;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.aerodynamics.Warning;
+import net.sf.openrocket.aerodynamics.WarningSet;
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.file.GeneralRocketLoader;
 import net.sf.openrocket.file.OpenRocketSaver;
@@ -62,17 +67,21 @@ import net.sf.openrocket.file.RocketLoader;
 import net.sf.openrocket.file.RocketSaver;
 import net.sf.openrocket.gui.StorageOptionChooser;
 import net.sf.openrocket.gui.configdialog.ComponentConfigDialog;
-import net.sf.openrocket.gui.dialogs.BugDialog;
+import net.sf.openrocket.gui.dialogs.AboutDialog;
+import net.sf.openrocket.gui.dialogs.BugReportDialog;
 import net.sf.openrocket.gui.dialogs.ComponentAnalysisDialog;
+import net.sf.openrocket.gui.dialogs.ExampleDesignDialog;
 import net.sf.openrocket.gui.dialogs.LicenseDialog;
 import net.sf.openrocket.gui.dialogs.PreferencesDialog;
 import net.sf.openrocket.gui.dialogs.SwingWorkerDialog;
+import net.sf.openrocket.gui.dialogs.WarningDialog;
 import net.sf.openrocket.gui.scalefigure.RocketPanel;
 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
 import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
 import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.rocketcomponent.Stage;
+import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.Icons;
 import net.sf.openrocket.util.OpenFileWorker;
 import net.sf.openrocket.util.Prefs;
@@ -86,7 +95,6 @@ public class BasicFrame extends JFrame {
         */
        private static final RocketLoader ROCKET_LOADER = new GeneralRocketLoader();
        
-       // TODO: Always uses OpenRocketSaver
        private static final RocketSaver ROCKET_SAVER = new OpenRocketSaver();
 
        
@@ -235,7 +243,9 @@ public class BasicFrame extends JFrame {
                        }
                });
                this.setLocationByPlatform(true);
-                               
+
+               GUIUtil.setWindowIcons(this);
+               
                this.validate();
                vertical.setDividerLocation(0.4);
                setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
@@ -402,6 +412,23 @@ public class BasicFrame extends JFrame {
                });
                menu.add(item);
                
+               item = new JMenuItem("Open example...");
+               item.getAccessibleContext().setAccessibleDescription("Open an example rocket design");
+               item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, 
+                               ActionEvent.CTRL_MASK | ActionEvent.SHIFT_MASK));
+               item.setIcon(Icons.FILE_OPEN_EXAMPLE);
+               item.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               URL[] urls = ExampleDesignDialog.selectExampleDesigns(BasicFrame.this);
+                               if (urls != null) {
+                                       for (URL u: urls) {
+                                               open(u, BasicFrame.this);
+                                       }
+                               }
+                       }
+               });
+               menu.add(item);
+               
                menu.addSeparator();
                
                item = new JMenuItem("Save",KeyEvent.VK_S);
@@ -528,6 +555,13 @@ public class BasicFrame extends JFrame {
                menu.add(item);
                
                
+               ////  Debug
+               // (shown if openrocket.debug.menu is defined)
+               if (System.getProperty("openrocket.debug.menu") != null) {
+                       menubar.add(makeDebugMenu());
+               }
+
+               
                
                ////  Help
                
@@ -552,7 +586,8 @@ public class BasicFrame extends JFrame {
                                "bugs in OpenRocket");
                item.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e) {
-                               new BugDialog(BasicFrame.this).setVisible(true);
+//                             new BugDialog(BasicFrame.this).setVisible(true);
+                               BugReportDialog.showBugReportDialog(BasicFrame.this);
                        }
                });
                menu.add(item);
@@ -571,6 +606,73 @@ public class BasicFrame extends JFrame {
        }
        
        
+       private JMenu makeDebugMenu() {
+               JMenu menu;
+               JMenuItem item;
+               
+               ////  Debug menu
+               menu = new JMenu("Debug");
+               menu.getAccessibleContext().setAccessibleDescription("OpenRocket debugging tasks");
+               
+               item = new JMenuItem("What is this menu?");
+               item.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               JOptionPane.showMessageDialog(BasicFrame.this,
+                                               new Object[] {
+                                               "The 'Debug' menu includes actions for testing and debugging " +
+                                               "OpenRocket.", " ",
+                                               "The menu is made visible by defining the system property " +
+                                               "'openrocket.debug.menu' when starting OpenRocket.",
+                                               "It should not be visible by default." },
+                                               "Debug menu", JOptionPane.INFORMATION_MESSAGE);
+                       }
+               });
+               menu.add(item);
+               
+               menu.addSeparator();
+               
+               item = new JMenuItem("Exception here");
+               item.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               throw new RuntimeException("Testing exception from menu action listener");
+                       }
+               });
+               menu.add(item);
+               
+               item = new JMenuItem("Exception from EDT");
+               item.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               SwingUtilities.invokeLater(new Runnable() {
+                                       @Override
+                                       public void run() {
+                                               throw new RuntimeException("Testing exception from " +
+                                                               "later invoked EDT thread");
+                                       }
+                               });
+                       }
+               });
+               menu.add(item);
+               
+               item = new JMenuItem("Exception from other thread");
+               item.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               new Thread() {
+                                       @Override
+                                       public void run() {
+                                               throw new RuntimeException("Testing exception from " +
+                                                               "newly created thread");
+                                       }
+                               }.start();
+                       }
+               });
+               menu.add(item);
+               
+               
+               
+               return menu;
+       }
+       
+       
        
        /**
         * Select the tab on the main pane.
@@ -609,20 +711,91 @@ public class BasicFrame extends JFrame {
        }
        
        
+       
+       
+       private static boolean open(URL url, Window parent) {
+               String filename = null;
+               
+               // Try using URI.getPath();
+               try {
+                       URI uri = url.toURI();
+                       filename = uri.getPath();
+               } catch (URISyntaxException ignore) { }
+
+               // Try URL-decoding the URL
+               if (filename == null) {
+                       try {
+                               filename = URLDecoder.decode(url.toString(), "UTF-8");
+                       } catch (UnsupportedEncodingException ignore) { }
+               }
+               
+               // Last resort
+               if (filename == null) {
+                       filename = "";
+               }
+               
+               // Remove path from filename
+               if (filename.lastIndexOf('/') >= 0) {
+                       filename = filename.substring(filename.lastIndexOf('/')+1);
+               }
+               
+               try {
+                       InputStream is = url.openStream();
+                       open(is, filename, parent);
+               } catch (IOException e) {
+                       JOptionPane.showMessageDialog(parent, 
+                                       "An error occurred while opening the file " + filename,
+                                       "Error loading file", JOptionPane.ERROR_MESSAGE);
+               }
+               
+               return false;
+       }
+       
+       
+       /**
+        * Open the specified file from an InputStream in a new design frame.  If an error
+        * occurs, an error dialog is shown and <code>false</code> is returned.
+        * 
+        * @param stream        the stream to load from.
+        * @param filename      the file name to display in dialogs (not set to the document).
+        * @param parent        the parent component for which a progress dialog is opened.
+        * @return                      whether the file was successfully loaded and opened.
+        */
+       private static boolean open(InputStream stream, String filename, Window parent) {
+               OpenFileWorker worker = new OpenFileWorker(stream, ROCKET_LOADER);
+               return open(worker, filename, null, parent);
+       }
+       
+
        /**
-        * Open the specified file in a new design frame.  If an error occurs, an error dialog
-        * is shown and <code>false</code> is returned.
+        * Open the specified file in a new design frame.  If an error occurs, an error
+        * dialog is shown and <code>false</code> is returned.
         * 
         * @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.
         */
        private static boolean open(File file, Window parent) {
+               OpenFileWorker worker = new OpenFileWorker(file, ROCKET_LOADER);
+               return open(worker, file.getName(), file, parent);
+       }
+       
+
+       /**
+        * Open the specified file using the provided worker.
+        * 
+        * @param worker        the OpenFileWorker that loads the file.
+        * @param filename      the file name to display in dialogs.
+        * @param file          the File to set the document to (may be null).
+        * @param parent
+        * @return
+        */
+       private static boolean open(OpenFileWorker worker, String filename, File file, 
+                       Window parent) {
 
                // Open the file in a Swing worker thread
-               OpenFileWorker worker = new OpenFileWorker(file);
                if (!SwingWorkerDialog.runWorker(parent, "Opening file", 
-                               "Reading " + file.getName() + "...", worker)) {
+                               "Reading " + filename + "...", worker)) {
 
                        // User cancelled the operation
                        return false;
@@ -642,14 +815,14 @@ public class BasicFrame extends JFrame {
                        if (cause instanceof FileNotFoundException) {
 
                                JOptionPane.showMessageDialog(parent, 
-                                               "File not found: " + file.getName(), 
+                                               "File not found: " + filename,
                                                "Error opening file", JOptionPane.ERROR_MESSAGE);
                                return false;
 
                        } else if (cause instanceof RocketLoadException) {
 
                                JOptionPane.showMessageDialog(parent, 
-                                               "Unable to open file '" + file.getName() +"': " 
+                                               "Unable to open file '" + filename +"': " 
                                                + cause.getMessage(),
                                                "Error opening file", JOptionPane.ERROR_MESSAGE);
                                return false;
@@ -670,12 +843,16 @@ public class BasicFrame extends JFrame {
                
                
            // Show warnings
-           Iterator<Warning> warns = ROCKET_LOADER.getWarnings().iterator();
-           System.out.println("Warnings:");
-           while (warns.hasNext()) {
-               System.out.println("  "+warns.next());
-               // TODO: HIGH: dialog
-           }
+               WarningSet warnings = worker.getRocketLoader().getWarnings();
+               if (!warnings.isEmpty()) {
+                       WarningDialog.showWarnings(parent,
+                                       new Object[] {
+                                       "The following problems were encountered while opening " + filename + ".",
+                                       "Some design features may not have been loaded correctly."
+                                       },
+                                       "Warnings while opening file", warnings);
+               }
+               
            
            // Set document state
            doc.setFile(file);
@@ -922,7 +1099,7 @@ public class BasicFrame extends JFrame {
        
        public static void main(final String[] args) {
                
-               // Run the actual startup method in the EDT since it can use dialogs etc. 
+               // Run the actual startup method in the EDT since it can use progress dialogs etc.
                try {
                        SwingUtilities.invokeAndWait(new Runnable() {
                                @Override
@@ -940,7 +1117,7 @@ public class BasicFrame extends JFrame {
        
        
        private static void runMain(String[] args) {
-               
+
                /*
                 * Set the look-and-feel.  On Linux, Motif/Metal is sometimes incorrectly used 
                 * which is butt-ugly, so if the system l&f is Motif/Metal, we search for a few
@@ -983,10 +1160,32 @@ public class BasicFrame extends JFrame {
                ToolTipManager.sharedInstance().setDismissDelay(30000);
                
                
+               // Setup the uncaught exception handler
+               ExceptionHandler.registerExceptionHandler();
+               
+               
                // Load defaults
                Prefs.loadDefaultUnits();
 
                
+               // Starting action
+               if (!handleCommandLine(args)) {
+                       newAction();
+               }
+       }
+       
+       
+       /**
+        * Handles arguments passed from the command line.  This may be used either
+        * when starting the first instance of OpenRocket or later when OpenRocket is
+        * executed again while running.
+        * 
+        * @param args  the command-line arguments.
+        * @return              whether a new frame was opened or similar user desired action was
+        *                              performed as a result.
+        */
+       public static boolean handleCommandLine(String[] args) {
+               
                // Check command-line for files
                boolean opened = false;
                for (String file: args) {
@@ -994,10 +1193,7 @@ public class BasicFrame extends JFrame {
                                opened = true;
                        }
                }
-               
-               if (!opened) {
-                       newAction();
-               }
+               return opened;
        }
 
 }