From: plaa Date: Sun, 31 May 2009 17:50:09 +0000 (+0000) Subject: Bug fixes and startup checks X-Git-Tag: upstream/1.0.0~32 X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=02f3d96a74beac56396117f4c8ea3497134ad139;hp=cc0359dcfd20fcaca76bbb6ac1138dbc3d3528cb;p=debian%2Fopenrocket Bug fixes and startup checks git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@6 180e2498-e6e9-4542-8430-84ac67f01cd8 --- diff --git a/ChangeLog b/ChangeLog index 9e11801e..7efec8a2 100644 --- 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 * Initial release 0.9.0 - diff --git a/build.xml b/build.xml index f5639657..c4892fa8 100644 --- a/build.xml +++ b/build.xml @@ -12,7 +12,7 @@ - + diff --git a/html/download.html b/html/download.html index 0795dc8a..f79600f3 100644 --- a/html/download.html +++ b/html/download.html @@ -76,7 +76,7 @@

The source code for OpenRocket is available from the SourceForge SVN repository. It can be retrieved simply using the command

-
$ svn co https://openrocket.svn.sourceforge.net/svnroot/openrocket openrocket
+
$ svn co https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk OpenRocket

The above URL may be used to connect to the repository with other Subversion clients as well.

diff --git a/src/net/sf/openrocket/database/Database.java b/src/net/sf/openrocket/database/Database.java index b7986cb7..fd901dfa 100644 --- a/src/net/sf/openrocket/database/Database.java +++ b/src/net/sf/openrocket/database/Database.java @@ -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> extends AbstractSet 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> extends AbstractSet 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) { diff --git a/src/net/sf/openrocket/file/openrocket/TransitionSaver.java b/src/net/sf/openrocket/file/openrocket/TransitionSaver.java index d597d129..461087f6 100644 --- a/src/net/sf/openrocket/file/openrocket/TransitionSaver.java +++ b/src/net/sf/openrocket/file/openrocket/TransitionSaver.java @@ -33,7 +33,7 @@ public class TransitionSaver extends SymmetricComponentSaver { Transition.Shape shape = trans.getType(); - elements.add("" + shape.getName().toLowerCase() + ""); + elements.add("" + shape.name().toLowerCase() + ""); if (shape.isClippable()) { elements.add("" + trans.isClipped() + ""); } diff --git a/src/net/sf/openrocket/gui/BasicSlider.java b/src/net/sf/openrocket/gui/BasicSlider.java deleted file mode 100644 index d22c3e83..00000000 --- a/src/net/sf/openrocket/gui/BasicSlider.java +++ /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 - */ - -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/ComponentAnalysisDialog.java b/src/net/sf/openrocket/gui/ComponentAnalysisDialog.java index e44e48bd..7fa39a7a 100644 --- a/src/net/sf/openrocket/gui/ComponentAnalysisDialog.java +++ b/src/net/sf/openrocket/gui/ComponentAnalysisDialog.java @@ -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 index ba29be47..00000000 --- a/src/net/sf/openrocket/gui/DescriptionArea.java +++ /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("")) - txt = "" + 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/PreferencesDialog.java b/src/net/sf/openrocket/gui/PreferencesDialog.java index e42d9f92..2cdb4c45 100644 --- a/src/net/sf/openrocket/gui/PreferencesDialog.java +++ b/src/net/sf/openrocket/gui/PreferencesDialog.java @@ -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 index 6951d628..00000000 --- a/src/net/sf/openrocket/gui/ResizeLabel.java +++ /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. - *

- * A nice small text is achievable by new ResizeLabel("My text", -2); - * - * @author Sampo Niskanen - */ - -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 index a0ad4376..00000000 --- a/src/net/sf/openrocket/gui/StageSelector.java +++ /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 buttons = new ArrayList(); - - 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 index 37453ef4..00000000 --- a/src/net/sf/openrocket/gui/UnitSelector.java +++ /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 - */ - -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 itemListeners = new ArrayList(); - - - /** - * 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 null. - * Either this method or {@link #getUnitGroup()} always returns null. - * - * @return the DoubleModel being used, or null. - */ - public DoubleModel getModel() { - return model; - } - - - /** - * Return the unit group that is being shown, or null. Either this method - * or {@link #getModel()} always returns null. - * - * @return the UnitGroup being used, or null. - */ - 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 - -} diff --git a/src/net/sf/openrocket/gui/adaptors/MaterialModel.java b/src/net/sf/openrocket/gui/adaptors/MaterialModel.java index 1af6f2ad..1daf286c 100644 --- a/src/net/sf/openrocket/gui/adaptors/MaterialModel.java +++ b/src/net/sf/openrocket/gui/adaptors/MaterialModel.java @@ -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; diff --git a/src/net/sf/openrocket/gui/adaptors/MotorConfigurationModel.java b/src/net/sf/openrocket/gui/adaptors/MotorConfigurationModel.java index fbf367bf..9f96997c 100644 --- a/src/net/sf/openrocket/gui/adaptors/MotorConfigurationModel.java +++ b/src/net/sf/openrocket/gui/adaptors/MotorConfigurationModel.java @@ -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 index 00000000..0ac92e79 --- /dev/null +++ b/src/net/sf/openrocket/gui/components/BasicSlider.java @@ -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 + */ + +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 index 00000000..264953f7 --- /dev/null +++ b/src/net/sf/openrocket/gui/components/DescriptionArea.java @@ -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("")) + txt = "" + 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 index 00000000..0978252a --- /dev/null +++ b/src/net/sf/openrocket/gui/components/ResizeLabel.java @@ -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. + *

+ * A nice small text is achievable by new ResizeLabel("My text", -2); + * + * @author Sampo Niskanen + */ + +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 index 00000000..5b5e78ae --- /dev/null +++ b/src/net/sf/openrocket/gui/components/StageSelector.java @@ -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 buttons = new ArrayList(); + + 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 index 00000000..be6bdd82 --- /dev/null +++ b/src/net/sf/openrocket/gui/components/URLLabel.java @@ -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 + */ +public class URLLabel extends JLabel { + + private final String url; + + public URLLabel(String urlLabel) { + super(); + + this.url = urlLabel; + + + if (Desktop.isDesktopSupported()) { + + setText("" + url + ""); + + 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 index 00000000..962992e2 --- /dev/null +++ b/src/net/sf/openrocket/gui/components/UnitSelector.java @@ -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 + */ + +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 itemListeners = new ArrayList(); + + + /** + * 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 null. + * Either this method or {@link #getUnitGroup()} always returns null. + * + * @return the DoubleModel being used, or null. + */ + public DoubleModel getModel() { + return model; + } + + + /** + * Return the unit group that is being shown, or null. Either this method + * or {@link #getModel()} always returns null. + * + * @return the UnitGroup being used, or null. + */ + 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 + +} diff --git a/src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java b/src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java index 7c5776ad..874111a2 100644 --- a/src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java @@ -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; diff --git a/src/net/sf/openrocket/gui/configdialog/EllipticalFinSetConfig.java b/src/net/sf/openrocket/gui/configdialog/EllipticalFinSetConfig.java index 8092ae4b..51f45318 100644 --- a/src/net/sf/openrocket/gui/configdialog/EllipticalFinSetConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/EllipticalFinSetConfig.java @@ -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; diff --git a/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java b/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java index de59d7a1..889d4adf 100644 --- a/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java @@ -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; diff --git a/src/net/sf/openrocket/gui/configdialog/InnerTubeConfig.java b/src/net/sf/openrocket/gui/configdialog/InnerTubeConfig.java index b8d9534b..b1319b7b 100644 --- a/src/net/sf/openrocket/gui/configdialog/InnerTubeConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/InnerTubeConfig.java @@ -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; diff --git a/src/net/sf/openrocket/gui/configdialog/LaunchLugConfig.java b/src/net/sf/openrocket/gui/configdialog/LaunchLugConfig.java index 9ef72034..909c5d31 100644 --- a/src/net/sf/openrocket/gui/configdialog/LaunchLugConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/LaunchLugConfig.java @@ -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; diff --git a/src/net/sf/openrocket/gui/configdialog/MassComponentConfig.java b/src/net/sf/openrocket/gui/configdialog/MassComponentConfig.java index 93a3d472..5bff03a0 100644 --- a/src/net/sf/openrocket/gui/configdialog/MassComponentConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/MassComponentConfig.java @@ -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; diff --git a/src/net/sf/openrocket/gui/configdialog/MotorConfig.java b/src/net/sf/openrocket/gui/configdialog/MotorConfig.java index 47b94192..cf81eaab 100644 --- a/src/net/sf/openrocket/gui/configdialog/MotorConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/MotorConfig.java @@ -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; diff --git a/src/net/sf/openrocket/gui/configdialog/NoseConeConfig.java b/src/net/sf/openrocket/gui/configdialog/NoseConeConfig.java index 1c75f8c1..f1b6daf2 100644 --- a/src/net/sf/openrocket/gui/configdialog/NoseConeConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/NoseConeConfig.java @@ -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; diff --git a/src/net/sf/openrocket/gui/configdialog/ParachuteConfig.java b/src/net/sf/openrocket/gui/configdialog/ParachuteConfig.java index 340dfb8c..c058725d 100644 --- a/src/net/sf/openrocket/gui/configdialog/ParachuteConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/ParachuteConfig.java @@ -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; diff --git a/src/net/sf/openrocket/gui/configdialog/RingComponentConfig.java b/src/net/sf/openrocket/gui/configdialog/RingComponentConfig.java index 9acbbda0..1b2f12ad 100644 --- a/src/net/sf/openrocket/gui/configdialog/RingComponentConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/RingComponentConfig.java @@ -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; diff --git a/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java b/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java index 9b19bcb8..5e017a4b 100644 --- a/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java @@ -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; diff --git a/src/net/sf/openrocket/gui/configdialog/ShockCordConfig.java b/src/net/sf/openrocket/gui/configdialog/ShockCordConfig.java index 9b82ea9f..e3b1ba53 100644 --- a/src/net/sf/openrocket/gui/configdialog/ShockCordConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/ShockCordConfig.java @@ -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; diff --git a/src/net/sf/openrocket/gui/configdialog/StreamerConfig.java b/src/net/sf/openrocket/gui/configdialog/StreamerConfig.java index 951969e6..132f6a5e 100644 --- a/src/net/sf/openrocket/gui/configdialog/StreamerConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/StreamerConfig.java @@ -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; diff --git a/src/net/sf/openrocket/gui/configdialog/TransitionConfig.java b/src/net/sf/openrocket/gui/configdialog/TransitionConfig.java index 61a6ff24..3a908ee8 100644 --- a/src/net/sf/openrocket/gui/configdialog/TransitionConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/TransitionConfig.java @@ -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; diff --git a/src/net/sf/openrocket/gui/configdialog/TrapezoidFinSetConfig.java b/src/net/sf/openrocket/gui/configdialog/TrapezoidFinSetConfig.java index 4a640ec9..92081be6 100644 --- a/src/net/sf/openrocket/gui/configdialog/TrapezoidFinSetConfig.java +++ b/src/net/sf/openrocket/gui/configdialog/TrapezoidFinSetConfig.java @@ -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 index 00000000..ae0bee8c --- /dev/null +++ b/src/net/sf/openrocket/gui/dialogs/BugDialog.java @@ -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("Please copy and paste the following information " + + "to the end of your bug report:"), "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 keys = new TreeSet(); + 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); + } + +} diff --git a/src/net/sf/openrocket/gui/main/AboutDialog.java b/src/net/sf/openrocket/gui/main/AboutDialog.java index ca302bcc..52184f3c 100644 --- a/src/net/sf/openrocket/gui/main/AboutDialog.java +++ b/src/net/sf/openrocket/gui/main/AboutDialog.java @@ -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("" + - OPENROCKET_URL + ""); - 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"); diff --git a/src/net/sf/openrocket/gui/main/BasicFrame.java b/src/net/sf/openrocket/gui/main/BasicFrame.java index 4bd73ca1..a924db64 100644 --- a/src/net/sf/openrocket/gui/main/BasicFrame.java +++ b/src/net/sf/openrocket/gui/main/BasicFrame.java @@ -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()); diff --git a/src/net/sf/openrocket/gui/main/ComponentAddButtons.java b/src/net/sf/openrocket/gui/main/ComponentAddButtons.java index 7d0308ca..0b7454e7 100644 --- a/src/net/sf/openrocket/gui/main/ComponentAddButtons.java +++ b/src/net/sf/openrocket/gui/main/ComponentAddButtons.java @@ -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 getAdditionPosition(RocketComponent c) { + return new Pair(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 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 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(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(parent, parent.getChildPosition(c)+1); case 2: // Insert at the end of the parent - return new Object[] { parent }; + return new Pair(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 index 00000000..055f1116 --- /dev/null +++ b/src/net/sf/openrocket/gui/main/DocumentSelectionListener.java @@ -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 index 00000000..94bc39df --- /dev/null +++ b/src/net/sf/openrocket/gui/main/DocumentSelectionModel.java @@ -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 listeners = + new ArrayList(); + + + + 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 null + * if no rocket component is selected. + * + * @return the currently selected rocket component, or null. + */ + 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 list = new ArrayList(); + 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); + } + + } + +} diff --git a/src/net/sf/openrocket/gui/main/LicenseDialog.java b/src/net/sf/openrocket/gui/main/LicenseDialog.java index 77690b9d..6df25692 100644 --- a/src/net/sf/openrocket/gui/main/LicenseDialog.java +++ b/src/net/sf/openrocket/gui/main/LicenseDialog.java @@ -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 { diff --git a/src/net/sf/openrocket/gui/main/MotorChooserDialog.java b/src/net/sf/openrocket/gui/main/MotorChooserDialog.java index c6e0f0f3..04a78979 100644 --- a/src/net/sf/openrocket/gui/main/MotorChooserDialog.java +++ b/src/net/sf/openrocket/gui/main/MotorChooserDialog.java @@ -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 index 00000000..b50bffc8 --- /dev/null +++ b/src/net/sf/openrocket/gui/main/OpenRocketClipboard.java @@ -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 RocketComponent contained in the clipboard, or + * null. + * + * @return the rocket component contained in the clipboard, or null + * 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 + } + + +} diff --git a/src/net/sf/openrocket/gui/main/RocketActions.java b/src/net/sf/openrocket/gui/main/RocketActions.java index 05b31e4b..b0352283 100644 --- a/src/net/sf/openrocket/gui/main/RocketActions.java +++ b/src/net/sf/openrocket/gui/main/RocketActions.java @@ -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 diff --git a/src/net/sf/openrocket/gui/main/SimulationEditDialog.java b/src/net/sf/openrocket/gui/main/SimulationEditDialog.java index f9c1c4c6..5074d112 100644 --- a/src/net/sf/openrocket/gui/main/SimulationEditDialog.java +++ b/src/net/sf/openrocket/gui/main/SimulationEditDialog.java @@ -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; diff --git a/src/net/sf/openrocket/gui/main/SimulationPanel.java b/src/net/sf/openrocket/gui/main/SimulationPanel.java index bb3cd3aa..a4046fb8 100644 --- a/src/net/sf/openrocket/gui/main/SimulationPanel.java +++ b/src/net/sf/openrocket/gui/main/SimulationPanel.java @@ -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; diff --git a/src/net/sf/openrocket/gui/plot/PlotPanel.java b/src/net/sf/openrocket/gui/plot/PlotPanel.java index 953ab4a0..b049b2eb 100644 --- a/src/net/sf/openrocket/gui/plot/PlotPanel.java +++ b/src/net/sf/openrocket/gui/plot/PlotPanel.java @@ -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; diff --git a/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java b/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java index 94bf1017..e40ba387 100644 --- a/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java +++ b/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java @@ -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 diff --git a/src/net/sf/openrocket/gui/scalefigure/ScaleScrollPane.java b/src/net/sf/openrocket/gui/scalefigure/ScaleScrollPane.java index e1d08b6e..caa28515 100644 --- a/src/net/sf/openrocket/gui/scalefigure/ScaleScrollPane.java +++ b/src/net/sf/openrocket/gui/scalefigure/ScaleScrollPane.java @@ -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 index 00000000..a2120d21 --- /dev/null +++ b/src/net/sf/openrocket/startup/Startup.java @@ -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. + *

+ * Note: This class must be Java 1.4 compatible and calls the next class using + * only reflection. + * + * @author Sampo Niskanen + */ +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); + } + + } + + } + + +} diff --git a/src/net/sf/openrocket/unit/FixedPrecisionUnit.java b/src/net/sf/openrocket/unit/FixedPrecisionUnit.java index 2946dc70..c175d4ef 100644 --- a/src/net/sf/openrocket/unit/FixedPrecisionUnit.java +++ b/src/net/sf/openrocket/unit/FixedPrecisionUnit.java @@ -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 index 00000000..7e45a653 --- /dev/null +++ b/src/net/sf/openrocket/util/JarUtil.java @@ -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 null if it cannot be found. + * + * @return a File object of the current Java archive, or null + */ + 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 index 00000000..d3d4fe11 --- /dev/null +++ b/src/net/sf/openrocket/util/PrintProperties.java @@ -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 keys = new TreeSet(); + for (Object key: System.getProperties().keySet()) { + keys.add((String)key); + } + + for (String key: keys) { + System.out.println(key + "=" + System.getProperty((String)key)); + } + + } + +}