1 package net.sf.openrocket.gui.main;
3 import java.awt.Dimension;
5 import java.awt.Toolkit;
6 import java.awt.event.ActionEvent;
7 import java.awt.event.ActionListener;
8 import java.awt.event.ComponentAdapter;
9 import java.awt.event.ComponentEvent;
10 import java.awt.event.KeyEvent;
11 import java.awt.event.MouseAdapter;
12 import java.awt.event.MouseEvent;
13 import java.awt.event.MouseListener;
14 import java.awt.event.WindowAdapter;
15 import java.awt.event.WindowEvent;
17 import java.io.IOException;
18 import java.util.ArrayList;
19 import java.util.Iterator;
21 import javax.swing.Action;
22 import javax.swing.InputMap;
23 import javax.swing.JButton;
24 import javax.swing.JComponent;
25 import javax.swing.JFileChooser;
26 import javax.swing.JFrame;
27 import javax.swing.JMenu;
28 import javax.swing.JMenuBar;
29 import javax.swing.JMenuItem;
30 import javax.swing.JOptionPane;
31 import javax.swing.JPanel;
32 import javax.swing.JScrollPane;
33 import javax.swing.JSeparator;
34 import javax.swing.JSplitPane;
35 import javax.swing.JTabbedPane;
36 import javax.swing.KeyStroke;
37 import javax.swing.ListSelectionModel;
38 import javax.swing.LookAndFeel;
39 import javax.swing.ScrollPaneConstants;
40 import javax.swing.SwingUtilities;
41 import javax.swing.ToolTipManager;
42 import javax.swing.UIManager;
43 import javax.swing.border.TitledBorder;
44 import javax.swing.event.TreeSelectionEvent;
45 import javax.swing.event.TreeSelectionListener;
46 import javax.swing.filechooser.FileFilter;
47 import javax.swing.tree.DefaultTreeSelectionModel;
48 import javax.swing.tree.TreePath;
49 import javax.swing.tree.TreeSelectionModel;
51 import net.miginfocom.swing.MigLayout;
52 import net.sf.openrocket.aerodynamics.Warning;
53 import net.sf.openrocket.document.OpenRocketDocument;
54 import net.sf.openrocket.file.GeneralRocketLoader;
55 import net.sf.openrocket.file.OpenRocketSaver;
56 import net.sf.openrocket.file.RocketLoadException;
57 import net.sf.openrocket.file.RocketLoader;
58 import net.sf.openrocket.file.RocketSaver;
59 import net.sf.openrocket.gui.ComponentAnalysisDialog;
60 import net.sf.openrocket.gui.PreferencesDialog;
61 import net.sf.openrocket.gui.StorageOptionChooser;
62 import net.sf.openrocket.gui.configdialog.ComponentConfigDialog;
63 import net.sf.openrocket.gui.dialogs.BugDialog;
64 import net.sf.openrocket.gui.scalefigure.RocketPanel;
65 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
66 import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
67 import net.sf.openrocket.rocketcomponent.Rocket;
68 import net.sf.openrocket.rocketcomponent.RocketComponent;
69 import net.sf.openrocket.rocketcomponent.Stage;
70 import net.sf.openrocket.util.Icons;
71 import net.sf.openrocket.util.Prefs;
73 public class BasicFrame extends JFrame {
74 private static final long serialVersionUID = 1L;
77 * The RocketLoader instance used for loading all rocket designs.
79 private static final RocketLoader ROCKET_LOADER = new GeneralRocketLoader();
83 * File filter for filtering only rocket designs.
85 private static final FileFilter ROCKET_DESIGN_FILTER = new FileFilter() {
87 public String getDescription() {
88 return "OpenRocket designs (*.ork)";
91 public boolean accept(File f) {
94 String name = f.getName().toLowerCase();
95 return name.endsWith(".ork") || name.endsWith(".ork.gz");
101 public static final int COMPONENT_TAB = 0;
102 public static final int SIMULATION_TAB = 1;
106 * List of currently open frames. When the list goes empty
107 * it is time to exit the application.
109 private static final ArrayList<BasicFrame> frames = new ArrayList<BasicFrame>();
116 * Whether "New" and "Open" should replace this frame.
117 * Should be set to false on the first rocket modification.
119 private boolean replaceable = false;
123 private final OpenRocketDocument document;
124 private final Rocket rocket;
126 private JTabbedPane tabbedPane;
127 private RocketPanel rocketpanel;
128 private ComponentTree tree = null;
130 private final DocumentSelectionModel selectionModel;
131 private final TreeSelectionModel componentSelectionModel;
132 private final ListSelectionModel simulationSelectionModel;
134 /** Actions available for rocket modifications */
135 private final RocketActions actions;
140 * Sole constructor. Creates a new frame based on the supplied document
141 * and adds it to the current frames list.
143 * @param document the document to show.
145 public BasicFrame(OpenRocketDocument document) {
147 this.document = document;
148 this.rocket = document.getRocket();
149 this.rocket.getDefaultConfiguration().setAllStages();
152 // Set replaceable flag to false at first modification
153 rocket.addComponentChangeListener(new ComponentChangeListener() {
154 public void componentChanged(ComponentChangeEvent e) {
156 BasicFrame.this.rocket.removeComponentChangeListener(this);
161 // Create the component tree selection model that will be used
162 componentSelectionModel = new DefaultTreeSelectionModel();
163 componentSelectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
165 // Obtain the simulation selection model that will be used
166 SimulationPanel simulationPanel = new SimulationPanel(document);
167 simulationSelectionModel = simulationPanel.getSimulationListSelectionModel();
169 // Combine into a DocumentSelectionModel
170 selectionModel = new DocumentSelectionModel(document);
171 selectionModel.attachComponentTreeSelectionModel(componentSelectionModel);
172 selectionModel.attachSimulationListSelectionModel(simulationSelectionModel);
175 actions = new RocketActions(document, selectionModel, this);
178 // The main vertical split pane
179 JSplitPane vertical = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true);
180 vertical.setResizeWeight(0.5);
184 // The top tabbed pane
185 tabbedPane = new JTabbedPane();
186 tabbedPane.addTab("Rocket design", null, designTab());
187 tabbedPane.addTab("Flight simulations", null, simulationPanel);
189 vertical.setTopComponent(tabbedPane);
193 // Bottom segment, rocket figure
195 rocketpanel = new RocketPanel(document);
196 vertical.setBottomComponent(rocketpanel);
198 rocketpanel.setSelectionModel(tree.getSelectionModel());
204 rocket.addComponentChangeListener(new ComponentChangeListener() {
205 public void componentChanged(ComponentChangeEvent e) {
213 Dimension size = Prefs.getWindowSize(this.getClass());
215 size = Toolkit.getDefaultToolkit().getScreenSize();
216 size.width = size.width*9/10;
217 size.height = size.height*9/10;
220 this.addComponentListener(new ComponentAdapter() {
222 public void componentResized(ComponentEvent e) {
223 Prefs.setWindowSize(BasicFrame.this.getClass(), BasicFrame.this.getSize());
226 this.setLocationByPlatform(true);
229 vertical.setDividerLocation(0.4);
230 setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
231 addWindowListener(new WindowAdapter() {
233 public void windowClosing(WindowEvent e) {
243 * Construct the "Rocket design" tab. This contains a horizontal split pane
244 * with the left component the design tree and the right component buttons
245 * for adding components.
247 private JComponent designTab() {
248 JSplitPane horizontal = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,true);
249 horizontal.setResizeWeight(0.5);
252 // Upper-left segment, component tree
254 JPanel panel = new JPanel(new MigLayout("fill, flowy","","[grow]"));
256 tree = new ComponentTree(rocket);
257 tree.setSelectionModel(componentSelectionModel);
259 // Remove JTree key events that interfere with menu accelerators
260 InputMap im = SwingUtilities.getUIInputMap(tree, JComponent.WHEN_FOCUSED);
261 im.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.CTRL_MASK), null);
262 im.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK), null);
263 im.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, ActionEvent.CTRL_MASK), null);
264 im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, ActionEvent.CTRL_MASK), null);
265 im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK), null);
266 im.put(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK), null);
267 im.put(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK), null);
271 // Double-click opens config dialog
272 MouseListener ml = new MouseAdapter() {
274 public void mousePressed(MouseEvent e) {
275 int selRow = tree.getRowForLocation(e.getX(), e.getY());
276 TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
278 if(e.getClickCount() == 2) {
280 RocketComponent c = (RocketComponent)selPath.getLastPathComponent();
281 ComponentConfigDialog.showDialog(BasicFrame.this,
282 BasicFrame.this.document, c);
287 tree.addMouseListener(ml);
289 // Update dialog when selection is changed
290 componentSelectionModel.addTreeSelectionListener(new TreeSelectionListener() {
291 public void valueChanged(TreeSelectionEvent e) {
292 // Scroll tree to the selected item
293 TreePath path = componentSelectionModel.getSelectionPath();
296 tree.scrollPathToVisible(path);
298 if (!ComponentConfigDialog.isDialogVisible())
300 RocketComponent c = (RocketComponent)path.getLastPathComponent();
301 ComponentConfigDialog.showDialog(BasicFrame.this,
302 BasicFrame.this.document, c);
306 // Place tree inside scroll pane
307 JScrollPane scroll = new JScrollPane(tree);
308 panel.add(scroll,"spany, grow, wrap");
312 JButton button = new JButton(actions.getMoveUpAction());
313 panel.add(button,"sizegroup buttons, aligny 65%");
315 button = new JButton(actions.getMoveDownAction());
316 panel.add(button,"sizegroup buttons, aligny 0%");
318 button = new JButton(actions.getEditAction());
319 panel.add(button, "sizegroup buttons");
321 button = new JButton(actions.getNewStageAction());
322 panel.add(button,"sizegroup buttons");
324 button = new JButton(actions.getDeleteAction());
325 button.setIcon(null);
326 button.setMnemonic(0);
327 panel.add(button,"sizegroup buttons");
329 horizontal.setLeftComponent(panel);
332 // Upper-right segment, component addition buttons
334 panel = new JPanel(new MigLayout("fill, insets 0","[0::]"));
336 scroll = new JScrollPane(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
337 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
338 scroll.setViewportView(new ComponentAddButtons(document, componentSelectionModel,
339 scroll.getViewport()));
340 scroll.setBorder(null);
341 scroll.setViewportBorder(null);
343 TitledBorder border = new TitledBorder("Add new component");
344 border.setTitleFont(border.getTitleFont().deriveFont(Font.BOLD));
345 scroll.setBorder(border);
347 panel.add(scroll,"grow");
349 horizontal.setRightComponent(panel);
357 * Creates the menu for the window.
359 private void createMenu() {
360 JMenuBar menubar = new JMenuBar();
365 menu = new JMenu("File");
366 menu.setMnemonic(KeyEvent.VK_F);
367 menu.getAccessibleContext().setAccessibleDescription("File-handling related tasks");
370 item = new JMenuItem("New",KeyEvent.VK_N);
371 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK));
372 item.setMnemonic(KeyEvent.VK_N);
373 item.getAccessibleContext().setAccessibleDescription("Create a new rocket design");
374 item.setIcon(Icons.FILE_NEW);
375 item.addActionListener(new ActionListener() {
376 public void actionPerformed(ActionEvent e) {
384 item = new JMenuItem("Open...",KeyEvent.VK_O);
385 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
386 item.getAccessibleContext().setAccessibleDescription("Open a rocket design");
387 item.setIcon(Icons.FILE_OPEN);
388 item.addActionListener(new ActionListener() {
389 public void actionPerformed(ActionEvent e) {
397 item = new JMenuItem("Save",KeyEvent.VK_S);
398 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK));
399 item.getAccessibleContext().setAccessibleDescription("Save the current rocket design");
400 item.setIcon(Icons.FILE_SAVE);
401 item.addActionListener(new ActionListener() {
402 public void actionPerformed(ActionEvent e) {
408 item = new JMenuItem("Save as...",KeyEvent.VK_A);
409 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
410 ActionEvent.CTRL_MASK | ActionEvent.SHIFT_MASK));
411 item.getAccessibleContext().setAccessibleDescription("Save the current rocket design "+
413 item.setIcon(Icons.FILE_SAVE_AS);
414 item.addActionListener(new ActionListener() {
415 public void actionPerformed(ActionEvent e) {
421 // menu.addSeparator();
422 menu.add(new JSeparator());
424 item = new JMenuItem("Close",KeyEvent.VK_C);
425 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, ActionEvent.CTRL_MASK));
426 item.getAccessibleContext().setAccessibleDescription("Close the current rocket design");
427 item.setIcon(Icons.FILE_CLOSE);
428 item.addActionListener(new ActionListener() {
429 public void actionPerformed(ActionEvent e) {
437 item = new JMenuItem("Quit",KeyEvent.VK_Q);
438 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK));
439 item.getAccessibleContext().setAccessibleDescription("Quit the program");
440 item.setIcon(Icons.FILE_QUIT);
441 item.addActionListener(new ActionListener() {
442 public void actionPerformed(ActionEvent e) {
451 menu = new JMenu("Edit");
452 menu.setMnemonic(KeyEvent.VK_E);
453 menu.getAccessibleContext().setAccessibleDescription("Rocket editing");
457 Action action = document.getUndoAction();
458 item = new JMenuItem(action);
459 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, ActionEvent.CTRL_MASK));
460 item.setMnemonic(KeyEvent.VK_U);
461 item.getAccessibleContext().setAccessibleDescription("Undo the previous operation");
465 action = document.getRedoAction();
466 item = new JMenuItem(action);
467 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, ActionEvent.CTRL_MASK));
468 item.setMnemonic(KeyEvent.VK_R);
469 item.getAccessibleContext().setAccessibleDescription("Redo the previously undone " +
476 item = new JMenuItem(actions.getCutAction());
479 item = new JMenuItem(actions.getCopyAction());
482 item = new JMenuItem(actions.getPasteAction());
485 item = new JMenuItem(actions.getDeleteAction());
490 item = new JMenuItem("Preferences");
491 item.setIcon(Icons.PREFERENCES);
492 item.getAccessibleContext().setAccessibleDescription("Setup the application "+
494 item.addActionListener(new ActionListener() {
495 public void actionPerformed(ActionEvent e) {
496 PreferencesDialog.showPreferences();
505 menu = new JMenu("Analyze");
506 menu.setMnemonic(KeyEvent.VK_A);
507 menu.getAccessibleContext().setAccessibleDescription("Analyzing the rocket");
510 item = new JMenuItem("Component analysis",KeyEvent.VK_C);
511 item.getAccessibleContext().setAccessibleDescription("Analyze the rocket components " +
513 item.addActionListener(new ActionListener() {
514 public void actionPerformed(ActionEvent e) {
515 ComponentAnalysisDialog.showDialog(rocketpanel);
524 menu = new JMenu("Help");
525 menu.setMnemonic(KeyEvent.VK_H);
526 menu.getAccessibleContext().setAccessibleDescription("Information about OpenRocket");
531 item = new JMenuItem("License",KeyEvent.VK_L);
532 item.getAccessibleContext().setAccessibleDescription("OpenRocket license information");
533 item.addActionListener(new ActionListener() {
534 public void actionPerformed(ActionEvent e) {
535 new LicenseDialog(BasicFrame.this).setVisible(true);
540 item = new JMenuItem("Bug report",KeyEvent.VK_B);
541 item.getAccessibleContext().setAccessibleDescription("Information about reporting " +
542 "bugs in OpenRocket");
543 item.addActionListener(new ActionListener() {
544 public void actionPerformed(ActionEvent e) {
545 new BugDialog(BasicFrame.this).setVisible(true);
550 item = new JMenuItem("About",KeyEvent.VK_A);
551 item.getAccessibleContext().setAccessibleDescription("About OpenRocket");
552 item.addActionListener(new ActionListener() {
553 public void actionPerformed(ActionEvent e) {
554 new AboutDialog(BasicFrame.this).setVisible(true);
560 this.setJMenuBar(menubar);
566 * Select the tab on the main pane.
568 * @param tab one of {@link #COMPONENT_TAB} or {@link #SIMULATION_TAB}.
570 public void selectTab(int tab) {
571 tabbedPane.setSelectedIndex(tab);
576 private void openAction() {
577 JFileChooser chooser = new JFileChooser();
578 chooser.setFileFilter(ROCKET_DESIGN_FILTER);
579 chooser.setMultiSelectionEnabled(true);
580 chooser.setCurrentDirectory(Prefs.getDefaultDirectory());
581 if (chooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION)
584 Prefs.setDefaultDirectory(chooser.getCurrentDirectory());
586 File[] files = chooser.getSelectedFiles();
587 boolean opened = false;
589 for (File file: files) {
590 System.out.println("Opening file: " + file);
596 // Close this frame if replaceable and file opened successfully
597 if (replaceable && opened) {
604 * Open the specified file in a new design frame. If an error occurs, an error dialog
605 * is shown and <code>false</code> is returned.
607 * @param file the file to open.
608 * @return whether the file was successfully loaded and opened.
610 private static boolean open(File file) {
611 OpenRocketDocument doc = null;
613 doc = ROCKET_LOADER.load(file);
614 } catch (RocketLoadException e) {
615 JOptionPane.showMessageDialog(null, "Unable to open file '" + file.getName()
616 +"': " + e.getMessage(), "Error opening file", JOptionPane.ERROR_MESSAGE);
622 throw new RuntimeException("BUG: Rocket loader returned null");
626 Iterator<Warning> warns = ROCKET_LOADER.getWarnings().iterator();
627 System.out.println("Warnings:");
628 while (warns.hasNext()) {
629 System.out.println(" "+warns.next());
630 // TODO: HIGH: dialog
633 // Set document state
638 BasicFrame frame = new BasicFrame(doc);
639 frame.setVisible(true);
646 private boolean saveAction() {
647 File file = document.getFile();
649 return saveAsAction();
655 private boolean saveAsAction() {
657 while (file == null) {
658 StorageOptionChooser storageChooser =
659 new StorageOptionChooser(document.getDefaultStorageOptions());
660 JFileChooser chooser = new JFileChooser();
661 chooser.setFileFilter(ROCKET_DESIGN_FILTER);
662 chooser.setCurrentDirectory(Prefs.getDefaultDirectory());
663 chooser.setAccessory(storageChooser);
664 if (document.getFile() != null)
665 chooser.setSelectedFile(document.getFile());
667 if (chooser.showSaveDialog(BasicFrame.this) != JFileChooser.APPROVE_OPTION)
670 file = chooser.getSelectedFile();
674 Prefs.setDefaultDirectory(chooser.getCurrentDirectory());
675 storageChooser.storeOptions(document.getDefaultStorageOptions());
677 if (file.getName().indexOf('.') < 0) {
678 String name = file.getAbsolutePath();
679 name = name + ".ork";
680 file = new File(name);
684 int result = JOptionPane.showConfirmDialog(this,
685 "File '"+file.getName()+"' exists. Do you want to overwrite it?",
686 "File exists", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
687 if (result != JOptionPane.YES_OPTION)
696 private boolean saveAs(File file) {
697 System.out.println("Saving to file: " + file.getName());
698 boolean saved = false;
700 if (!StorageOptionChooser.verifyStorageOptions(document, this)) {
701 // User cancelled the dialog
705 RocketSaver saver = new OpenRocketSaver();
707 saver.save(file, document);
708 document.setFile(file);
709 document.setSaved(true);
711 } catch (IOException e) {
712 JOptionPane.showMessageDialog(this, new String[] {
713 "An I/O error occurred while saving:",
714 e.getMessage() }, "Saving failed", JOptionPane.ERROR_MESSAGE);
721 private boolean closeAction() {
722 if (!document.isSaved()) {
723 ComponentConfigDialog.hideDialog();
724 int result = JOptionPane.showConfirmDialog(this,
725 "Design '"+rocket.getName()+"' has not been saved. " +
726 "Do you want to save it?",
727 "Design not saved", JOptionPane.YES_NO_CANCEL_OPTION,
728 JOptionPane.QUESTION_MESSAGE);
729 if (result == JOptionPane.YES_OPTION) {
732 return false; // If save was interrupted
733 } else if (result == JOptionPane.NO_OPTION) {
741 // Rocket has been saved or discarded
744 // TODO: LOW: Close only dialogs that have this frame as their parent
745 ComponentConfigDialog.hideDialog();
746 ComponentAnalysisDialog.hideDialog();
749 if (frames.isEmpty())
755 * Open a new design window with a basic rocket+stage.
757 public static void newAction() {
758 Rocket rocket = new Rocket();
759 Stage stage = new Stage();
760 stage.setName("Sustainer");
761 rocket.addChild(stage);
762 OpenRocketDocument doc = new OpenRocketDocument(rocket);
765 BasicFrame frame = new BasicFrame(doc);
766 frame.replaceable = true;
767 frame.setVisible(true);
768 ComponentConfigDialog.showDialog(frame, doc, rocket);
772 * Quit the application. Confirms saving unsaved designs. The action of File->Quit.
774 public static void quitAction() {
775 for (int i=frames.size()-1; i>=0; i--) {
776 if (!frames.get(i).closeAction()) {
781 // Should not be reached, but just in case
787 * Set the title of the frame, taking into account the name of the rocket, file it
788 * has been saved to (if any) and saved status.
790 private void setTitle() {
791 File file = document.getFile();
792 boolean saved = document.isSaved();
795 title = rocket.getName();
797 title = title + " ("+file.getName()+")";
810 public static void main(String[] args) {
813 * Set the look-and-feel. On Linux, Motif/Metal is sometimes incorrectly used
814 * which is butt-ugly, so if the system l&f is Motif/Metal, we search for a few
815 * other alternatives.
818 UIManager.LookAndFeelInfo[] info = UIManager.getInstalledLookAndFeels();
819 // System.out.println("Available look-and-feels:");
820 // for (int i=0; i<info.length; i++) {
821 // System.out.println(" "+info[i]);
825 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
827 // Check whether we have an ugly L&F
828 LookAndFeel laf = UIManager.getLookAndFeel();
830 laf.getName().matches(".*[mM][oO][tT][iI][fF].*") ||
831 laf.getName().matches(".*[mM][eE][tT][aA][lL].*")) {
833 // Search for better LAF
834 for (UIManager.LookAndFeelInfo l: info) {
835 if (l.getName().matches(".*[gG][tT][kK].*")) {
836 UIManager.setLookAndFeel(l.getClassName());
839 if (l.getName().contains(".*[wW][iI][nN].*")) {
840 UIManager.setLookAndFeel(l.getClassName());
843 if (l.getName().contains(".*[mM][aA][cC].*")) {
844 UIManager.setLookAndFeel(l.getClassName());
849 } catch (Exception e) {
850 System.err.println("Error setting LAF: " + e);
853 // Set tooltip delay time. Tooltips are used in MotorChooserDialog extensively.
854 ToolTipManager.sharedInstance().setDismissDelay(30000);
858 Prefs.loadDefaultUnits();
861 // Check command-line for files
862 boolean opened = false;
863 for (String file: args) {
864 if (open(new File(file))) {