X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=core%2Fsrc%2Fnet%2Fsf%2Fopenrocket%2Fgui%2Fmain%2FBasicFrame.java;h=9f758c347a5d971150561eab92cc7f476ef53142;hb=c83755695e7597383be28aa9fb0d2089aaaa0378;hp=f9884900bdd4defeb4f8dcf01d3d3fbb3f8f4932;hpb=587569f41cf4c0eefee10339bdb324d366280cd5;p=debian%2Fopenrocket diff --git a/core/src/net/sf/openrocket/gui/main/BasicFrame.java b/core/src/net/sf/openrocket/gui/main/BasicFrame.java index f9884900..9f758c34 100644 --- a/core/src/net/sf/openrocket/gui/main/BasicFrame.java +++ b/core/src/net/sf/openrocket/gui/main/BasicFrame.java @@ -1,62 +1,5 @@ package net.sf.openrocket.gui.main; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Toolkit; -import java.awt.Window; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.WindowAdapter; -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.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLDecoder; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.ExecutionException; - -import javax.swing.Action; -import javax.swing.BorderFactory; -import javax.swing.InputMap; -import javax.swing.JButton; -import javax.swing.JComponent; -import javax.swing.JFileChooser; -import javax.swing.JFrame; -import javax.swing.JMenu; -import javax.swing.JMenuBar; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JScrollPane; -import javax.swing.JSpinner; -import javax.swing.JSplitPane; -import javax.swing.JTabbedPane; -import javax.swing.JTextField; -import javax.swing.KeyStroke; -import javax.swing.ListSelectionModel; -import javax.swing.ScrollPaneConstants; -import javax.swing.SwingUtilities; -import javax.swing.border.BevelBorder; -import javax.swing.border.TitledBorder; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.tree.DefaultTreeSelectionModel; -import javax.swing.tree.TreePath; -import javax.swing.tree.TreeSelectionModel; - import net.miginfocom.swing.MigLayout; import net.sf.openrocket.aerodynamics.WarningSet; import net.sf.openrocket.document.OpenRocketDocument; @@ -105,148 +48,194 @@ import net.sf.openrocket.util.MemoryManagement.MemoryData; import net.sf.openrocket.util.Reflection; import net.sf.openrocket.util.TestRockets; +import javax.swing.Action; +import javax.swing.BorderFactory; +import javax.swing.InputMap; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; +import javax.swing.JTextField; +import javax.swing.KeyStroke; +import javax.swing.ListSelectionModel; +import javax.swing.ScrollPaneConstants; +import javax.swing.SwingUtilities; +import javax.swing.border.BevelBorder; +import javax.swing.border.TitledBorder; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultTreeSelectionModel; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.WindowAdapter; +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.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ExecutionException; + public class BasicFrame extends JFrame { private static final LogHelper log = Application.getLogger(); - + /** * The RocketLoader instance used for loading all rocket designs. */ private static final RocketLoader ROCKET_LOADER = new GeneralRocketLoader(); - + private static final RocketSaver ROCKET_SAVER = new OpenRocketSaver(); - + private static final Translator trans = Application.getTranslator(); - + public static final int COMPONENT_TAB = 0; public static final int SIMULATION_TAB = 1; - - + + /** * List of currently open frames. When the list goes empty * it is time to exit the application. */ private static final ArrayList frames = new ArrayList(); - - + + /** * Whether "New" and "Open" should replace this frame. * Should be set to false on the first rocket modification. */ private boolean replaceable = false; - - - + + + private final OpenRocketDocument document; private final Rocket rocket; - + private JTabbedPane tabbedPane; private RocketPanel rocketpanel; private ComponentTree tree = null; - + private final DocumentSelectionModel selectionModel; private final TreeSelectionModel componentSelectionModel; private final ListSelectionModel simulationSelectionModel; - + /** Actions available for rocket modifications */ private final RocketActions actions; - - - + + + + /** * Sole constructor. Creates a new frame based on the supplied document * and adds it to the current frames list. - * + * * @param document the document to show. */ public BasicFrame(OpenRocketDocument document) { log.debug("Instantiating new BasicFrame"); - + this.document = document; this.rocket = document.getRocket(); this.rocket.getDefaultConfiguration().setAllStages(); - - - // Set replaceable flag to false at first modification - rocket.addComponentChangeListener(new ComponentChangeListener() { - @Override - public void componentChanged(ComponentChangeEvent e) { - replaceable = false; - BasicFrame.this.rocket.removeComponentChangeListener(this); - } - }); - - + // Create the component tree selection model that will be used componentSelectionModel = new DefaultTreeSelectionModel(); componentSelectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); - + // Obtain the simulation selection model that will be used SimulationPanel simulationPanel = new SimulationPanel(document); simulationSelectionModel = simulationPanel.getSimulationListSelectionModel(); - + // Combine into a DocumentSelectionModel selectionModel = new DocumentSelectionModel(document); selectionModel.attachComponentTreeSelectionModel(componentSelectionModel); selectionModel.attachSimulationListSelectionModel(simulationSelectionModel); - - + + actions = new RocketActions(document, selectionModel, this); - - + + log.debug("Constructing the BasicFrame UI"); - - // The main vertical split pane + + // The main vertical split pane JSplitPane vertical = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true); vertical.setResizeWeight(0.5); this.add(vertical); - - + + // The top tabbed pane tabbedPane = new JTabbedPane(); //// Rocket design tabbedPane.addTab(trans.get("BasicFrame.tab.Rocketdesign"), null, designTab()); //// Flight simulations tabbedPane.addTab(trans.get("BasicFrame.tab.Flightsim"), null, simulationPanel); - + vertical.setTopComponent(tabbedPane); - - - + + + // Bottom segment, rocket figure - + rocketpanel = new RocketPanel(document); vertical.setBottomComponent(rocketpanel); - + rocketpanel.setSelectionModel(tree.getSelectionModel()); - - + + createMenu(); - - + + rocket.addComponentChangeListener(new ComponentChangeListener() { @Override public void componentChanged(ComponentChangeEvent e) { setTitle(); } }); - + setTitle(); this.pack(); - - + + // Set initial window size Dimension size = Toolkit.getDefaultToolkit().getScreenSize(); size.width = size.width * 9 / 10; size.height = size.height * 9 / 10; this.setSize(size); - + // Remember changed size GUIUtil.rememberWindowSize(this); - + this.setLocationByPlatform(true); - + GUIUtil.setWindowIcons(this); - + this.validate(); vertical.setDividerLocation(0.4); setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); @@ -256,12 +245,12 @@ public class BasicFrame extends JFrame { closeAction(); } }); - + frames.add(this); log.debug("BasicFrame instantiation complete"); } - - + + /** * Construct the "Rocket design" tab. This contains a horizontal split pane * with the left component the design tree and the right component buttons @@ -270,15 +259,15 @@ public class BasicFrame extends JFrame { private JComponent designTab() { JSplitPane horizontal = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true); horizontal.setResizeWeight(0.5); - - + + // Upper-left segment, component tree - + JPanel panel = new JPanel(new MigLayout("fill, flowy", "", "[grow]")); - + tree = new ComponentTree(document); tree.setSelectionModel(componentSelectionModel); - + // Remove JTree key events that interfere with menu accelerators InputMap im = SwingUtilities.getUIInputMap(tree, JComponent.WHEN_FOCUSED); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.CTRL_MASK), null); @@ -288,9 +277,9 @@ public class BasicFrame extends JFrame { im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK), null); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK), null); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK), null); - - - + + + // Double-click opens config dialog MouseListener ml = new MouseAdapter() { @Override @@ -308,7 +297,7 @@ public class BasicFrame extends JFrame { } }; tree.addMouseListener(ml); - + // Update dialog when selection is changed componentSelectionModel.addTreeSelectionListener(new TreeSelectionListener() { @Override @@ -318,7 +307,7 @@ public class BasicFrame extends JFrame { if (path == null) return; tree.scrollPathToVisible(path); - + if (!ComponentConfigDialog.isDialogVisible()) return; RocketComponent c = (RocketComponent) path.getLastPathComponent(); @@ -326,57 +315,57 @@ public class BasicFrame extends JFrame { BasicFrame.this.document, c); } }); - + // Place tree inside scroll pane JScrollPane scroll = new JScrollPane(tree); panel.add(scroll, "spany, grow, wrap"); - - + + // Buttons JButton button = new JButton(actions.getMoveUpAction()); panel.add(button, "sizegroup buttons, aligny 65%"); - + button = new JButton(actions.getMoveDownAction()); panel.add(button, "sizegroup buttons, aligny 0%"); - + button = new JButton(actions.getEditAction()); panel.add(button, "sizegroup buttons"); - + button = new JButton(actions.getNewStageAction()); panel.add(button, "sizegroup buttons"); - + button = new JButton(actions.getDeleteAction()); button.setIcon(null); button.setMnemonic(0); panel.add(button, "sizegroup buttons"); - + horizontal.setLeftComponent(panel); - - + + // Upper-right segment, component addition buttons - + panel = new JPanel(new MigLayout("fill, insets 0", "[0::]")); - + scroll = new JScrollPane(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scroll.setViewportView(new ComponentAddButtons(document, componentSelectionModel, scroll.getViewport())); scroll.setBorder(null); scroll.setViewportBorder(null); - + TitledBorder border = BorderFactory.createTitledBorder(trans.get("BasicFrame.title.Addnewcomp")); GUIUtil.changeFontStyle(border, Font.BOLD); scroll.setBorder(border); - + panel.add(scroll, "grow"); - + horizontal.setRightComponent(panel); - + return horizontal; } - - - + + + /** * Return the currently selected rocket component, or null if none selected. */ @@ -385,11 +374,11 @@ public class BasicFrame extends JFrame { if (path == null) return null; tree.scrollPathToVisible(path); - + return (RocketComponent) path.getLastPathComponent(); } - - + + /** * Creates the menu for the window. */ @@ -397,15 +386,15 @@ public class BasicFrame extends JFrame { JMenuBar menubar = new JMenuBar(); JMenu menu; JMenuItem item; - + //// File menu = new JMenu(trans.get("main.menu.file")); menu.setMnemonic(KeyEvent.VK_F); //// File-handling related tasks menu.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.file.desc")); menubar.add(menu); - - //// New + + //// New item = new JMenuItem(trans.get("main.menu.file.new"), KeyEvent.VK_N); item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK)); item.setMnemonic(KeyEvent.VK_N); @@ -417,14 +406,11 @@ public class BasicFrame extends JFrame { public void actionPerformed(ActionEvent e) { log.user("New... selected"); newAction(); - if (replaceable) { - log.info("Closing previous window"); - closeAction(); - } + closeIfReplaceable(); } }); menu.add(item); - + //// Open... item = new JMenuItem(trans.get("main.menu.file.open"), KeyEvent.VK_O); item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK)); @@ -439,7 +425,14 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - + + //// Open Recent... + item = new MRUDesignFileAction(trans.get("main.menu.file.openRecent"), this); + //// Open a recent rocket design + item.getAccessibleContext().setAccessibleDescription(trans.get("BasicFrame.item.Openrecentrocketdesign")); + item.setIcon(Icons.FILE_OPEN); + menu.add(item); + //// Open example... item = new JMenuItem(trans.get("main.menu.file.openExample")); //// Open an example rocket design @@ -461,9 +454,9 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - + menu.addSeparator(); - + //// Save item = new JMenuItem(trans.get("main.menu.file.save"), KeyEvent.VK_S); item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK)); @@ -478,7 +471,7 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - + //// Save as... item = new JMenuItem(trans.get("main.menu.file.saveAs"), KeyEvent.VK_A); item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, @@ -494,7 +487,7 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - + //// Print... item = new JMenuItem(trans.get("main.menu.file.print"), KeyEvent.VK_P); item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.CTRL_MASK)); @@ -509,10 +502,10 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - + + menu.addSeparator(); - + //// Close item = new JMenuItem(trans.get("main.menu.file.close"), KeyEvent.VK_C); item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, ActionEvent.CTRL_MASK)); @@ -527,9 +520,9 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - + menu.addSeparator(); - + //// Quit item = new JMenuItem(trans.get("main.menu.file.quit"), KeyEvent.VK_Q); item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK)); @@ -544,26 +537,26 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - - + + + //// Edit menu = new JMenu(trans.get("main.menu.edit")); menu.setMnemonic(KeyEvent.VK_E); //// Rocket editing menu.getAccessibleContext().setAccessibleDescription(trans.get("BasicFrame.menu.Rocketedt")); menubar.add(menu); - - + + Action action = UndoRedoAction.newUndoAction(document); item = new JMenuItem(action); item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, ActionEvent.CTRL_MASK)); item.setMnemonic(KeyEvent.VK_U); //// Undo the previous operation item.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.edit.undo.desc")); - + menu.add(item); - + action = UndoRedoAction.newRedoAction(document); item = new JMenuItem(action); item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, ActionEvent.CTRL_MASK)); @@ -571,26 +564,26 @@ public class BasicFrame extends JFrame { //// Redo the previously undone operation item.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.edit.redo.desc")); menu.add(item); - + menu.addSeparator(); - - + + item = new JMenuItem(actions.getCutAction()); menu.add(item); - + item = new JMenuItem(actions.getCopyAction()); menu.add(item); - + item = new JMenuItem(actions.getPasteAction()); menu.add(item); - + item = new JMenuItem(actions.getDeleteAction()); menu.add(item); - + menu.addSeparator(); - - - + + + item = new JMenuItem(trans.get("main.menu.edit.resize")); item.setIcon(Icons.EDIT_SCALE); item.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.edit.resize.desc")); @@ -604,9 +597,9 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - - + + + //// Preferences item = new JMenuItem(trans.get("main.menu.edit.preferences")); item.setIcon(Icons.PREFERENCES); @@ -620,17 +613,17 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - - - + + + + //// Analyze menu = new JMenu(trans.get("main.menu.analyze")); menu.setMnemonic(KeyEvent.VK_A); //// Analyzing the rocket menu.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.analyze.desc")); menubar.add(menu); - + //// Component analysis item = new JMenuItem(trans.get("main.menu.analyze.componentAnalysis"), KeyEvent.VK_C); //// Analyze the rocket components separately @@ -643,8 +636,8 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - + + item = new JMenuItem(trans.get("main.menu.analyze.optimization"), KeyEvent.VK_O); item.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.analyze.optimization.desc")); item.addActionListener(new ActionListener() { @@ -655,27 +648,27 @@ 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 - + menu = new JMenu(trans.get("main.menu.help")); menu.setMnemonic(KeyEvent.VK_H); menu.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.help.desc")); menubar.add(menu); - - + + // Guided tours - + item = new JMenuItem(trans.get("main.menu.help.tours"), KeyEvent.VK_L); item.setIcon(Icons.HELP_TOURS); item.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.help.tours.desc")); @@ -683,14 +676,13 @@ public class BasicFrame extends JFrame { @Override public void actionPerformed(ActionEvent e) { log.user("Guided tours selected"); - // FIXME: Singleton - new GuidedTourSelectionDialog(BasicFrame.this).setVisible(true); + GuidedTourSelectionDialog.showDialog(BasicFrame.this); } }); menu.add(item); - + menu.addSeparator(); - + //// Bug report item = new JMenuItem(trans.get("main.menu.help.bugReport"), KeyEvent.VK_B); item.setIcon(Icons.HELP_BUG_REPORT); @@ -703,7 +695,7 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - + //// Debug log item = new JMenuItem(trans.get("main.menu.help.debugLog")); item.setIcon(Icons.HELP_DEBUG_LOG); @@ -716,10 +708,10 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - + menu.addSeparator(); - - + + //// License item = new JMenuItem(trans.get("main.menu.help.license"), KeyEvent.VK_L); item.setIcon(Icons.HELP_LICENSE); @@ -732,8 +724,8 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - + + //// About item = new JMenuItem(trans.get("main.menu.help.about"), KeyEvent.VK_A); item.setIcon(Icons.HELP_ABOUT); @@ -746,24 +738,24 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - + + this.setJMenuBar(menubar); } - + private JMenu makeDebugMenu() { JMenu menu; JMenuItem item; - + /* * This menu is intentionally left untranslated. */ - + //// Debug menu menu = new JMenu("Debug"); //// OpenRocket debugging tasks menu.getAccessibleContext().setAccessibleDescription("OpenRocket debugging tasks"); - + //// What is this menu? item = new JMenuItem("What is this menu?"); item.addActionListener(new ActionListener() { @@ -781,9 +773,9 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - + menu.addSeparator(); - + //// Create test rocket item = new JMenuItem("Create test rocket"); item.addActionListener(new ActionListener() { @@ -798,7 +790,7 @@ public class BasicFrame extends JFrame { JOptionPane.QUESTION_MESSAGE, null, new Object[] { "Random", "OK" }, "OK"); - + Rocket r; if (sel == 0) { r = new TestRockets(null).makeTestRocket(); @@ -807,7 +799,7 @@ public class BasicFrame extends JFrame { } else { return; } - + OpenRocketDocument doc = new OpenRocketDocument(r); doc.setSaved(true); BasicFrame frame = new BasicFrame(doc); @@ -815,9 +807,9 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - - + + + item = new JMenuItem("Create 'Iso-Haisu'"); item.addActionListener(new ActionListener() { @Override @@ -831,8 +823,8 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - + + item = new JMenuItem("Create 'Big Blue'"); item.addActionListener(new ActionListener() { @Override @@ -846,16 +838,16 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - + menu.addSeparator(); - - + + item = new JMenuItem("Memory statistics"); item.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { log.user("Memory statistics selected"); - + // Get discarded but remaining objects (this also runs System.gc multiple times) List objects = MemoryManagement.getRemainingCollectableObjects(); StringBuilder sb = new StringBuilder(); @@ -872,7 +864,7 @@ public class BasicFrame extends JFrame { o = null; } sb.append("Total: " + count); - + // Get basic memory stats System.gc(); long max = Runtime.getRuntime().maxMemory(); @@ -883,14 +875,14 @@ public class BasicFrame extends JFrame { stats[1] = String.format(" Max memory: %.1f MB", max / 1024.0 / 1024.0); stats[2] = String.format(" Used memory: %.1f MB (%.0f%%)", used / 1024.0 / 1024.0, 100.0 * used / max); stats[3] = String.format(" Free memory: %.1f MB (%.0f%%)", free / 1024.0 / 1024.0, 100.0 * free / max); - - + + DetailDialog.showDetailedMessageDialog(BasicFrame.this, stats, sb.toString(), "Memory statistics", JOptionPane.INFORMATION_MESSAGE); } }); menu.add(item); - + //// Exhaust memory item = new JMenuItem("Exhaust memory"); item.addActionListener(new ActionListener() { @@ -920,10 +912,10 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - + + menu.addSeparator(); - + //// Exception here item = new JMenuItem("Exception here"); item.addActionListener(new ActionListener() { @@ -934,7 +926,7 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - + item = new JMenuItem("Exception from EDT"); item.addActionListener(new ActionListener() { @Override @@ -950,7 +942,7 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - + item = new JMenuItem("Exception from other thread"); item.addActionListener(new ActionListener() { @Override @@ -965,7 +957,7 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - + item = new JMenuItem("OutOfMemoryError here"); item.addActionListener(new ActionListener() { @Override @@ -975,11 +967,11 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - + + menu.addSeparator(); - - + + item = new JMenuItem("Test popup"); item.addActionListener(new ActionListener() { @Override @@ -995,33 +987,33 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - - - + + + + return menu; } - - + + /** * Select the tab on the main pane. - * + * * @param tab one of {@link #COMPONENT_TAB} or {@link #SIMULATION_TAB}. */ public void selectTab(int tab) { tabbedPane.setSelectedIndex(tab); } - - - + + + private void openAction() { JFileChooser chooser = new JFileChooser(); - + chooser.addChoosableFileFilter(FileHelper.ALL_DESIGNS_FILTER); chooser.addChoosableFileFilter(FileHelper.OPENROCKET_DESIGN_FILTER); chooser.addChoosableFileFilter(FileHelper.ROCKSIM_DESIGN_FILTER); chooser.setFileFilter(FileHelper.ALL_DESIGNS_FILTER); - + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); chooser.setMultiSelectionEnabled(true); chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory()); @@ -1030,31 +1022,33 @@ public class BasicFrame extends JFrame { log.user("Decided not to open files, option=" + option); return; } - + ((SwingPreferences) Application.getPreferences()).setDefaultDirectory(chooser.getCurrentDirectory()); - + File[] files = chooser.getSelectedFiles(); log.user("Opening files " + Arrays.toString(files)); - + for (File file : files) { log.info("Opening file: " + file); if (open(file, this)) { - - // Close previous window if replacing - if (replaceable && document.isSaved()) { - // We are replacing the frame, make new window have current location - BasicFrame newFrame = frames.get(frames.size() - 1); - newFrame.setLocation(this.getLocation()); - - log.info("Closing window because it is replaceable"); - closeAction(); - replaceable = false; - } + MRUDesignFile opts = MRUDesignFile.getInstance(); + opts.addFile(file.getAbsolutePath()); } } } - - + + void closeIfReplaceable() { + // Close previous window if replacing + if (replaceable && document.isSaved()) { + // We are replacing the frame, make new window have current location + BasicFrame newFrame = frames.get(frames.size() - 1); + newFrame.setLocation(this.getLocation()); + + log.info("Closing window because it is replaceable"); + closeAction(); + } + + } /** * Open a file based on a URL. * @param url the file to open. @@ -1063,16 +1057,16 @@ public class BasicFrame extends JFrame { */ private static boolean open(URL url, BasicFrame parent) { String filename = null; - + // First figure out the file name from the URL - + // Try using URI.getPath(); try { URI uri = url.toURI(); filename = uri.getPath(); } catch (URISyntaxException ignore) { } - + // Try URL-decoding the URL if (filename == null) { try { @@ -1080,44 +1074,38 @@ public class BasicFrame extends JFrame { } catch (UnsupportedEncodingException ignore) { } } - + // Last resort if (filename == null) { filename = ""; } - + // Remove path from filename if (filename.lastIndexOf('/') >= 0) { filename = filename.substring(filename.lastIndexOf('/') + 1); } - - + + // Open the file log.info("Opening file from url=" + url + " filename=" + filename); try { InputStream is = url.openStream(); - if (open(is, filename, parent)) { - // Close previous window if replacing - if (parent.replaceable && parent.document.isSaved()) { - parent.closeAction(); - parent.replaceable = false; - } - } + open(is, filename, parent); } catch (IOException e) { log.warn("Error opening file" + 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 false 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. @@ -1127,12 +1115,12 @@ public class BasicFrame extends JFrame { 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 false 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. @@ -1141,11 +1129,11 @@ public class BasicFrame extends JFrame { 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). @@ -1153,9 +1141,9 @@ public class BasicFrame extends JFrame { * @return */ private static boolean open(OpenFileWorker worker, String filename, File file, Window parent) { - + MotorDatabaseLoadingDialog.check(parent); - + // Open the file in a Swing worker thread log.info("Starting OpenFileWorker"); if (!SwingWorkerDialog.runWorker(parent, "Opening file", "Reading " + filename + "...", worker)) { @@ -1163,50 +1151,50 @@ public class BasicFrame extends JFrame { log.info("User cancelled the OpenFileWorker"); return false; } - - + + // Handle the document OpenRocketDocument doc = null; try { - + doc = worker.get(); - + } catch (ExecutionException e) { - + Throwable cause = e.getCause(); - + if (cause instanceof FileNotFoundException) { - + log.warn("File not found", cause); JOptionPane.showMessageDialog(parent, "File not found: " + filename, "Error opening file", JOptionPane.ERROR_MESSAGE); return false; - + } else if (cause instanceof RocketLoadException) { - + log.warn("Error loading the file", cause); JOptionPane.showMessageDialog(parent, "Unable to open file '" + filename + "': " + cause.getMessage(), "Error opening file", JOptionPane.ERROR_MESSAGE); return false; - + } else { - + throw new BugException("Unknown error when opening file", e); - + } - + } catch (InterruptedException e) { throw new BugException("EDT was interrupted", e); } - + if (doc == null) { throw new BugException("Document loader returned null"); } - - + + // Show warnings WarningSet warnings = worker.getRocketLoader().getWarnings(); if (!warnings.isEmpty()) { @@ -1221,21 +1209,24 @@ public class BasicFrame extends JFrame { //// Warnings while opening file trans.get("BasicFrame.WarningDialog.title"), warnings); } - - + + // Set document state doc.setFile(file); doc.setSaved(true); - - + + // Open the frame log.debug("Opening new frame with the document"); BasicFrame frame = new BasicFrame(doc); frame.setVisible(true); - + + if ( parent != null && parent instanceof BasicFrame ) { + ((BasicFrame)parent).closeIfReplaceable(); + } return true; } - + /** * "Save" action. If the design is new, then this is identical to "Save As", with a default file filter for .ork. * If the rocket being edited previously was opened from a .ork file, then it will be saved immediately to the same @@ -1251,13 +1242,13 @@ public class BasicFrame extends JFrame { return saveAsAction(); } log.info("Saving document to " + file); - + if (FileHelper.ROCKSIM_DESIGN_FILTER.accept(file)) { return saveAsRocksim(file); } return saveAs(file); } - + /** * "Save As" action. * @@ -1272,13 +1263,13 @@ public class BasicFrame extends JFrame { */ private boolean saveAsAction() { File file = null; - + StorageOptionChooser storageChooser = new StorageOptionChooser(document, document.getDefaultStorageOptions()); final JFileChooser chooser = new JFileChooser(); chooser.addChoosableFileFilter(FileHelper.OPENROCKET_DESIGN_FILTER); chooser.addChoosableFileFilter(FileHelper.ROCKSIM_DESIGN_FILTER); - + //Force the file filter to match the file extension that was opened. Will default to OR if the file is null. if (FileHelper.ROCKSIM_DESIGN_FILTER.accept(document.getFile())) { chooser.setFileFilter(FileHelper.ROCKSIM_DESIGN_FILTER); @@ -1291,22 +1282,22 @@ public class BasicFrame extends JFrame { if (document.getFile() != null) { chooser.setSelectedFile(document.getFile()); } - + int option = chooser.showSaveDialog(BasicFrame.this); if (option != JFileChooser.APPROVE_OPTION) { log.user("User decided not to save, option=" + option); return false; } - + file = chooser.getSelectedFile(); if (file == null) { log.user("User did not select a file"); return false; } - + ((SwingPreferences) Application.getPreferences()).setDefaultDirectory(chooser.getCurrentDirectory()); storageChooser.storeOptions(document.getDefaultStorageOptions()); - + if (chooser.getFileFilter().equals(FileHelper.ROCKSIM_DESIGN_FILTER)) { return saveAsRocksim(file); } @@ -1315,7 +1306,7 @@ public class BasicFrame extends JFrame { return FileHelper.confirmWrite(file, this) && saveAs(file); } } - + /** * Perform the writing of the design to the given file in Rocksim format. * @@ -1328,7 +1319,7 @@ public class BasicFrame extends JFrame { if (!FileHelper.confirmWrite(file, this)) { return false; } - + try { new RocksimSaver().save(file, document); return true; @@ -1336,7 +1327,7 @@ public class BasicFrame extends JFrame { return false; } } - + /** * Perform the writing of the design to the given file in OpenRocket format. * @@ -1347,25 +1338,25 @@ public class BasicFrame extends JFrame { private boolean saveAs(File file) { log.info("Saving document as " + file); boolean saved = false; - + if (!StorageOptionChooser.verifyStorageOptions(document, this)) { // User cancelled the dialog log.user("User cancelled saving in storage options dialog"); return false; } - - + + SaveFileWorker worker = new SaveFileWorker(document, file, ROCKET_SAVER); - + if (!SwingWorkerDialog.runWorker(this, "Saving file", "Writing " + file.getName() + "...", worker)) { - + // User cancelled the save log.user("User cancelled the save, deleting the file"); file.delete(); return false; } - + try { worker.get(); document.setFile(file); @@ -1373,9 +1364,9 @@ public class BasicFrame extends JFrame { saved = true; setTitle(); } catch (ExecutionException e) { - + Throwable cause = e.getCause(); - + if (cause instanceof IOException) { log.warn("An I/O error occurred while saving " + file, cause); JOptionPane.showMessageDialog(this, new String[] { @@ -1385,15 +1376,15 @@ public class BasicFrame extends JFrame { } else { Reflection.handleWrappedException(e); } - + } catch (InterruptedException e) { throw new BugException("EDT was interrupted", e); } - + return saved; } - - + + private boolean closeAction() { if (!document.isSaved()) { log.info("Confirming whether to save the design"); @@ -1420,14 +1411,14 @@ public class BasicFrame extends JFrame { return false; } } - + // Rocket has been saved or discarded log.debug("Disposing window"); this.dispose(); - + ComponentConfigDialog.hideDialog(); ComponentAnalysisDialog.hideDialog(); - + frames.remove(this); if (frames.isEmpty()) { log.info("Last frame closed, exiting"); @@ -1435,22 +1426,26 @@ public class BasicFrame extends JFrame { } return true; } - - - + + + /** - * + * */ public void printAction() { - new PrintDialog(this, document).setVisible(true); + Double rotation = rocketpanel.getFigure().getRotation(); + if (rotation == null) { + rotation = 0d; + } + new PrintDialog(this, document, rotation).setVisible(true); } - + /** * Open a new design window with a basic rocket+stage. */ public static void newAction() { log.info("New action initiated"); - + Rocket rocket = new Rocket(); Stage stage = new Stage(); //// Sustainer @@ -1458,13 +1453,14 @@ public class BasicFrame extends JFrame { rocket.addChild(stage); OpenRocketDocument doc = new OpenRocketDocument(rocket); doc.setSaved(true); - + BasicFrame frame = new BasicFrame(doc); frame.replaceable = true; frame.setVisible(true); - ComponentConfigDialog.showDialog(frame, doc, rocket); + // FIXME - kruland commented this out - I don't like it. + //ComponentConfigDialog.showDialog(frame, doc, rocket); } - + /** * Quit the application. Confirms saving unsaved designs. The action of File->Quit. */ @@ -1482,33 +1478,33 @@ public class BasicFrame extends JFrame { log.error("Should already have exited application"); System.exit(0); } - - + + /** - * Set the title of the frame, taking into account the name of the rocket, file it + * Set the title of the frame, taking into account the name of the rocket, file it * has been saved to (if any) and saved status. */ private void setTitle() { File file = document.getFile(); boolean saved = document.isSaved(); String title; - + title = rocket.getName(); if (file != null) { title = title + " (" + file.getName() + ")"; } if (!saved) title = "*" + title; - + setTitle(title); } - - - + + + /** * Find a currently open BasicFrame containing the specified rocket. This method * can be used to map a Rocket to a BasicFrame from GUI methods. - * + * * @param rocket the Rocket. * @return the corresponding BasicFrame, or null if none found. */ @@ -1522,11 +1518,11 @@ public class BasicFrame extends JFrame { log.debug("Could not find frame for rocket " + rocket); return null; } - + /** * Find a currently open document by the rocket object. This method can be used * to map a Rocket to OpenRocketDocument from GUI methods. - * + * * @param rocket the Rocket. * @return the corresponding OpenRocketDocument, or null if not found. */