Bug fixes and startup checks
authorplaa <plaa@180e2498-e6e9-4542-8430-84ac67f01cd8>
Sun, 31 May 2009 17:50:09 +0000 (17:50 +0000)
committerplaa <plaa@180e2498-e6e9-4542-8430-84ac67f01cd8>
Sun, 31 May 2009 17:50:09 +0000 (17:50 +0000)
git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@6 180e2498-e6e9-4542-8430-84ac67f01cd8

54 files changed:
ChangeLog
build.xml
html/download.html
src/net/sf/openrocket/database/Database.java
src/net/sf/openrocket/file/openrocket/TransitionSaver.java
src/net/sf/openrocket/gui/BasicSlider.java [deleted file]
src/net/sf/openrocket/gui/ComponentAnalysisDialog.java
src/net/sf/openrocket/gui/DescriptionArea.java [deleted file]
src/net/sf/openrocket/gui/PreferencesDialog.java
src/net/sf/openrocket/gui/ResizeLabel.java [deleted file]
src/net/sf/openrocket/gui/StageSelector.java [deleted file]
src/net/sf/openrocket/gui/UnitSelector.java [deleted file]
src/net/sf/openrocket/gui/adaptors/MaterialModel.java
src/net/sf/openrocket/gui/adaptors/MotorConfigurationModel.java
src/net/sf/openrocket/gui/components/BasicSlider.java [new file with mode: 0644]
src/net/sf/openrocket/gui/components/DescriptionArea.java [new file with mode: 0644]
src/net/sf/openrocket/gui/components/ResizeLabel.java [new file with mode: 0644]
src/net/sf/openrocket/gui/components/StageSelector.java [new file with mode: 0644]
src/net/sf/openrocket/gui/components/URLLabel.java [new file with mode: 0644]
src/net/sf/openrocket/gui/components/UnitSelector.java [new file with mode: 0644]
src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java
src/net/sf/openrocket/gui/configdialog/EllipticalFinSetConfig.java
src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java
src/net/sf/openrocket/gui/configdialog/InnerTubeConfig.java
src/net/sf/openrocket/gui/configdialog/LaunchLugConfig.java
src/net/sf/openrocket/gui/configdialog/MassComponentConfig.java
src/net/sf/openrocket/gui/configdialog/MotorConfig.java
src/net/sf/openrocket/gui/configdialog/NoseConeConfig.java
src/net/sf/openrocket/gui/configdialog/ParachuteConfig.java
src/net/sf/openrocket/gui/configdialog/RingComponentConfig.java
src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
src/net/sf/openrocket/gui/configdialog/ShockCordConfig.java
src/net/sf/openrocket/gui/configdialog/StreamerConfig.java
src/net/sf/openrocket/gui/configdialog/TransitionConfig.java
src/net/sf/openrocket/gui/configdialog/TrapezoidFinSetConfig.java
src/net/sf/openrocket/gui/dialogs/BugDialog.java [new file with mode: 0644]
src/net/sf/openrocket/gui/main/AboutDialog.java
src/net/sf/openrocket/gui/main/BasicFrame.java
src/net/sf/openrocket/gui/main/ComponentAddButtons.java
src/net/sf/openrocket/gui/main/DocumentSelectionListener.java [new file with mode: 0644]
src/net/sf/openrocket/gui/main/DocumentSelectionModel.java [new file with mode: 0644]
src/net/sf/openrocket/gui/main/LicenseDialog.java
src/net/sf/openrocket/gui/main/MotorChooserDialog.java
src/net/sf/openrocket/gui/main/OpenRocketClipboard.java [new file with mode: 0644]
src/net/sf/openrocket/gui/main/RocketActions.java
src/net/sf/openrocket/gui/main/SimulationEditDialog.java
src/net/sf/openrocket/gui/main/SimulationPanel.java
src/net/sf/openrocket/gui/plot/PlotPanel.java
src/net/sf/openrocket/gui/scalefigure/RocketPanel.java
src/net/sf/openrocket/gui/scalefigure/ScaleScrollPane.java
src/net/sf/openrocket/startup/Startup.java [new file with mode: 0644]
src/net/sf/openrocket/unit/FixedPrecisionUnit.java
src/net/sf/openrocket/util/JarUtil.java [new file with mode: 0644]
src/net/sf/openrocket/util/PrintProperties.java [new file with mode: 0644]

index 9e11801e703ddab6ab086d842019ace2426b8c29..7efec8a2494b76b47cad3edc92a788251f370f1e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,15 @@
+2009-05-28  Sampo Niskanen
+
+       * Added startup check for Java 1.6 and OpenJDK
+
+2009-05-28  Sampo Niskanen
+
+       * Fixed FixedPrecisionUnit formatting
+       * Fixed saving of transitions
+       * Fixed file dialog directory browsing
+       * Initial shift-click selects second component from figure
+       * Allow adding body components without selecting stage
+       
 2009-05-24  Sampo Niskanen  <sampo.niskanen@iki.fi>
 
        * Initial release 0.9.0
-
index f56396575ca7fd9d5bf7f4c7d8d35f340b93ed00..c4892fa8bc3cb950f7b89e684467bd1a2eb15b51 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -12,7 +12,7 @@
 
        
        <!-- The main class of the application -->
-       <property name="main-class"  value="net.sf.openrocket.gui.main.BasicFrame"/>
+       <property name="main-class"  value="net.sf.openrocket.startup.Startup"/>
 
        
        <!-- Classpath definition -->
index 0795dc8a85f01781ec826e8c45b038c4d66219ed..f79600f31a520f3cef0dbb07d548eaa661382c13 100644 (file)
@@ -76,7 +76,7 @@
     <p>The source code for OpenRocket is available from the
     <a href="http://openrocket.svn.sourceforge.net/viewvc/openrocket/">SourceForge SVN repository</a>.  
     It can be retrieved simply using the command</p>
-    <pre class="quote">$ svn co https://openrocket.svn.sourceforge.net/svnroot/openrocket openrocket</pre>
+    <pre class="quote">$ svn co https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk OpenRocket</pre>
     <p>The above URL may be used to connect to the repository with
     other Subversion clients as well.</p>
 
index b7986cb7fed54abd33ead08066204860a1210b72..fd901dfa9da216c1c438d32480e87eeb97df4e19 100644 (file)
@@ -5,10 +5,6 @@ import java.io.FileInputStream;
 import java.io.FilenameFilter;
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.security.CodeSource;
 import java.util.AbstractSet;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -24,6 +20,7 @@ import javax.swing.event.EventListenerList;
 
 import net.sf.openrocket.file.Loader;
 import net.sf.openrocket.util.ChangeSource;
+import net.sf.openrocket.util.JarUtil;
 
 
 
@@ -182,17 +179,9 @@ public class Database<T extends Comparable<T>> extends AbstractSet<T> implements
                if (!dir.endsWith("/")) {
                        dir += "/";
                }
-
-               // Find the jar file this class is contained in and open it
-               URL jarUrl = null;
-               CodeSource codeSource = Database.class.getProtectionDomain().getCodeSource();
-               if (codeSource != null)
-                       jarUrl = codeSource.getLocation();
                
-               if (jarUrl == null) {
-                       throw new IOException("Could not find containing JAR file.");
-               }
-               File file = urlToFile(jarUrl);
+               // Find and open the jar file this class is contained in
+               File file = JarUtil.getCurrentJarFile();
                JarFile jarFile = new JarFile(file);
                
                try {
@@ -219,22 +208,6 @@ public class Database<T extends Comparable<T>> extends AbstractSet<T> implements
        }
        
        
-       static File urlToFile(URL url) {
-               URI uri;
-               try {
-                       uri = url.toURI();
-               } catch (URISyntaxException e) {
-                       try {
-                               uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), 
-                                               url.getPath(), url.getQuery(), url.getRef());
-                       } catch (URISyntaxException e1) {
-                               throw new IllegalArgumentException("Broken URL: " + url);
-                       }
-               }
-               return new File(uri);
-       }
-       
-       
        
        public void load(File file) throws IOException {
                if (loader == null) {
index d597d129d78cf68c111ccc74c4c32159320938f8..461087f65edf80fdc285271bb91c013c80dfc281 100644 (file)
@@ -33,7 +33,7 @@ public class TransitionSaver extends SymmetricComponentSaver {
 
 
                Transition.Shape shape = trans.getType();
-               elements.add("<shape>" + shape.getName().toLowerCase() + "</shape>");
+               elements.add("<shape>" + shape.name().toLowerCase() + "</shape>");
                if (shape.isClippable()) {
                        elements.add("<shapeclipped>" + trans.isClipped() + "</shapeclipped>");
                }
diff --git a/src/net/sf/openrocket/gui/BasicSlider.java b/src/net/sf/openrocket/gui/BasicSlider.java
deleted file mode 100644 (file)
index d22c3e8..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-package net.sf.openrocket.gui;
-
-import javax.swing.BoundedRangeModel;
-import javax.swing.JSlider;
-import javax.swing.plaf.basic.BasicSliderUI;
-
-/**
- * A simple slider that does not show the current value.  GTK l&f shows the value, and cannot 
- * be configured otherwise(!).
- * 
- * @author Sampo Niskanen <sampo.niskanen@iki.fi>
- */
-
-public class BasicSlider extends JSlider {
-
-       public BasicSlider(BoundedRangeModel brm) {
-               this(brm,JSlider.HORIZONTAL,false);
-       }
-       
-       public BasicSlider(BoundedRangeModel brm, int orientation) {
-               this(brm,orientation,false);
-       }
-       
-       public BasicSlider(BoundedRangeModel brm, int orientation, boolean inverted) {
-               super(brm);
-               setOrientation(orientation);
-               setInverted(inverted);
-               setUI(new BasicSliderUI(this));
-       }
-
-}
index e44e48bdb0decad6a068e15b7b150c9c5e965634..7fa39a7a3520893ce3d69d57800b687901633d5c 100644 (file)
@@ -44,6 +44,10 @@ import net.sf.openrocket.gui.adaptors.Column;
 import net.sf.openrocket.gui.adaptors.ColumnTableModel;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.adaptors.MotorConfigurationModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.ResizeLabel;
+import net.sf.openrocket.gui.components.StageSelector;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.gui.scalefigure.RocketPanel;
 import net.sf.openrocket.rocketcomponent.Configuration;
 import net.sf.openrocket.rocketcomponent.FinSet;
diff --git a/src/net/sf/openrocket/gui/DescriptionArea.java b/src/net/sf/openrocket/gui/DescriptionArea.java
deleted file mode 100644 (file)
index ba29be4..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-package net.sf.openrocket.gui;
-
-import java.awt.Dimension;
-import java.awt.Rectangle;
-
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.ScrollPaneConstants;
-
-import net.miginfocom.swing.MigLayout;
-
-public class DescriptionArea extends JScrollPane {
-
-       private ResizeLabel text;
-       private MigLayout layout;
-       private JPanel panel;
-       
-       public DescriptionArea(int rows) {
-               this(rows, -2);
-       }
-       
-       public DescriptionArea(int rows, float size) {
-               super(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
-                               ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
-               
-               layout = new MigLayout("ins 0 2px, fill");
-               panel = new JPanel(layout);
-               
-               text = new ResizeLabel(" ",size);
-               text.validate();
-               Dimension dim = text.getPreferredSize();
-               dim.height = (dim.height+2)*rows + 2;
-               this.setPreferredSize(dim);
-               
-               panel.add(text, "growx");
-               
-               this.setViewportView(panel);
-               this.revalidate();
-       }
-       
-       public void setText(String txt) {
-               if (!txt.startsWith("<html>"))
-                       txt = "<html>" + txt;
-               text.setText(txt);
-       }
-       
-       
-       @Override
-       public void validate() {
-               
-               Rectangle dim = this.getViewportBorderBounds();
-               layout.setComponentConstraints(text, "width "+ dim.width + ", growx");
-               super.validate();
-               text.validate();
-
-       }
-       
-}
index e42d9f921c1d0e69445ef92e494ec7f47876c0e2..2cdb4c45b20402154a873eed671658b46d2bef93 100644 (file)
@@ -18,6 +18,7 @@ import javax.swing.JPanel;
 import javax.swing.JTabbedPane;
 
 import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.gui.components.ResizeLabel;
 import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.util.GUIUtil;
diff --git a/src/net/sf/openrocket/gui/ResizeLabel.java b/src/net/sf/openrocket/gui/ResizeLabel.java
deleted file mode 100644 (file)
index 6951d62..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-package net.sf.openrocket.gui;
-
-import java.awt.Font;
-import javax.swing.JLabel;
-
-/**
- * A resizeable JLabel.  The method resizeFont(float) changes the current font size by the
- * given (positive or negative) amount.  The change is relative to the current font size.
- * <p>
- * A nice small text is achievable by  <code>new ResizeLabel("My text", -2);</code>
- * 
- * @author Sampo Niskanen <sampo.niskanen@iki.fi>
- */
-
-public class ResizeLabel extends JLabel {
-       
-       public ResizeLabel() {
-               super();
-       }
-       
-       public ResizeLabel(String text) {
-               super(text);
-       }
-       
-       public ResizeLabel(float size) {
-               super();
-               resizeFont(size);
-       }
-       
-       public ResizeLabel(String text, float size) {
-               super(text);
-               resizeFont(size);
-       }
-       
-       public ResizeLabel(String text, int horizontalAlignment, float size) {
-               super(text, horizontalAlignment);
-               resizeFont(size);
-       }
-       
-       
-       public void resizeFont(float size) {
-               Font font = this.getFont();
-               font = font.deriveFont(font.getSize2D()+size);
-               this.setFont(font);
-       }
-       
-}
diff --git a/src/net/sf/openrocket/gui/StageSelector.java b/src/net/sf/openrocket/gui/StageSelector.java
deleted file mode 100644 (file)
index a0ad437..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-package net.sf.openrocket.gui;
-
-import java.awt.event.ActionEvent;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.AbstractAction;
-import javax.swing.JPanel;
-import javax.swing.JToggleButton;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-
-import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.rocketcomponent.Configuration;
-
-
-public class StageSelector extends JPanel implements ChangeListener {
-
-       private final Configuration configuration;
-       
-       private List<JToggleButton> buttons = new ArrayList<JToggleButton>();
-       
-       public StageSelector(Configuration configuration) {
-               super(new MigLayout("gap 0!"));
-               this.configuration = configuration;
-               
-               JToggleButton button = new JToggleButton(new StageAction(0));
-               this.add(button);
-               buttons.add(button);
-               
-               updateButtons();
-               configuration.addChangeListener(this);
-       }
-       
-       private void updateButtons() {
-               int stages = configuration.getStageCount();
-               if (buttons.size() == stages)
-                       return;
-               
-               while (buttons.size() > stages) {
-                       JToggleButton button = buttons.remove(buttons.size()-1);
-                       this.remove(button);
-               }
-               
-               while (buttons.size() < stages) {
-                       JToggleButton button = new JToggleButton(new StageAction(buttons.size()));
-                       this.add(button);
-                       buttons.add(button);
-               }
-               
-               this.revalidate();
-       }
-       
-
-
-
-       @Override
-       public void stateChanged(ChangeEvent e) {
-               updateButtons();
-       }
-       
-       
-       private class StageAction extends AbstractAction implements ChangeListener {
-               private final int stage;
-
-               public StageAction(final int stage) {
-                       this.stage = stage;
-                       configuration.addChangeListener(this);
-                       stateChanged(null);
-               }
-               
-               @Override
-               public Object getValue(String key) {
-                       if (key.equals(NAME)) {
-                               return "Stage "+(stage+1);
-                       }
-                       return super.getValue(key);
-               }
-               
-               @Override
-               public void actionPerformed(ActionEvent e) {
-                       configuration.setToStage(stage);
-                       
-//                     boolean state = (Boolean)getValue(SELECTED_KEY);
-//                     if (state == true) {
-//                             // Was disabled, now enabled
-//                             configuration.setToStage(stage);
-//                     } else {
-//                             // Was enabled, check what to do
-//                             if (configuration.isStageActive(stage + 1)) {
-//                                     configuration.setToStage(stage);
-//                             } else {
-//                                     if (stage == 0)
-//                                             configuration.setAllStages();
-//                                     else 
-//                                             configuration.setToStage(stage-1);
-//                             }
-//                     }
-//                     stateChanged(null);
-               }
-               
-
-               @Override
-               public void stateChanged(ChangeEvent e) {
-                       this.putValue(SELECTED_KEY, configuration.isStageActive(stage));
-               }
-       }
-}
diff --git a/src/net/sf/openrocket/gui/UnitSelector.java b/src/net/sf/openrocket/gui/UnitSelector.java
deleted file mode 100644 (file)
index 37453ef..0000000
+++ /dev/null
@@ -1,314 +0,0 @@
-package net.sf.openrocket.gui;
-
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.ItemSelectable;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.Action;
-import javax.swing.JMenuItem;
-import javax.swing.JPopupMenu;
-import javax.swing.border.Border;
-import javax.swing.border.CompoundBorder;
-import javax.swing.border.EmptyBorder;
-import javax.swing.border.LineBorder;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-
-import net.sf.openrocket.gui.adaptors.DoubleModel;
-import net.sf.openrocket.unit.Unit;
-import net.sf.openrocket.unit.UnitGroup;
-
-
-/**
- * A Swing component that allows one to choose a unit from a UnitGroup within
- * a DoubleModel model.  The current unit of the model is shown as a JLabel, and
- * the unit can be changed by clicking on the label.
- * 
- * @author Sampo Niskanen <sampo.niskanen@iki.fi>
- */
-
-public class UnitSelector extends ResizeLabel implements ChangeListener, MouseListener,
-               ItemSelectable {
-
-       private final DoubleModel model;
-       private final Action[] extraActions;
-
-       private UnitGroup unitGroup;
-       private Unit currentUnit;
-
-       private final boolean showValue;
-
-       private final Border normalBorder;
-       private final Border withinBorder;
-
-
-       private final List<ItemListener> itemListeners = new ArrayList<ItemListener>();
-
-
-       /**
-        * Common private constructor that sets the values and sets up the borders.
-        * Either model or group must be null.
-        * 
-        * @param model
-        * @param showValue
-        * @param group
-        * @param actions
-        */
-       private UnitSelector(DoubleModel model, boolean showValue, UnitGroup group,
-                       Action[] actions) {
-               super();
-
-               this.model = model;
-               this.showValue = showValue;
-
-               if (model != null) {
-                       this.unitGroup = model.getUnitGroup();
-                       this.currentUnit = model.getCurrentUnit();
-               } else {
-                       this.unitGroup = group;
-                       this.currentUnit = group.getDefaultUnit();
-               }
-
-               this.extraActions = actions;
-
-               addMouseListener(this);
-
-               // Define borders to use:
-
-               normalBorder = new CompoundBorder(
-                               new LineBorder(new Color(0f, 0f, 0f, 0.08f), 1), new EmptyBorder(1, 1, 1,
-                                               1));
-               withinBorder = new CompoundBorder(new LineBorder(new Color(0f, 0f, 0f, 0.6f)),
-                               new EmptyBorder(1, 1, 1, 1));
-
-               setBorder(normalBorder);
-               updateText();
-       }
-
-
-
-       public UnitSelector(DoubleModel model, Action... actions) {
-               this(model, false, actions);
-       }
-
-       public UnitSelector(DoubleModel model, boolean showValue, Action... actions) {
-               this(model, showValue, null, actions);
-
-               // Add model listener
-               this.model.addChangeListener(this);
-       }
-
-
-       public UnitSelector(UnitGroup group, Action... actions) {
-               this(null, false, group, actions);
-       }
-
-
-
-
-       /**
-        * Return the DoubleModel that is backing this selector up, or <code>null</code>.
-        * Either this method or {@link #getUnitGroup()} always returns <code>null</code>.
-        * 
-        * @return              the DoubleModel being used, or <code>null</code>.
-        */
-       public DoubleModel getModel() {
-               return model;
-       }
-
-
-       /**
-        * Return the unit group that is being shown, or <code>null</code>.  Either this method
-        * or {@link #getModel()} always returns <code>null</code>.
-        * 
-        * @return              the UnitGroup being used, or <code>null</code>.
-        */
-       public UnitGroup getUnitGroup() {
-               return unitGroup;
-       }
-
-
-       public void setUnitGroup(UnitGroup group) {
-               if (model != null) {
-                       throw new IllegalStateException(
-                                       "UnitGroup cannot be set when backed up with model.");
-               }
-
-               if (this.unitGroup == group)
-                       return;
-
-               this.unitGroup = group;
-               this.currentUnit = group.getDefaultUnit();
-               updateText();
-       }
-
-
-       /**
-        * Return the currently selected unit.  Works both when backup up with a DoubleModel
-        * and UnitGroup.
-        * 
-        * @return              the currently selected unit.
-        */
-       public Unit getSelectedUnit() {
-               return currentUnit;
-       }
-
-
-       /**
-        * Set the currently selected unit.  Sets it to the DoubleModel if it is backed up
-        * by it.
-        * 
-        * @param unit          the unit to select.
-        */
-       public void setSelectedUnit(Unit unit) {
-               if (!unitGroup.contains(unit)) {
-                       throw new IllegalArgumentException("unit " + unit
-                                       + " not contained in group " + unitGroup);
-               }
-
-               this.currentUnit = unit;
-               if (model != null) {
-                       model.setCurrentUnit(unit);
-               }
-               updateText();
-               fireItemEvent();
-       }
-
-
-
-       /**
-        * Updates the text of the label
-        */
-       private void updateText() {
-               if (model != null) {
-
-                       Unit unit = model.getCurrentUnit();
-                       if (showValue) {
-                               setText(unit.toStringUnit(model.getValue()));
-                       } else {
-                               setText(unit.getUnit());
-                       }
-
-               } else if (unitGroup != null) {
-
-                       setText(currentUnit.getUnit());
-
-               } else {
-                       throw new IllegalStateException("Both model and unitGroup are null.");
-               }
-       }
-
-
-       /**
-        * Update the component when the DoubleModel changes.
-        */
-       public void stateChanged(ChangeEvent e) {
-               updateText();
-       }
-
-
-
-       ////////  ItemListener handling  ////////
-
-       public void addItemListener(ItemListener listener) {
-               itemListeners.add(listener);
-       }
-
-       public void removeItemListener(ItemListener listener) {
-               itemListeners.remove(listener);
-       }
-
-       protected void fireItemEvent() {
-               ItemEvent event = null;
-               ItemListener[] listeners = itemListeners.toArray(new ItemListener[0]);
-               for (ItemListener l: listeners) {
-                       if (event == null) {
-                               event = new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED, getSelectedUnit(),
-                                               ItemEvent.SELECTED);
-                       }
-                       l.itemStateChanged(event);
-               }
-       }
-
-
-
-       ////////  Popup  ////////
-
-       private void popup() {
-               JPopupMenu popup = new JPopupMenu();
-
-               for (int i = 0; i < unitGroup.getUnitCount(); i++) {
-                       Unit unit = unitGroup.getUnit(i);
-                       JMenuItem item = new JMenuItem(unit.getUnit());
-                       item.addActionListener(new UnitSelectorItem(unit));
-                       popup.add(item);
-               }
-
-               for (int i = 0; i < extraActions.length; i++) {
-                       if (extraActions[i] == null && i < extraActions.length - 1) {
-                               popup.addSeparator();
-                       } else {
-                               popup.add(new JMenuItem(extraActions[i]));
-                       }
-               }
-
-               Dimension d = getSize();
-               popup.show(this, 0, d.height);
-       }
-
-
-       /**
-        * ActionListener class that sets the currently selected unit.
-        */
-       private class UnitSelectorItem implements ActionListener {
-               private final Unit unit;
-
-               public UnitSelectorItem(Unit u) {
-                       unit = u;
-               }
-
-               public void actionPerformed(ActionEvent e) {
-                       setSelectedUnit(unit);
-               }
-       }
-
-
-       @Override
-       public Object[] getSelectedObjects() {
-               return new Object[]{ getSelectedUnit() };
-       }
-
-
-
-       ////////  Mouse handling ////////
-
-       public void mouseClicked(MouseEvent e) {
-               if (unitGroup.getUnitCount() > 1)
-                       popup();
-       }
-
-       public void mouseEntered(MouseEvent e) {
-               if (unitGroup.getUnitCount() > 1)
-                       setBorder(withinBorder);
-       }
-
-       public void mouseExited(MouseEvent e) {
-               setBorder(normalBorder);
-       }
-
-       public void mousePressed(MouseEvent e) {
-       } // Ignore
-
-       public void mouseReleased(MouseEvent e) {
-       } // Ignore
-
-}
index 1af6f2addd3de90b14b2ab89b259756cd62affc9..1daf286cb3dc2e77ef4b7ee2dbbdf92fc912af9b 100644 (file)
@@ -20,7 +20,7 @@ import javax.swing.event.ChangeListener;
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.database.Database;
 import net.sf.openrocket.database.Databases;
-import net.sf.openrocket.gui.UnitSelector;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
index fbf367bf429b3cf2b71d079472e32cdfea8ec253..9f96997c637268d4fced6b015def952b4fd206fe 100644 (file)
@@ -30,8 +30,8 @@ import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.ResizeLabel;
 import net.sf.openrocket.gui.TextFieldListener;
+import net.sf.openrocket.gui.components.ResizeLabel;
 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
 import net.sf.openrocket.rocketcomponent.Configuration;
 import net.sf.openrocket.rocketcomponent.Motor;
diff --git a/src/net/sf/openrocket/gui/components/BasicSlider.java b/src/net/sf/openrocket/gui/components/BasicSlider.java
new file mode 100644 (file)
index 0000000..0ac92e7
--- /dev/null
@@ -0,0 +1,31 @@
+package net.sf.openrocket.gui.components;
+
+import javax.swing.BoundedRangeModel;
+import javax.swing.JSlider;
+import javax.swing.plaf.basic.BasicSliderUI;
+
+/**
+ * A simple slider that does not show the current value.  GTK l&f shows the value, and cannot 
+ * be configured otherwise(!).
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+
+public class BasicSlider extends JSlider {
+
+       public BasicSlider(BoundedRangeModel brm) {
+               this(brm,JSlider.HORIZONTAL,false);
+       }
+       
+       public BasicSlider(BoundedRangeModel brm, int orientation) {
+               this(brm,orientation,false);
+       }
+       
+       public BasicSlider(BoundedRangeModel brm, int orientation, boolean inverted) {
+               super(brm);
+               setOrientation(orientation);
+               setInverted(inverted);
+               setUI(new BasicSliderUI(this));
+       }
+
+}
diff --git a/src/net/sf/openrocket/gui/components/DescriptionArea.java b/src/net/sf/openrocket/gui/components/DescriptionArea.java
new file mode 100644 (file)
index 0000000..264953f
--- /dev/null
@@ -0,0 +1,58 @@
+package net.sf.openrocket.gui.components;
+
+import java.awt.Dimension;
+import java.awt.Rectangle;
+
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.ScrollPaneConstants;
+
+import net.miginfocom.swing.MigLayout;
+
+public class DescriptionArea extends JScrollPane {
+
+       private ResizeLabel text;
+       private MigLayout layout;
+       private JPanel panel;
+       
+       public DescriptionArea(int rows) {
+               this(rows, -2);
+       }
+       
+       public DescriptionArea(int rows, float size) {
+               super(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
+                               ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
+               
+               layout = new MigLayout("ins 0 2px, fill");
+               panel = new JPanel(layout);
+               
+               text = new ResizeLabel(" ",size);
+               text.validate();
+               Dimension dim = text.getPreferredSize();
+               dim.height = (dim.height+2)*rows + 2;
+               this.setPreferredSize(dim);
+               
+               panel.add(text, "growx");
+               
+               this.setViewportView(panel);
+               this.revalidate();
+       }
+       
+       public void setText(String txt) {
+               if (!txt.startsWith("<html>"))
+                       txt = "<html>" + txt;
+               text.setText(txt);
+       }
+       
+       
+       @Override
+       public void validate() {
+               
+               Rectangle dim = this.getViewportBorderBounds();
+               layout.setComponentConstraints(text, "width "+ dim.width + ", growx");
+               super.validate();
+               text.validate();
+
+       }
+       
+}
diff --git a/src/net/sf/openrocket/gui/components/ResizeLabel.java b/src/net/sf/openrocket/gui/components/ResizeLabel.java
new file mode 100644 (file)
index 0000000..0978252
--- /dev/null
@@ -0,0 +1,47 @@
+package net.sf.openrocket.gui.components;
+
+import java.awt.Font;
+import javax.swing.JLabel;
+
+/**
+ * A resizeable JLabel.  The method resizeFont(float) changes the current font size by the
+ * given (positive or negative) amount.  The change is relative to the current font size.
+ * <p>
+ * A nice small text is achievable by  <code>new ResizeLabel("My text", -2);</code>
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+
+public class ResizeLabel extends JLabel {
+       
+       public ResizeLabel() {
+               super();
+       }
+       
+       public ResizeLabel(String text) {
+               super(text);
+       }
+       
+       public ResizeLabel(float size) {
+               super();
+               resizeFont(size);
+       }
+       
+       public ResizeLabel(String text, float size) {
+               super(text);
+               resizeFont(size);
+       }
+       
+       public ResizeLabel(String text, int horizontalAlignment, float size) {
+               super(text, horizontalAlignment);
+               resizeFont(size);
+       }
+       
+       
+       public void resizeFont(float size) {
+               Font font = this.getFont();
+               font = font.deriveFont(font.getSize2D()+size);
+               this.setFont(font);
+       }
+       
+}
diff --git a/src/net/sf/openrocket/gui/components/StageSelector.java b/src/net/sf/openrocket/gui/components/StageSelector.java
new file mode 100644 (file)
index 0000000..5b5e78a
--- /dev/null
@@ -0,0 +1,108 @@
+package net.sf.openrocket.gui.components;
+
+import java.awt.event.ActionEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.JPanel;
+import javax.swing.JToggleButton;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.rocketcomponent.Configuration;
+
+
+public class StageSelector extends JPanel implements ChangeListener {
+
+       private final Configuration configuration;
+       
+       private List<JToggleButton> buttons = new ArrayList<JToggleButton>();
+       
+       public StageSelector(Configuration configuration) {
+               super(new MigLayout("gap 0!"));
+               this.configuration = configuration;
+               
+               JToggleButton button = new JToggleButton(new StageAction(0));
+               this.add(button);
+               buttons.add(button);
+               
+               updateButtons();
+               configuration.addChangeListener(this);
+       }
+       
+       private void updateButtons() {
+               int stages = configuration.getStageCount();
+               if (buttons.size() == stages)
+                       return;
+               
+               while (buttons.size() > stages) {
+                       JToggleButton button = buttons.remove(buttons.size()-1);
+                       this.remove(button);
+               }
+               
+               while (buttons.size() < stages) {
+                       JToggleButton button = new JToggleButton(new StageAction(buttons.size()));
+                       this.add(button);
+                       buttons.add(button);
+               }
+               
+               this.revalidate();
+       }
+       
+
+
+
+       @Override
+       public void stateChanged(ChangeEvent e) {
+               updateButtons();
+       }
+       
+       
+       private class StageAction extends AbstractAction implements ChangeListener {
+               private final int stage;
+
+               public StageAction(final int stage) {
+                       this.stage = stage;
+                       configuration.addChangeListener(this);
+                       stateChanged(null);
+               }
+               
+               @Override
+               public Object getValue(String key) {
+                       if (key.equals(NAME)) {
+                               return "Stage "+(stage+1);
+                       }
+                       return super.getValue(key);
+               }
+               
+               @Override
+               public void actionPerformed(ActionEvent e) {
+                       configuration.setToStage(stage);
+                       
+//                     boolean state = (Boolean)getValue(SELECTED_KEY);
+//                     if (state == true) {
+//                             // Was disabled, now enabled
+//                             configuration.setToStage(stage);
+//                     } else {
+//                             // Was enabled, check what to do
+//                             if (configuration.isStageActive(stage + 1)) {
+//                                     configuration.setToStage(stage);
+//                             } else {
+//                                     if (stage == 0)
+//                                             configuration.setAllStages();
+//                                     else 
+//                                             configuration.setToStage(stage-1);
+//                             }
+//                     }
+//                     stateChanged(null);
+               }
+               
+
+               @Override
+               public void stateChanged(ChangeEvent e) {
+                       this.putValue(SELECTED_KEY, configuration.isStageActive(stage));
+               }
+       }
+}
diff --git a/src/net/sf/openrocket/gui/components/URLLabel.java b/src/net/sf/openrocket/gui/components/URLLabel.java
new file mode 100644 (file)
index 0000000..be6bdd8
--- /dev/null
@@ -0,0 +1,51 @@
+package net.sf.openrocket.gui.components;
+
+import java.awt.Desktop;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.swing.JLabel;
+
+/**
+ * A label of a URL that is clickable.  Clicking the URL will launch the URL in
+ * the default browser if the Desktop class is supported.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class URLLabel extends JLabel {
+       
+       private final String url;
+       
+       public URLLabel(String urlLabel) {
+               super();
+               
+               this.url = urlLabel;
+               
+
+               if (Desktop.isDesktopSupported()) {
+                       
+                       setText("<html><a href=\"" + url + "\">" + url + "</a>");
+
+                       this.addMouseListener(new MouseAdapter() {
+                               @Override
+                               public void mouseClicked(MouseEvent e) {
+                                       Desktop d = Desktop.getDesktop();
+                                       try {
+                                               d.browse(new URI(url));
+                                       } catch (URISyntaxException e1) {
+                                               throw new RuntimeException("BUG: Illegal URL: " + url, e1);
+                                       } catch (IOException e1) {
+                                               System.err.println("Unable to launch browser:");
+                                               e1.printStackTrace();
+                                       }
+                               }
+                       });
+                       
+               } else {
+                       setText(url);
+               }
+       }
+}
diff --git a/src/net/sf/openrocket/gui/components/UnitSelector.java b/src/net/sf/openrocket/gui/components/UnitSelector.java
new file mode 100644 (file)
index 0000000..962992e
--- /dev/null
@@ -0,0 +1,314 @@
+package net.sf.openrocket.gui.components;
+
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.ItemSelectable;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.Action;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.border.Border;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.LineBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import net.sf.openrocket.gui.adaptors.DoubleModel;
+import net.sf.openrocket.unit.Unit;
+import net.sf.openrocket.unit.UnitGroup;
+
+
+/**
+ * A Swing component that allows one to choose a unit from a UnitGroup within
+ * a DoubleModel model.  The current unit of the model is shown as a JLabel, and
+ * the unit can be changed by clicking on the label.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+
+public class UnitSelector extends ResizeLabel implements ChangeListener, MouseListener,
+               ItemSelectable {
+
+       private final DoubleModel model;
+       private final Action[] extraActions;
+
+       private UnitGroup unitGroup;
+       private Unit currentUnit;
+
+       private final boolean showValue;
+
+       private final Border normalBorder;
+       private final Border withinBorder;
+
+
+       private final List<ItemListener> itemListeners = new ArrayList<ItemListener>();
+
+
+       /**
+        * Common private constructor that sets the values and sets up the borders.
+        * Either model or group must be null.
+        * 
+        * @param model
+        * @param showValue
+        * @param group
+        * @param actions
+        */
+       private UnitSelector(DoubleModel model, boolean showValue, UnitGroup group,
+                       Action[] actions) {
+               super();
+
+               this.model = model;
+               this.showValue = showValue;
+
+               if (model != null) {
+                       this.unitGroup = model.getUnitGroup();
+                       this.currentUnit = model.getCurrentUnit();
+               } else {
+                       this.unitGroup = group;
+                       this.currentUnit = group.getDefaultUnit();
+               }
+
+               this.extraActions = actions;
+
+               addMouseListener(this);
+
+               // Define borders to use:
+
+               normalBorder = new CompoundBorder(
+                               new LineBorder(new Color(0f, 0f, 0f, 0.08f), 1), new EmptyBorder(1, 1, 1,
+                                               1));
+               withinBorder = new CompoundBorder(new LineBorder(new Color(0f, 0f, 0f, 0.6f)),
+                               new EmptyBorder(1, 1, 1, 1));
+
+               setBorder(normalBorder);
+               updateText();
+       }
+
+
+
+       public UnitSelector(DoubleModel model, Action... actions) {
+               this(model, false, actions);
+       }
+
+       public UnitSelector(DoubleModel model, boolean showValue, Action... actions) {
+               this(model, showValue, null, actions);
+
+               // Add model listener
+               this.model.addChangeListener(this);
+       }
+
+
+       public UnitSelector(UnitGroup group, Action... actions) {
+               this(null, false, group, actions);
+       }
+
+
+
+
+       /**
+        * Return the DoubleModel that is backing this selector up, or <code>null</code>.
+        * Either this method or {@link #getUnitGroup()} always returns <code>null</code>.
+        * 
+        * @return              the DoubleModel being used, or <code>null</code>.
+        */
+       public DoubleModel getModel() {
+               return model;
+       }
+
+
+       /**
+        * Return the unit group that is being shown, or <code>null</code>.  Either this method
+        * or {@link #getModel()} always returns <code>null</code>.
+        * 
+        * @return              the UnitGroup being used, or <code>null</code>.
+        */
+       public UnitGroup getUnitGroup() {
+               return unitGroup;
+       }
+
+
+       public void setUnitGroup(UnitGroup group) {
+               if (model != null) {
+                       throw new IllegalStateException(
+                                       "UnitGroup cannot be set when backed up with model.");
+               }
+
+               if (this.unitGroup == group)
+                       return;
+
+               this.unitGroup = group;
+               this.currentUnit = group.getDefaultUnit();
+               updateText();
+       }
+
+
+       /**
+        * Return the currently selected unit.  Works both when backup up with a DoubleModel
+        * and UnitGroup.
+        * 
+        * @return              the currently selected unit.
+        */
+       public Unit getSelectedUnit() {
+               return currentUnit;
+       }
+
+
+       /**
+        * Set the currently selected unit.  Sets it to the DoubleModel if it is backed up
+        * by it.
+        * 
+        * @param unit          the unit to select.
+        */
+       public void setSelectedUnit(Unit unit) {
+               if (!unitGroup.contains(unit)) {
+                       throw new IllegalArgumentException("unit " + unit
+                                       + " not contained in group " + unitGroup);
+               }
+
+               this.currentUnit = unit;
+               if (model != null) {
+                       model.setCurrentUnit(unit);
+               }
+               updateText();
+               fireItemEvent();
+       }
+
+
+
+       /**
+        * Updates the text of the label
+        */
+       private void updateText() {
+               if (model != null) {
+
+                       Unit unit = model.getCurrentUnit();
+                       if (showValue) {
+                               setText(unit.toStringUnit(model.getValue()));
+                       } else {
+                               setText(unit.getUnit());
+                       }
+
+               } else if (unitGroup != null) {
+
+                       setText(currentUnit.getUnit());
+
+               } else {
+                       throw new IllegalStateException("Both model and unitGroup are null.");
+               }
+       }
+
+
+       /**
+        * Update the component when the DoubleModel changes.
+        */
+       public void stateChanged(ChangeEvent e) {
+               updateText();
+       }
+
+
+
+       ////////  ItemListener handling  ////////
+
+       public void addItemListener(ItemListener listener) {
+               itemListeners.add(listener);
+       }
+
+       public void removeItemListener(ItemListener listener) {
+               itemListeners.remove(listener);
+       }
+
+       protected void fireItemEvent() {
+               ItemEvent event = null;
+               ItemListener[] listeners = itemListeners.toArray(new ItemListener[0]);
+               for (ItemListener l: listeners) {
+                       if (event == null) {
+                               event = new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED, getSelectedUnit(),
+                                               ItemEvent.SELECTED);
+                       }
+                       l.itemStateChanged(event);
+               }
+       }
+
+
+
+       ////////  Popup  ////////
+
+       private void popup() {
+               JPopupMenu popup = new JPopupMenu();
+
+               for (int i = 0; i < unitGroup.getUnitCount(); i++) {
+                       Unit unit = unitGroup.getUnit(i);
+                       JMenuItem item = new JMenuItem(unit.getUnit());
+                       item.addActionListener(new UnitSelectorItem(unit));
+                       popup.add(item);
+               }
+
+               for (int i = 0; i < extraActions.length; i++) {
+                       if (extraActions[i] == null && i < extraActions.length - 1) {
+                               popup.addSeparator();
+                       } else {
+                               popup.add(new JMenuItem(extraActions[i]));
+                       }
+               }
+
+               Dimension d = getSize();
+               popup.show(this, 0, d.height);
+       }
+
+
+       /**
+        * ActionListener class that sets the currently selected unit.
+        */
+       private class UnitSelectorItem implements ActionListener {
+               private final Unit unit;
+
+               public UnitSelectorItem(Unit u) {
+                       unit = u;
+               }
+
+               public void actionPerformed(ActionEvent e) {
+                       setSelectedUnit(unit);
+               }
+       }
+
+
+       @Override
+       public Object[] getSelectedObjects() {
+               return new Object[]{ getSelectedUnit() };
+       }
+
+
+
+       ////////  Mouse handling ////////
+
+       public void mouseClicked(MouseEvent e) {
+               if (unitGroup.getUnitCount() > 1)
+                       popup();
+       }
+
+       public void mouseEntered(MouseEvent e) {
+               if (unitGroup.getUnitCount() > 1)
+                       setBorder(withinBorder);
+       }
+
+       public void mouseExited(MouseEvent e) {
+               setBorder(normalBorder);
+       }
+
+       public void mousePressed(MouseEvent e) {
+       } // Ignore
+
+       public void mouseReleased(MouseEvent e) {
+       } // Ignore
+
+}
index 7c5776ade312f4d50897a90e8c1568ce1fd0badf..874111a286e8addc00e79a3501d021b671e44ce6 100644 (file)
@@ -7,11 +7,11 @@ import javax.swing.JPanel;
 import javax.swing.JSpinner;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.BasicSlider;
 import net.sf.openrocket.gui.SpinnerEditor;
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.BooleanModel;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.rocketcomponent.BodyTube;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
index 8092ae4b61f1002a3f0e97d8858c7d70d3f2dd59..51f45318f6958b1436b58583c178bc4671419b2d 100644 (file)
@@ -14,12 +14,12 @@ import javax.swing.SwingConstants;
 import javax.swing.SwingUtilities;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.BasicSlider;
 import net.sf.openrocket.gui.SpinnerEditor;
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.adaptors.EnumModel;
 import net.sf.openrocket.gui.adaptors.IntegerModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.rocketcomponent.FinSet;
 import net.sf.openrocket.rocketcomponent.FreeformFinSet;
index de59d7a10a4d4a11503c2174f9f017c06bfabda7..889d4adf61786de2cbcd3a931e5c92c55d0bb957 100644 (file)
@@ -17,13 +17,13 @@ import javax.swing.SwingConstants;
 import javax.swing.table.AbstractTableModel;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.BasicSlider;
-import net.sf.openrocket.gui.ResizeLabel;
 import net.sf.openrocket.gui.SpinnerEditor;
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.adaptors.EnumModel;
 import net.sf.openrocket.gui.adaptors.IntegerModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.ResizeLabel;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.gui.scalefigure.FinPointFigure;
 import net.sf.openrocket.gui.scalefigure.ScaleScrollPane;
 import net.sf.openrocket.gui.scalefigure.ScaleSelector;
index b8d9534b4dc186670b534de9afa8e51eee6122eb..b1319b7b5fc90aad37b705b08cfe41e08eb7635a 100644 (file)
@@ -26,11 +26,11 @@ import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.BasicSlider;
 import net.sf.openrocket.gui.Resettable;
 import net.sf.openrocket.gui.SpinnerEditor;
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.rocketcomponent.ClusterConfiguration;
 import net.sf.openrocket.rocketcomponent.Clusterable;
 import net.sf.openrocket.rocketcomponent.InnerTube;
index 9ef7203457bfa75a8e0969f2110a220f5dd3ace7..909c5d3156ef4d2081c6db2fcf8098049910f05f 100644 (file)
@@ -7,11 +7,11 @@ import javax.swing.JPanel;
 import javax.swing.JSpinner;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.BasicSlider;
 import net.sf.openrocket.gui.SpinnerEditor;
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.adaptors.EnumModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.unit.UnitGroup;
index 93a3d472aa8e2d0eb0a10ad27cea17f48cef2bac..5bff03a074edfa92c3e7be182d06ee5d894c3d0c 100644 (file)
@@ -11,11 +11,11 @@ import javax.swing.JPanel;
 import javax.swing.JSpinner;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.BasicSlider;
 import net.sf.openrocket.gui.SpinnerEditor;
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.adaptors.EnumModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.rocketcomponent.MassComponent;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.unit.UnitGroup;
index 47b94192115534f6a31f005297c4a435d1ff4c99..cf81eaab0e282d8cdf82fb0b8377b73451e91d72 100644 (file)
@@ -17,13 +17,13 @@ import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.BasicSlider;
 import net.sf.openrocket.gui.SpinnerEditor;
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.BooleanModel;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.adaptors.EnumModel;
 import net.sf.openrocket.gui.adaptors.MotorConfigurationModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.gui.main.MotorChooserDialog;
 import net.sf.openrocket.rocketcomponent.Configuration;
 import net.sf.openrocket.rocketcomponent.Motor;
index 1c75f8c17373dff8f25abe53bdf08bb2641d93e0..f1b6daf24bf29fadce8bf2e3ad725e5a398e7afe 100644 (file)
@@ -12,12 +12,12 @@ import javax.swing.JSlider;
 import javax.swing.JSpinner;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.BasicSlider;
-import net.sf.openrocket.gui.DescriptionArea;
 import net.sf.openrocket.gui.SpinnerEditor;
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.BooleanModel;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.DescriptionArea;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.rocketcomponent.NoseCone;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
index 340dfb8c59927f75b877e0f14bd369fc1eb87330..c058725d95e7d68935e5030808d182d8147a64df 100644 (file)
@@ -11,13 +11,13 @@ import javax.swing.JPanel;
 import javax.swing.JSpinner;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.BasicSlider;
 import net.sf.openrocket.gui.SpinnerEditor;
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.adaptors.EnumModel;
 import net.sf.openrocket.gui.adaptors.IntegerModel;
 import net.sf.openrocket.gui.adaptors.MaterialModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.rocketcomponent.MassComponent;
 import net.sf.openrocket.rocketcomponent.Parachute;
index 9acbbda089b60ccc08413aa9c8bf39defa4c252f..1b2f12ad3dbd6cc4516f4ba31c58926effa949ae 100644 (file)
@@ -12,11 +12,11 @@ import javax.swing.JPanel;
 import javax.swing.JSpinner;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.BasicSlider;
 import net.sf.openrocket.gui.SpinnerEditor;
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.adaptors.EnumModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.rocketcomponent.RingComponent;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
index 9b19bcb82e7a49fd30cd9f5f93eac6962a369514..5e017a4b43024645201a58f45f090634f1821703 100644 (file)
@@ -25,14 +25,14 @@ import javax.swing.JTextArea;
 import javax.swing.JTextField;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.BasicSlider;
-import net.sf.openrocket.gui.ResizeLabel;
 import net.sf.openrocket.gui.SpinnerEditor;
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.BooleanModel;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.adaptors.EnumModel;
 import net.sf.openrocket.gui.adaptors.MaterialModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.ResizeLabel;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.rocketcomponent.ComponentAssembly;
 import net.sf.openrocket.rocketcomponent.ExternalComponent;
index 9b82ea9f3d982cff5b9f0213c71a74115316a519..e3b1ba53e15ee15c816f35c165fcc443f0fa3bef 100644 (file)
@@ -7,11 +7,11 @@ import javax.swing.JPanel;
 import javax.swing.JSpinner;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.BasicSlider;
 import net.sf.openrocket.gui.SpinnerEditor;
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.adaptors.EnumModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.unit.UnitGroup;
index 951969e6abf28a273611d213758df4ae004bc9e9..132f6a5e585d96d05049896143772eb811e49411 100644 (file)
@@ -12,13 +12,13 @@ import javax.swing.JPanel;
 import javax.swing.JSpinner;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.BasicSlider;
-import net.sf.openrocket.gui.ResizeLabel;
 import net.sf.openrocket.gui.SpinnerEditor;
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.adaptors.EnumModel;
 import net.sf.openrocket.gui.adaptors.MaterialModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.ResizeLabel;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.rocketcomponent.MassComponent;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
index 61a6ff24498532b619b8ef42812333545a678a56..3a908ee850567714491e0d6a425c993ef37145c5 100644 (file)
@@ -11,12 +11,12 @@ import javax.swing.JPanel;
 import javax.swing.JSpinner;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.BasicSlider;
-import net.sf.openrocket.gui.DescriptionArea;
 import net.sf.openrocket.gui.SpinnerEditor;
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.BooleanModel;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.DescriptionArea;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.rocketcomponent.Transition;
index 4a640ec9ebbbfe5e5f504124577e062eafbe6e53..92081be63b3a5c6668e16049772d9d5d34eb6c8e 100644 (file)
@@ -9,12 +9,12 @@ import javax.swing.JSpinner;
 import javax.swing.SwingConstants;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.BasicSlider;
 import net.sf.openrocket.gui.SpinnerEditor;
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.adaptors.EnumModel;
 import net.sf.openrocket.gui.adaptors.IntegerModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.rocketcomponent.FinSet;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
diff --git a/src/net/sf/openrocket/gui/dialogs/BugDialog.java b/src/net/sf/openrocket/gui/dialogs/BugDialog.java
new file mode 100644 (file)
index 0000000..ae0bee8
--- /dev/null
@@ -0,0 +1,90 @@
+package net.sf.openrocket.gui.dialogs;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.gui.components.URLLabel;
+import net.sf.openrocket.gui.main.AboutDialog;
+import net.sf.openrocket.util.GUIUtil;
+import net.sf.openrocket.util.JarUtil;
+import net.sf.openrocket.util.Prefs;
+
+public class BugDialog extends JDialog {
+
+       public BugDialog(JFrame parent) {
+               super(parent, "Bug reporing", true);
+               
+               JPanel panel = new JPanel(new MigLayout("fill"));
+               
+               panel.add(new JLabel("Please report any bugs you encounter as instructed at "), 
+                               "gap para, split 2");
+               panel.add(new URLLabel(AboutDialog.OPENROCKET_URL), "wrap rel");
+               panel.add(new JLabel("This allows us to make OpenRocket an even better simulator."),
+                               "gap para, wrap para");
+               
+               panel.add(new JLabel("<html><em>Please copy and paste the following information " +
+                               "to the end of your bug report:</em>"), "gap para, wrap");
+               
+               
+               StringBuilder sb = new StringBuilder();
+               sb.append('\n');
+               sb.append("---------- Included system information ----------\n");
+               sb.append("OpenRocket version: " + Prefs.getVersion() + "\n");
+               sb.append("OpenRocket location: " + JarUtil.getCurrentJarFile() + "\n");
+               sb.append("System properties:\n");
+
+               // Sort the keys
+               SortedSet<String> keys = new TreeSet<String>();
+               for (Object key: System.getProperties().keySet()) {
+                       keys.add((String)key);
+               }
+               
+               for (String key: keys) {
+                       String value = System.getProperty(key);
+                       sb.append("  " + key + "=");
+                       if (key.equals("line.separator")) {
+                               for (char c: value.toCharArray()) {
+                                       sb.append(String.format("\\u%04x", (int)c));
+                               }
+                       } else {
+                               sb.append(value);
+                       }
+                       sb.append('\n');
+               }
+               
+               sb.append("---------- End system information ----------\n");
+               sb.append('\n');
+
+               JTextArea text = new JTextArea(sb.toString(), 15, 70);
+               text.setEditable(false);
+               panel.add(new JScrollPane(text), "grow, wrap para");
+               
+               JButton close = new JButton("Close");
+               close.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               BugDialog.this.dispose();
+                       }
+               });
+               panel.add(close, "right");
+
+               this.add(panel);
+               
+               this.pack();
+               this.setLocationRelativeTo(parent);
+               GUIUtil.installEscapeCloseOperation(this);
+               GUIUtil.setDefaultButton(close);
+       }
+
+}
index ca302bcc295cbc5d60662f3fc9876a4c07a88539..52184f3c98c1eaaaaaedc42579a0fb365667fd20 100644 (file)
@@ -1,22 +1,16 @@
 package net.sf.openrocket.gui.main;
 
-import java.awt.Desktop;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
 
 import javax.swing.JButton;
 import javax.swing.JDialog;
 import javax.swing.JFrame;
-import javax.swing.JLabel;
 import javax.swing.JPanel;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.ResizeLabel;
+import net.sf.openrocket.gui.components.ResizeLabel;
+import net.sf.openrocket.gui.components.URLLabel;
 import net.sf.openrocket.util.GUIUtil;
 import net.sf.openrocket.util.Prefs;
 
@@ -37,33 +31,7 @@ public class AboutDialog extends JDialog {
                
                panel.add(new ResizeLabel("Copyright \u00A9 2007-2009 Sampo Niskanen"), "ax 50%, wrap para");
                
-               JLabel link;
-               
-               if (Desktop.isDesktopSupported()) {
-                       
-                       link = new JLabel("<html><a href=\"" + OPENROCKET_URL + "\">" +
-                                       OPENROCKET_URL + "</a>");
-                       link.addMouseListener(new MouseAdapter() {
-                               @Override
-                               public void mouseClicked(MouseEvent e) {
-                                       Desktop d = Desktop.getDesktop();
-                                       try {
-                                               d.browse(new URI(OPENROCKET_URL));
-                                               
-                                       } catch (URISyntaxException e1) {
-                                               throw new RuntimeException("BUG: Illegal OpenRocket URL: "+OPENROCKET_URL,
-                                                               e1);
-                                       } catch (IOException e1) {
-                                               System.err.println("Unable to launch browser:");
-                                               e1.printStackTrace();
-                                       }
-                               }
-                       });
-                       
-               } else {
-                       link = new JLabel(OPENROCKET_URL);
-               }
-               panel.add(link, "ax 50%, wrap para");
+               panel.add(new URLLabel(OPENROCKET_URL), "ax 50%, wrap para");
                
 
                JButton close = new JButton("Close");
index 4bd73ca1d3a51c170e3a0d1c59bad2bb32079fef..a924db6489a9aefe9841aaab13a24efbfe16f023 100644 (file)
@@ -59,6 +59,7 @@ import net.sf.openrocket.gui.ComponentAnalysisDialog;
 import net.sf.openrocket.gui.PreferencesDialog;
 import net.sf.openrocket.gui.StorageOptionChooser;
 import net.sf.openrocket.gui.configdialog.ComponentConfigDialog;
+import net.sf.openrocket.gui.dialogs.BugDialog;
 import net.sf.openrocket.gui.scalefigure.RocketPanel;
 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
 import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
@@ -87,6 +88,8 @@ public class BasicFrame extends JFrame {
                }
                @Override
                public boolean accept(File f) {
+                       if (f.isDirectory())
+                               return true;
                        String name = f.getName().toLowerCase();
                        return name.endsWith(".ork") || name.endsWith(".ork.gz");
                }
@@ -117,7 +120,8 @@ public class BasicFrame extends JFrame {
        
        private RocketPanel rocketpanel;
        private ComponentTree tree = null;
-       private final TreeSelectionModel selectionModel;
+       private final TreeSelectionModel componentSelectionModel;
+       // private final ListSelectionModel simulationSelectionModel; ...
        
        /** Actions available for rocket modifications */
        private final RocketActions actions;
@@ -147,10 +151,10 @@ public class BasicFrame extends JFrame {
                
                
                // Create the selection model that will be used
-               selectionModel = new DefaultTreeSelectionModel();
-               selectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+               componentSelectionModel = new DefaultTreeSelectionModel();
+               componentSelectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
                
-               actions = new RocketActions(document, selectionModel, this);
+               actions = new RocketActions(document, componentSelectionModel, this);
                
                
                // The main vertical split pane         
@@ -232,7 +236,7 @@ public class BasicFrame extends JFrame {
                JPanel panel = new JPanel(new MigLayout("fill, flowy","","[grow]"));
 
                tree = new ComponentTree(rocket);
-               tree.setSelectionModel(selectionModel);
+               tree.setSelectionModel(componentSelectionModel);
 
                // Remove JTree key events that interfere with menu accelerators
                InputMap im = SwingUtilities.getUIInputMap(tree, JComponent.WHEN_FOCUSED);
@@ -265,10 +269,10 @@ public class BasicFrame extends JFrame {
                tree.addMouseListener(ml);
 
                // Update dialog when selection is changed
-               selectionModel.addTreeSelectionListener(new TreeSelectionListener() {
+               componentSelectionModel.addTreeSelectionListener(new TreeSelectionListener() {
                        public void valueChanged(TreeSelectionEvent e) {
                                // Scroll tree to the selected item
-                               TreePath path = selectionModel.getSelectionPath();
+                               TreePath path = componentSelectionModel.getSelectionPath();
                                if (path == null)
                                        return;
                                tree.scrollPathToVisible(path);
@@ -313,7 +317,7 @@ public class BasicFrame extends JFrame {
 
                scroll = new JScrollPane(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
-               scroll.setViewportView(new ComponentAddButtons(document, selectionModel,
+               scroll.setViewportView(new ComponentAddButtons(document, componentSelectionModel,
                                scroll.getViewport()));
                scroll.setBorder(null);
                scroll.setViewportBorder(null);
@@ -513,6 +517,8 @@ public class BasicFrame extends JFrame {
                menu.getAccessibleContext().setAccessibleDescription("Information about OpenRocket");
                menubar.add(menu);
                
+               
+               
                item = new JMenuItem("License",KeyEvent.VK_L);
                item.getAccessibleContext().setAccessibleDescription("OpenRocket license information");
                item.addActionListener(new ActionListener() {
@@ -522,6 +528,16 @@ public class BasicFrame extends JFrame {
                });
                menu.add(item);
                
+               item = new JMenuItem("Bug report",KeyEvent.VK_B);
+               item.getAccessibleContext().setAccessibleDescription("Information about reporting " +
+                               "bugs in OpenRocket");
+               item.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               new BugDialog(BasicFrame.this).setVisible(true);
+                       }
+               });
+               menu.add(item);
+               
                item = new JMenuItem("About",KeyEvent.VK_A);
                item.getAccessibleContext().setAccessibleDescription("About OpenRocket");
                item.addActionListener(new ActionListener() {
@@ -537,14 +553,13 @@ public class BasicFrame extends JFrame {
        
        
        
-       // TODO: HIGH: Remember last directory on open/save
        
        private void openAction() {
            JFileChooser chooser = new JFileChooser();
            chooser.setFileFilter(ROCKET_DESIGN_FILTER);
            chooser.setMultiSelectionEnabled(true);
            chooser.setCurrentDirectory(Prefs.getDefaultDirectory());
-           if (chooser.showOpenDialog(BasicFrame.this) != JFileChooser.APPROVE_OPTION)
+           if (chooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION)
                return;
            
            Prefs.setDefaultDirectory(chooser.getCurrentDirectory());
index 7d0308ca6cd023de48606ed83e6eca3057643af2..0b7454e78724117b61c0adf2467dd14464a95dd6 100644 (file)
@@ -26,7 +26,7 @@ import javax.swing.tree.TreeSelectionModel;
 
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.document.OpenRocketDocument;
-import net.sf.openrocket.gui.ResizeLabel;
+import net.sf.openrocket.gui.components.ResizeLabel;
 import net.sf.openrocket.gui.configdialog.ComponentConfigDialog;
 import net.sf.openrocket.rocketcomponent.BodyComponent;
 import net.sf.openrocket.rocketcomponent.BodyTube;
@@ -40,12 +40,14 @@ import net.sf.openrocket.rocketcomponent.LaunchLug;
 import net.sf.openrocket.rocketcomponent.MassComponent;
 import net.sf.openrocket.rocketcomponent.NoseCone;
 import net.sf.openrocket.rocketcomponent.Parachute;
+import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.rocketcomponent.ShockCord;
 import net.sf.openrocket.rocketcomponent.Streamer;
 import net.sf.openrocket.rocketcomponent.Transition;
 import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
 import net.sf.openrocket.rocketcomponent.TubeCoupler;
+import net.sf.openrocket.util.Pair;
 import net.sf.openrocket.util.Prefs;
 
 /**
@@ -94,20 +96,6 @@ public class ComponentAddButtons extends JPanel implements Scrollable {
                
                ////////////////////////////////////////////
                
-//             addButtonRow("Body components",row,
-//                             new ComponentButton(NoseCone.class,"Nose cone") {
-//                                     @Override
-//                                     public boolean isAddable(RocketComponent c) {
-//                                             if (!(c instanceof ComponentAssembly))
-//                                                     return false;
-//                                             if (c.getSiblingCount() == 0)
-//                                                     return true;
-//                                             return false;
-//                                     }
-//                             },
-//                             new BodyComponentButton(BodyTube.class,"Body tube"),
-//                             new BodyComponentButton(null,"Transition"));
-               
                
                addButtonRow("Body components and fin sets",row,
                                new BodyComponentButton(NoseCone.class,"Nose cone"),
@@ -120,7 +108,6 @@ public class ComponentAddButtons extends JPanel implements Scrollable {
                );
                
                row++;
-/////
                
                
                /////////////////////////////////////////////
@@ -328,16 +315,16 @@ public class ComponentAddButtons extends JPanel implements Scrollable {
                /**
                 * Return the position to add the component if component c is selected currently.
                 * The first element of the returned array is the RocketComponent to add the component
-                * to, and the second (in any) an Integer telling the position of the component.
+                * to, and the second (if non-null) an Integer telling the position of the component.
                 * A return value of null means that the user cancelled addition of the component.
-                * If the array has only one element, the component is added at the end of the sibling 
+                * If the Integer is null, the component is added at the end of the sibling 
                 * list.  By default returns the end of the currently selected component.
                 * 
                 * @param c  The component currently selected
                 * @return   The position to add the new component to, or null if should not add.
                 */
-               public Object[] getAdditionPosition(RocketComponent c) {
-                       return new Object[] { c };
+               public Pair<RocketComponent, Integer> getAdditionPosition(RocketComponent c) {
+                       return new Pair<RocketComponent, Integer>(c, null);
                }
                
                /**
@@ -381,17 +368,15 @@ public class ComponentAddButtons extends JPanel implements Scrollable {
                        TreePath p = selectionModel.getSelectionPath();
                        if (p!= null)
                                c = (RocketComponent)p.getLastPathComponent();
-                       if (c != null) {
-                               Object[] pos = getAdditionPosition(c);
-                               if (pos==null || pos.length==0) {
-                                       // Cancel addition
-                                       return;
-                               }
 
-                               c = (RocketComponent)pos[0];
-                               if (pos.length>1)
-                                       position = (Integer)pos[1];
+                       Pair<RocketComponent, Integer> pos = getAdditionPosition(c);
+                       if (pos==null) {
+                               // Cancel addition
+                               return;
                        }
+                       c = pos.getU();
+                       position = pos.getV();
+
                        
                        if (c == null) {
                                // Should not occur
@@ -460,17 +445,27 @@ public class ComponentAddButtons extends JPanel implements Scrollable {
                public boolean isAddable(RocketComponent c) {
                        if (super.isAddable(c))
                                return true;
-                       if (c instanceof BodyComponent)  // Handled separately
+                       // Handled separately:
+                       if (c instanceof BodyComponent)
+                               return true;
+                       if (c == null || c instanceof Rocket)
                                return true;
                        return false;
                }
                
                @Override
-               public Object[] getAdditionPosition(RocketComponent c) {
+               public Pair<RocketComponent, Integer> getAdditionPosition(RocketComponent c) {
                        if (super.isAddable(c))     // Handled automatically
                                return super.getAdditionPosition(c);
                        
-                       // Handle BodyComponent separately
+                       
+                       if (c == null || c instanceof Rocket) {
+                               // Add as last body component of the last stage
+                               Rocket rocket = document.getRocket();
+                               return new Pair<RocketComponent,Integer>(rocket.getChild(rocket.getStageCount()-1),
+                                               null);
+                       }
+                       
                        if (!(c instanceof BodyComponent))
                                return null;
                        RocketComponent parent = c.getParent();
@@ -492,10 +487,10 @@ public class ComponentAddButtons extends JPanel implements Scrollable {
                                return null;
                        case 1:
                                // Insert after current position
-                               return new Object[] { parent, new Integer(parent.getChildPosition(c)+1) };
+                               return new Pair<RocketComponent,Integer>(parent, parent.getChildPosition(c)+1);
                        case 2:
                                // Insert at the end of the parent
-                               return new Object[] { parent };
+                               return new Pair<RocketComponent,Integer>(parent, null);
                        default:
                                System.err.println("ERROR:  Bad position type: "+pos);
                                Thread.dumpStack();
diff --git a/src/net/sf/openrocket/gui/main/DocumentSelectionListener.java b/src/net/sf/openrocket/gui/main/DocumentSelectionListener.java
new file mode 100644 (file)
index 0000000..055f111
--- /dev/null
@@ -0,0 +1,15 @@
+package net.sf.openrocket.gui.main;
+
+public interface DocumentSelectionListener {
+
+       public static final int COMPONENT_SELECTION_CHANGE = 1;
+       public static final int SIMULATION_SELECTION_CHANGE = 2;
+       
+       /**
+        * Called when the selection changes.
+        * 
+        * @param changeType    a bitmask of the type of change.
+        */
+       public void valueChanged(int changeType);
+       
+}
diff --git a/src/net/sf/openrocket/gui/main/DocumentSelectionModel.java b/src/net/sf/openrocket/gui/main/DocumentSelectionModel.java
new file mode 100644 (file)
index 0000000..94bc39d
--- /dev/null
@@ -0,0 +1,189 @@
+package net.sf.openrocket.gui.main;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+
+public class DocumentSelectionModel {
+
+       private static final Simulation[] NO_SIMULATION = new Simulation[0];
+
+       private final ComponentTreeSelectionListener componentTreeSelectionListener =
+               new ComponentTreeSelectionListener();
+       private final SimulationListSelectionListener simulationListSelectionListener =
+               new SimulationListSelectionListener();
+
+       
+       private final OpenRocketDocument document;
+       
+       private RocketComponent componentSelection = null;
+       private Simulation[] simulationSelection = NO_SIMULATION;
+
+       private TreeSelectionModel componentTreeSelectionModel = null; 
+       private ListSelectionModel simulationListSelectionModel = null;
+
+       private final List<DocumentSelectionListener> listeners =
+               new ArrayList<DocumentSelectionListener>();
+
+       
+       
+       public DocumentSelectionModel(OpenRocketDocument document) {
+               this.document = document;
+       }
+       
+
+
+
+       /**
+        * Return the currently selected simulations.  Returns an empty array if none
+        * are selected.
+        * 
+        * @return      an array of the currently selected simulations, may be of zero length.
+        */
+       public Simulation[] getSelectedSimulations() {
+               return Arrays.copyOf(simulationSelection, simulationSelection.length);
+       }
+
+       /**
+        * Return the currently selected rocket component.  Returns <code>null</code>
+        * if no rocket component is selected.
+        * 
+        * @return      the currently selected rocket component, or <code>null</code>.
+        */
+       public RocketComponent getSelectedComponent() {
+               return componentSelection;
+       }
+
+
+
+       
+
+       public void attachComponentTreeSelectionModel(TreeSelectionModel model) {
+               if (componentTreeSelectionModel != null)
+                       componentTreeSelectionModel.removeTreeSelectionListener(
+                                       componentTreeSelectionListener);
+
+               componentTreeSelectionModel = model;
+               if (model != null)
+                       model.addTreeSelectionListener(componentTreeSelectionListener);
+               clearComponentSelection();
+       }
+       
+       
+       
+       public void attachSimulationListSelectionModel(ListSelectionModel model) {
+               if (simulationListSelectionModel != null)
+                       simulationListSelectionModel.removeListSelectionListener(
+                                       simulationListSelectionListener);
+               
+               simulationListSelectionModel = model;
+               if (model != null)
+                       model.addListSelectionListener(simulationListSelectionListener);
+               clearSimulationSelection();
+       }
+
+       
+       
+       public void clearSimulationSelection() {
+               if (simulationSelection.length == 0)
+                       return;
+               
+               simulationSelection = NO_SIMULATION;
+               if (simulationListSelectionModel != null)
+                       simulationListSelectionModel.clearSelection();
+               
+               fireDocumentSelection(DocumentSelectionListener.SIMULATION_SELECTION_CHANGE);
+       }
+       
+       
+       public void clearComponentSelection() {
+               if (componentSelection == null)
+                       return;
+               
+               componentSelection = null;
+               if (componentTreeSelectionModel != null)
+                       componentTreeSelectionModel.clearSelection();
+               
+               fireDocumentSelection(DocumentSelectionListener.COMPONENT_SELECTION_CHANGE);
+       }
+
+
+       
+       public void addDocumentSelectionListener(DocumentSelectionListener l) {
+               listeners.add(l);
+       }
+       
+       public void removeDocumentSelectionListener(DocumentSelectionListener l) {
+               listeners.remove(l);
+       }
+       
+       protected void fireDocumentSelection(int type) {
+               DocumentSelectionListener[] array = 
+                       listeners.toArray(new DocumentSelectionListener[0]);
+               
+               for (DocumentSelectionListener l: array) {
+                       l.valueChanged(type);
+               }
+       }
+       
+       
+       
+       private class ComponentTreeSelectionListener implements TreeSelectionListener {
+
+               @Override
+               public void valueChanged(TreeSelectionEvent e) {
+                       TreePath path = componentTreeSelectionModel.getSelectionPath();
+                       if (path == null) {
+                               componentSelection = null;
+                               fireDocumentSelection(DocumentSelectionListener.COMPONENT_SELECTION_CHANGE);
+                               return;
+                       }
+                       
+                       componentSelection = (RocketComponent)path.getLastPathComponent();
+                       
+                       clearSimulationSelection();
+                       fireDocumentSelection(DocumentSelectionListener.COMPONENT_SELECTION_CHANGE);
+               }
+
+       }
+       
+       private class SimulationListSelectionListener implements ListSelectionListener {
+
+               @Override
+               public void valueChanged(ListSelectionEvent e) {
+                       int min = simulationListSelectionModel.getMinSelectionIndex();
+                       int max = simulationListSelectionModel.getMaxSelectionIndex();
+                       if (min < 0 || max < 0) {
+                               simulationSelection = NO_SIMULATION;
+                               fireDocumentSelection(DocumentSelectionListener.SIMULATION_SELECTION_CHANGE);
+                               return;
+                       }
+                       
+                       ArrayList<Simulation> list = new ArrayList<Simulation>();
+                       for (int i = min; i <= max; i++) {
+                               if (simulationListSelectionModel.isSelectedIndex(i) && 
+                                               (i < document.getSimulationCount())) {
+                                       list.add(document.getSimulation(i));
+                               }
+                       }
+                       simulationSelection = list.toArray(NO_SIMULATION);
+                       
+                       clearComponentSelection();
+                       fireDocumentSelection(DocumentSelectionListener.SIMULATION_SELECTION_CHANGE);
+               }
+               
+       }
+
+}
index 77690b9df0266fcb81588161c9fe55baaeede6d5..6df25692ee9ae1cf587671b6c1249456a8a7e1b2 100644 (file)
@@ -14,7 +14,7 @@ import javax.swing.JScrollPane;
 import javax.swing.JTextArea;
 
 import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.ResizeLabel;
+import net.sf.openrocket.gui.components.ResizeLabel;
 import net.sf.openrocket.util.GUIUtil;
 
 public class LicenseDialog extends JDialog {
index c6e0f0f3ff967bf4ae0b59479479fcf78e24207e..04a78979aa6575593143edaade26decf14308fd6 100644 (file)
@@ -32,7 +32,7 @@ import javax.swing.table.TableRowSorter;
 
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.database.Databases;
-import net.sf.openrocket.gui.ResizeLabel;
+import net.sf.openrocket.gui.components.ResizeLabel;
 import net.sf.openrocket.rocketcomponent.Motor;
 import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.util.GUIUtil;
diff --git a/src/net/sf/openrocket/gui/main/OpenRocketClipboard.java b/src/net/sf/openrocket/gui/main/OpenRocketClipboard.java
new file mode 100644 (file)
index 0000000..b50bffc
--- /dev/null
@@ -0,0 +1,35 @@
+package net.sf.openrocket.gui.main;
+
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+
+public class OpenRocketClipboard {
+
+       private static Object clipboard = null;
+       
+       private OpenRocketClipboard() {
+               // Disallow instantiation
+       }
+       
+       
+       /**
+        * Return the <code>RocketComponent</code> contained in the clipboard, or
+        * <code>null</code>.
+        * 
+        * @return      the rocket component contained in the clipboard, or <code>null</code>
+        *                      if the clipboard does not currently contain a rocket component.
+        */
+       public static RocketComponent getComponent() {
+               if (clipboard instanceof RocketComponent) {
+                       return (RocketComponent) clipboard;
+               }
+               return null;
+       }
+       
+       
+       public static Simulation[] getSimulations() {
+               return null; // TODO
+       }
+       
+       
+}
index 05b31e4b442a57b35d0bbce0ddd7f383d68f8355..b035228330a71aab3dbb62969aea43823ee65442 100644 (file)
@@ -28,7 +28,7 @@ import net.sf.openrocket.util.Pair;
 
 
 /**
- * A class that holds Actions for common rocket operations such as
+ * A class that holds Actions for common rocket and simulation operations such as
  * cut/copy/paste/delete etc.
  * 
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
index f9c1c4c6566b75dd6c76ce64a856c0842cbeb4e0..5074d1120f00885ae7868da24ee5373893430f0b 100644 (file)
@@ -32,13 +32,13 @@ import javax.swing.event.DocumentListener;
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.aerodynamics.ExtendedISAModel;
 import net.sf.openrocket.document.Simulation;
-import net.sf.openrocket.gui.BasicSlider;
-import net.sf.openrocket.gui.DescriptionArea;
 import net.sf.openrocket.gui.SpinnerEditor;
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.BooleanModel;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.adaptors.MotorConfigurationModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.DescriptionArea;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.gui.plot.Axis;
 import net.sf.openrocket.gui.plot.PlotConfiguration;
 import net.sf.openrocket.gui.plot.PlotPanel;
index bb3cd3aa566cfad44ac2846fceef91b59f1becb8..a4046fb8266962f6a429f7b9e17d06e196d6a8cb 100644 (file)
@@ -25,9 +25,9 @@ import net.sf.openrocket.aerodynamics.Warning;
 import net.sf.openrocket.aerodynamics.WarningSet;
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.document.Simulation;
-import net.sf.openrocket.gui.ResizeLabel;
 import net.sf.openrocket.gui.adaptors.Column;
 import net.sf.openrocket.gui.adaptors.ColumnTableModel;
+import net.sf.openrocket.gui.components.ResizeLabel;
 import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
 import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
 import net.sf.openrocket.simulation.FlightData;
index 953ab4a0fe54bd4e6428af592ca802411723b66c..b049b2eb3635d4226a2654a67c9f585c58eb7b6a 100644 (file)
@@ -16,8 +16,8 @@ import javax.swing.SwingUtilities;
 
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.document.Simulation;
-import net.sf.openrocket.gui.ResizeLabel;
-import net.sf.openrocket.gui.UnitSelector;
+import net.sf.openrocket.gui.components.ResizeLabel;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.simulation.FlightDataBranch;
 import net.sf.openrocket.simulation.FlightDataBranch.Type;
 import net.sf.openrocket.unit.Unit;
index 94bf1017de70cbbbfc31b9fe79a5237672b7f549..e40ba387c85f40d44070070a969883441973e55e 100644 (file)
@@ -37,11 +37,11 @@ import net.sf.openrocket.aerodynamics.FlightConditions;
 import net.sf.openrocket.aerodynamics.WarningSet;
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.document.Simulation;
-import net.sf.openrocket.gui.BasicSlider;
-import net.sf.openrocket.gui.StageSelector;
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.adaptors.MotorConfigurationModel;
+import net.sf.openrocket.gui.components.BasicSlider;
+import net.sf.openrocket.gui.components.StageSelector;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.gui.configdialog.ComponentConfigDialog;
 import net.sf.openrocket.gui.figureelements.CGCaret;
 import net.sf.openrocket.gui.figureelements.CPCaret;
@@ -360,7 +360,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
         * 
         * Get the components clicked.
         * If no component is clicked, do nothing.
-        * If the primary currently selected component is in the set, keep it, 
+        * If the currently selected component is in the set, keep it, 
         * unless the selector specified is pressed.  If it is pressed, cycle to 
         * the next component. Otherwise select the first component in the list. 
         */
@@ -399,7 +399,11 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
 
                // Currently selected component not clicked
                if (path == null) {
-                       path = ComponentTreeModel.makeTreePath(clicked[0]);
+                       if (event.isShiftDown() && event.getClickCount()==1 && clicked.length>1) {
+                               path = ComponentTreeModel.makeTreePath(clicked[1]);
+                       } else {
+                               path = ComponentTreeModel.makeTreePath(clicked[0]);
+                       }
                }
                
                // Set selection and check for double-click
index e1d08b6e748090e85304abb45d82a062b3324c6e..caa285156e3bc5467ad95f681ebba6c5ad9ef0bf 100644 (file)
@@ -23,8 +23,8 @@ import javax.swing.ScrollPaneConstants;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 
-import net.sf.openrocket.gui.UnitSelector;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
+import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.unit.Tick;
 import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
diff --git a/src/net/sf/openrocket/startup/Startup.java b/src/net/sf/openrocket/startup/Startup.java
new file mode 100644 (file)
index 0000000..a2120d2
--- /dev/null
@@ -0,0 +1,180 @@
+package net.sf.openrocket.startup;
+
+import java.awt.GraphicsEnvironment;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import javax.swing.JOptionPane;
+
+
+/**
+ * A startup class that checks that a suitable JRE environment is being run.
+ * If the environment is too old the execution is canceled, and if OpenJDK is being
+ * used warns the user of problems and confirms whether to continue.
+ * <p>
+ * Note:  This class must be Java 1.4 compatible and calls the next class using
+ * only reflection.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class Startup {
+       
+       public static final String START_CLASS = "net.sf.openrocket.gui.main.BasicFrame";
+       
+       public static final int REQUIRED_MAJOR_VERSION = 1;
+       public static final int REQUIRED_MINOR_VERSION = 6;
+
+
+       public static void main(String[] args) {
+               
+               checkVersion();
+               checkHead();
+               checkOpenJDK();
+               
+               // Load and execute START_CLASS
+               try {
+                       
+                       Class cls = Class.forName(START_CLASS);
+                       Method m = cls.getMethod("main", String[].class);
+                       m.invoke(null, new Object[] { args });
+                       
+               } catch (ClassNotFoundException e) {
+                       e.printStackTrace();
+                       error("Error starting main class!", "Please report a bug.");
+               } catch (NoSuchMethodException e) {
+                       e.printStackTrace();
+                       error("Error starting main class!", "Please report a bug.");
+               } catch (InvocationTargetException e) {
+                       e.printStackTrace();
+                       error("Error starting main class!", "Please report a bug.");
+               } catch (IllegalAccessException e) {
+                       e.printStackTrace();
+                       error("Error starting main class!", "Please report a bug.");
+               }
+
+       }
+       
+       
+       /**
+        * Check that the JRE version is high enough.
+        */
+       private static void checkVersion() {
+               String[] version = System.getProperty("java.specification.version", "").split("\\.");
+               
+               String jreName = System.getProperty("java.vm.name", "(unknown)");
+               String jreVersion = System.getProperty("java.runtime.version", "(unknown)");
+               String jreVendor = System.getProperty("java.vendor", "(unknown)");
+               
+               int major, minor;
+
+               try {
+                       major = Integer.parseInt(version[0]);
+                       minor = Integer.parseInt(version[1]);
+                       
+                       if (major < REQUIRED_MAJOR_VERSION || 
+                                       (major == REQUIRED_MAJOR_VERSION && minor < REQUIRED_MINOR_VERSION)) {
+                               error("Java SE version 6 is required to run OpenRocket.",
+                                               "You are currently running " + jreName + " version " +
+                                               jreVersion + " by " + jreVendor);
+                       }
+                       
+               } catch (RuntimeException e) {
+                       
+                       confirm("The Java version in use could not be detected.",
+                                       "OpenRocket requires at least Java SE 6.",
+                                       "Continue anyway?");
+                       
+               }
+               
+       }
+
+       
+       /**
+        * Check that the JRE is not running headless.
+        */
+       private static void checkHead() {
+               
+               if (GraphicsEnvironment.isHeadless()) {
+                       System.err.println();
+                       System.err.println("OpenRocket cannot currently be run without the graphical " +
+                                       "user interface.");
+                       System.err.println();
+                       System.exit(1);
+               }
+               
+       }
+       
+       
+       /**
+        * Check whether OpenJDK is being used, and if it is warn the user about
+        * problems and confirm whether to continue.
+        */
+       private static void checkOpenJDK() {
+               
+               if (System.getProperty("java.runtime.name", "").toLowerCase().indexOf("icedtea")>=0 ||
+                               System.getProperty("java.vm.name", "").toLowerCase().indexOf("openjdk")>=0) {
+
+                       String jreName = System.getProperty("java.vm.name", "(unknown)");
+                       String jreVersion = System.getProperty("java.runtime.version", "(unknown)");
+                       String jreVendor = System.getProperty("java.vendor", "(unknown)");
+
+                       confirm("OpenJDK is known to have problems running OpenRocket.",
+                                       " ",
+                                       "You are currently running " + jreName + " version " +
+                                       jreVersion + " by " + jreVendor,
+                                       "Do you want to continue?");
+                       
+               }
+       }
+
+       
+       
+       
+       /**
+        * Presents an error message to the user and exits the application.
+        * 
+        * @param message       an array of messages to present.
+        */
+       private static void error(String ... message) {
+
+               System.err.println();
+               System.err.println("Error starting OpenRocket:");
+               System.err.println();
+               for (int i=0; i < message.length; i++) {
+                       System.err.println(message[i]);
+               }
+               System.err.println();
+
+               
+               if (!GraphicsEnvironment.isHeadless()) {
+
+                       JOptionPane.showMessageDialog(null, message, "Error starting OpenRocket",
+                                       JOptionPane.ERROR_MESSAGE);
+                       
+               }
+               
+               System.exit(1);
+       }
+       
+       
+       /**
+        * Presents the user with a message dialog and asks whether to continue.
+        * If the user does not select "Yes" the the application exits.
+        * 
+        * @param message       the message Strings to show.
+        */
+       private static void confirm(String ... message) {
+
+               if (!GraphicsEnvironment.isHeadless()) {
+                       
+                       if (JOptionPane.showConfirmDialog(null, message, "Error starting OpenRocket",
+                                       JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
+                               System.exit(1);
+                       }
+                       
+               }
+
+       }
+       
+       
+}
index 2946dc7079c133ac99f23ffee44d4d586ebea0ec..c175d4ef45c6e654ce5398a89c911fd31d88b91d 100644 (file)
@@ -47,7 +47,7 @@ public class FixedPrecisionUnit extends Unit {
 
        @Override
        public String toString(double value) {
-               return String.format(formatString, value);
+               return String.format(formatString, this.toUnit(value));
        }
        
        
diff --git a/src/net/sf/openrocket/util/JarUtil.java b/src/net/sf/openrocket/util/JarUtil.java
new file mode 100644 (file)
index 0000000..7e45a65
--- /dev/null
@@ -0,0 +1,50 @@
+package net.sf.openrocket.util;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.security.CodeSource;
+
+import net.sf.openrocket.database.Database;
+
+public class JarUtil {
+
+       /**
+        * Return the a File object pointing to the JAR file that this class belongs to,
+        * or <code>null</code> if it cannot be found.
+        * 
+        * @return      a File object of the current Java archive, or <code>null</code>
+        */
+       public static File getCurrentJarFile() {
+               // Find the jar file this class is contained in
+               URL jarUrl = null;
+               CodeSource codeSource = Database.class.getProtectionDomain().getCodeSource();
+               if (codeSource != null)
+                       jarUrl = codeSource.getLocation();
+               
+               if (jarUrl == null) {
+                       return null;
+               }
+               return urlToFile(jarUrl);
+       }
+       
+       
+
+       public static File urlToFile(URL url) {
+               URI uri;
+               try {
+                       uri = url.toURI();
+               } catch (URISyntaxException e) {
+                       try {
+                               uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), 
+                                               url.getPort(), url.getPath(), url.getQuery(), url.getRef());
+                       } catch (URISyntaxException e1) {
+                               throw new IllegalArgumentException("Broken URL: " + url);
+                       }
+               }
+               return new File(uri);
+       }
+       
+       
+}
diff --git a/src/net/sf/openrocket/util/PrintProperties.java b/src/net/sf/openrocket/util/PrintProperties.java
new file mode 100644 (file)
index 0000000..d3d4fe1
--- /dev/null
@@ -0,0 +1,22 @@
+package net.sf.openrocket.util;
+
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+public class PrintProperties {
+
+       public static void main(String[] args) {
+
+               // Sort the keys
+               SortedSet<String> keys = new TreeSet<String>();
+               for (Object key: System.getProperties().keySet()) {
+                       keys.add((String)key);
+               }
+               
+               for (String key: keys) {
+                       System.out.println(key + "=" + System.getProperty((String)key));
+               }
+               
+       }
+
+}