X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=core%2Fsrc%2Fnet%2Fsf%2Fopenrocket%2Fgui%2Fmain%2FBasicFrame.java;h=bdfcbd4a0a8a9218acacbf1c539b8d42bdc04005;hb=4095cb0dd61a75b7b6b0bd811f8e803af5b27919;hp=c05c1ba34dd82b9a39ded5737a5d2a9336445bb3;hpb=d50a8cec8f853189bbae90c25179b1971730fdac;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 c05c1ba3..bdfcbd4a 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; @@ -68,6 +11,7 @@ import net.sf.openrocket.file.openrocket.OpenRocketSaver; import net.sf.openrocket.file.rocksim.export.RocksimSaver; import net.sf.openrocket.gui.StorageOptionChooser; import net.sf.openrocket.gui.configdialog.ComponentConfigDialog; +import net.sf.openrocket.gui.customexpression.CustomExpressionDialog; import net.sf.openrocket.gui.dialogs.AboutDialog; import net.sf.openrocket.gui.dialogs.BugReportDialog; import net.sf.openrocket.gui.dialogs.ComponentAnalysisDialog; @@ -105,149 +49,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); @@ -257,12 +246,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 @@ -271,15 +260,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); @@ -289,9 +278,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 @@ -309,7 +298,7 @@ public class BasicFrame extends JFrame { } }; tree.addMouseListener(ml); - + // Update dialog when selection is changed componentSelectionModel.addTreeSelectionListener(new TreeSelectionListener() { @Override @@ -319,7 +308,7 @@ public class BasicFrame extends JFrame { if (path == null) return; tree.scrollPathToVisible(path); - + if (!ComponentConfigDialog.isDialogVisible()) return; RocketComponent c = (RocketComponent) path.getLastPathComponent(); @@ -327,57 +316,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. */ @@ -386,11 +375,11 @@ public class BasicFrame extends JFrame { if (path == null) return null; tree.scrollPathToVisible(path); - + return (RocketComponent) path.getLastPathComponent(); } - - + + /** * Creates the menu for the window. */ @@ -398,15 +387,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); @@ -418,14 +407,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)); @@ -440,7 +426,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 @@ -462,9 +455,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)); @@ -479,7 +472,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, @@ -495,7 +488,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)); @@ -510,10 +503,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)); @@ -528,9 +521,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)); @@ -545,26 +538,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)); @@ -572,26 +565,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")); @@ -605,9 +598,9 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - - + + + //// Preferences item = new JMenuItem(trans.get("main.menu.edit.preferences")); item.setIcon(Icons.PREFERENCES); @@ -621,17 +614,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 @@ -644,39 +637,49 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - + + //// Optimize 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() { @Override public void actionPerformed(ActionEvent e) { - log.user("Rocket optimization selected"); - new GeneralOptimizationDialog(document, BasicFrame.this).setVisible(true); + log.user("Rocket optimization selected"); + new GeneralOptimizationDialog(document, BasicFrame.this).setVisible(true); + } + }); + menu.add(item); + + //// Custom expressions + item = new JMenuItem(trans.get("main.menu.analyze.customExpressions"), KeyEvent.VK_E); + item.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.analyze.customExpressions.desc")); + item.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + log.debug("Custom expressions selected"); + new CustomExpressionDialog(document, BasicFrame.this).setVisible(true); } }); 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")); @@ -688,9 +691,9 @@ public class BasicFrame extends JFrame { } }); 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 +706,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 +719,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 +735,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 +749,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 +784,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 +801,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 +810,7 @@ public class BasicFrame extends JFrame { } else { return; } - + OpenRocketDocument doc = new OpenRocketDocument(r); doc.setSaved(true); BasicFrame frame = new BasicFrame(doc); @@ -815,9 +818,9 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - - + + + item = new JMenuItem("Create 'Iso-Haisu'"); item.addActionListener(new ActionListener() { @Override @@ -831,8 +834,8 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - + + item = new JMenuItem("Create 'Big Blue'"); item.addActionListener(new ActionListener() { @Override @@ -846,16 +849,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 +875,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 +886,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 +923,10 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - + + menu.addSeparator(); - + //// Exception here item = new JMenuItem("Exception here"); item.addActionListener(new ActionListener() { @@ -934,7 +937,7 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - + item = new JMenuItem("Exception from EDT"); item.addActionListener(new ActionListener() { @Override @@ -950,7 +953,7 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - + item = new JMenuItem("Exception from other thread"); item.addActionListener(new ActionListener() { @Override @@ -965,7 +968,7 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - + item = new JMenuItem("OutOfMemoryError here"); item.addActionListener(new ActionListener() { @Override @@ -975,11 +978,11 @@ public class BasicFrame extends JFrame { } }); menu.add(item); - - + + menu.addSeparator(); - - + + item = new JMenuItem("Test popup"); item.addActionListener(new ActionListener() { @Override @@ -995,33 +998,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 +1033,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 +1068,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 +1085,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 +1126,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 +1140,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 +1152,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 +1162,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 +1220,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 +1253,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 +1274,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 +1293,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 +1317,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 +1330,7 @@ public class BasicFrame extends JFrame { if (!FileHelper.confirmWrite(file, this)) { return false; } - + try { new RocksimSaver().save(file, document); return true; @@ -1336,7 +1338,7 @@ public class BasicFrame extends JFrame { return false; } } - + /** * Perform the writing of the design to the given file in OpenRocket format. * @@ -1347,25 +1349,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 +1375,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 +1387,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 +1422,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 +1437,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 +1464,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); + // 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 +1489,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 +1529,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. */